Wednesday 30 March 2011

LLDialog NPC HUD controller work-in-progress

K so the code doesn't work yet because it's splitting the list up based on UUID and you can't have more than 24 characters for a button (so that indicates it's actually working for the most part). What we should be doing is keeping two separate lists which are associated to each other by index, one for botName and one for botUUIDs. That way we can choose the bot by name but we will know the index and that will give us the corresponding UUID. Anyways, work on it another time since it's time for bed....

list lstBotList;
list main_menu = ["Blue", "Red"];
list blue_menu = ["Blue Stuff 1", "Blue Stuff 2", "Back"];
list red_menu = ["Red Stuff 1", "Red Stuff 2", "Back"];
integer submenu = FALSE;
integer listen_channel = 1;


default
{
state_entry()
{
llSetText("Touch to split parse the string", <1,0,0>, 1.0);

}

touch_end(integer num)
{


list a = osGetAvatarList();


integer i;
integer intCount= 1;
integer s = llGetListLength(a);
do
{

if (intCount == 4)
{

intCount = 1;
}
if (intCount == 1)
{
string strListItem = llList2String(a,i);
llSay(0,strListItem);
lstBotList = [strListItem] + lstBotList;
}
intCount++;
}
while(s>++i);
llSay(0, "Touched.");
llDialog(llDetectedKey(0),"Try a selection...", lstBotList, listen_channel);
state stReadToGenerateLLDialog;
}

}

state stReadyToGenerateLLDialog
{
state_entry()
{
llListen(listen_channel,"",llGetOwner(),"");
//llSay(0, "Hello, Avatar!");
llSetText("Sample menu using LLDialog", <1,0,0>, 1.0);
}


listen(integer channel, string name, key id, string message)
{
if (submenu == FALSE)
{
// Use a main menu verification

if (message == "Blue")
{
llSay(0,"Thanks for picking " + message);
llDialog(id,message + " Dialog", blue_menu, listen_channel);
}

if (message == "Red")
{
llSay(0,"Thanks for picking " + message);
llDialog(id,message + " Dialog", red_menu, listen_channel);
}

submenu = TRUE;
llSetTimerEvent(20.0);
}
else
{
// Use a sub menu verification

llSetTimerEvent(20.0);
if (message == "Back")
{
llDialog(id,message + " Dialog", main_menu, listen_channel);
submenu = FALSE;
}
else
{
llSay(0,"You picked " + message);
//might want to verify which sub-menu was being used to redisplay here, etc
submenu = FALSE;
}
}
}

timer()
{
llSetTimerEvent(0.0);
llSay(0,"You waited too long to pick, resetting menu.");
submenu = FALSE;
}
}

Tuesday 29 March 2011

There's an error in the osAvatarPlayAnimation code

So the deal is: you dump an animation into the prim along with the script. The script contains the UUID of the bot. Then you touch the script and the bot plays the animation. Doesn't work unfortunately because there's some kind of permissions error.

[09:39 PM] Object: Error script: System.Exception: Runtime Error: osAvatarPlayAnimation permission denied. Prim owner is not in the list of users allowed to execute this function.
at Aurora.ScriptEngine.AuroraDotNetEngine.ScriptProtectionModule.Error(String surMessage, String msg) in d:\works37\Aurora\AuroraDotNetEngine\ScriptProtectionModule.cs:line 178
at Aurora.ScriptEngine.AuroraDotNetEngine.ScriptProtectionModule.CheckThreatLevel(ThreatLevel level, String function, ISceneChildEntity m_host, String API) in d:\works37\Aurora\AuroraDotNetEngine\ScriptProtectionModule.cs:line 169
at Aurora.ScriptEngine.AuroraDotNetEngine.APIs.OSSL_Api.osAvatarPlayAnimation(String avatar, String animation) in d:\works37\Aurora\AuroraDotNetEngine\APIs\OSSL_Api.cs:line 797
at Script.ScriptClass.d__2.MoveNext() in c:\temp\hegrd1sn.0.cs:line 36
at Aurora.ScriptEngine.AuroraDotNetEngine.Runtime.Executor.FireAsEnumerator(EnumeratorInfo Start, MethodInfo ev, Object[] args, Exceptio

Sample Aurora NPC Scripts: Remove a bot from the sim

In order to use this one you need to know the UUID of the bot you want to nuke. If you're nuking a single bot, right click on it, use profile and then "get key" if you're in imprudence. Then copy the UUID in here and nuke it.

Another possibility might be to generate the list of UUIDs and step through each one of them at a time and nuke them all.

default
{
state_entry()
{
llSetText("Zap bot by UUID", <1,0,0>, 1.0);
}
touch_start(integer a)
{
string bot = "c8269ef3-873d-4b68-a667-a2938ffc90af"; //llGetObjectDesc();
botRemoveBot(bot);
}
}

Aurora NPC Sample Scripts: Create a menu

This one builds a menu from a list and then depending on your selection, performs other actions in a list. This could be modified to accept a list of bots passed in from the generate bots list script and then choose actions for them to perform from a list.


list main_menu = ["Blue", "Red"];
list blue_menu = ["Blue Stuff 1", "Blue Stuff 2", "Back"];
list red_menu = ["Red Stuff 1", "Red Stuff 2", "Back"];
integer submenu = FALSE;
integer listen_channel = 1;

default
{
state_entry()
{
llListen(listen_channel,"",llGetOwner(),"");
//llSay(0, "Hello, Avatar!");
llSetText("Sample menu using LLDialog", <1,0,0>, 1.0);
}

touch_start(integer total_number)
{
llSay(0, "Touched.");
llDialog(llDetectedKey(0),"Try a selection...", main_menu, listen_channel);
}

listen(integer channel, string name, key id, string message)
{
if (submenu == FALSE)
{
// Use a main menu verification

if (message == "Blue")
{
llSay(0,"Thanks for picking " + message);
llDialog(id,message + " Dialog", blue_menu, listen_channel);
}

if (message == "Red")
{
llSay(0,"Thanks for picking " + message);
llDialog(id,message + " Dialog", red_menu, listen_channel);
}

submenu = TRUE;
llSetTimerEvent(20.0);
}
else
{
// Use a sub menu verification

llSetTimerEvent(20.0);
if (message == "Back")
{
llDialog(id,message + " Dialog", main_menu, listen_channel);
submenu = FALSE;
}
else
{
llSay(0,"You picked " + message);
//might want to verify which sub-menu was being used to redisplay here, etc
submenu = FALSE;
}
}
}

timer()
{
llSetTimerEvent(0.0);
llSay(0,"You waited too long to pick, resetting menu.");
submenu = FALSE;
}
}

Sample Aurora NPC Scripts: Make bot move

This one will make the bot (whose UUID is specified in the string) move 2 units Yward and then 2 units Xward by walking.


default
{
state_entry()
{
llSetText("Make bot move", <1,0,0>, 1.0);
}
touch_start(integer a)
{
string botID = "271419d4-a01d-4432-83f7-64cae13c86bf";
//Now give it a list of positions to go around
list positions = [llGetPos(), llGetPos() + <0, 2, 0>, llGetPos() + <2, 0, 0>];
//Now tell it how it will get there
//0 - Walk to the next target
//1 - Fly to the next target
list types = [0,0,0];
//Now tell the bot what to do
botSetMap(botID, positions, types);
}
}

Sample Aurora NPC Scripts: Get a list of all bots in region

This one will generate a list of all the bots in the region along with locations.
This in theory could be used to parse out the bots and pass them to some kind of menu list from which you could choose a bot's actions.




// ----------------------------------------------------------------
// Example / Sample Script to show function use.
//
// Script Title: osGetAgents.lsl
// Script Author: WSM
// Threat Level: None
// Script Source: SUPPLEMENTAL http://opensimulator.org/wiki/osGetAgents
//
// Notes: See Script Source reference for more detailed information
// This sample is full opensource and available to use as you see fit and desire.
// Threat Levels only apply to OSSL & AA Functions
// See http://opensimulator.org/wiki/Threat_level
//================================================================
// C# Source Line: public LSL_List osGetAgents()
// Inworld Script Line: list osGetAgents();
//
// Example of osGetAgents
//
//default
//{
// state_entry()
// {
// llSay(0, "Touch to get a List of Avatars on this Region using osGetAgents");
// }
// touch_start(integer num)
// {
// llSay(0, "The Avatars located here are: "+ llList2CSV(osGetAgents()));
// }
//}

default
{
state_entry()
{
llSetText("Touch to get a list of bots and UUIDs", <1,0,0>, 1.0);;
}
touch_start(integer total_number)
{
list avatars = osGetAvatarList(); //creates a Strided List (3 strides)
llSay(0, "UUID, Position, AvatarName, on this Region (without the owner):\n" + llList2CSV(avatars));
}
}

Sample Useful scripts for Aurora NPCs: Followbot

This one will generate a bot using the UUID of the originator avatar. The so-generated bot will appear wearing the clothes, skin and attachments the avatar was wearing last time it was logged in. Then the bot will follow the avatar whose UUID is given in toFollow


string first = "Test";
string last = "Bot";
key userToDuplicate;
string botID;
string toFollow;
default
{
state_entry()
{
llSetText("Create followbot by UUID", <1,0,0>, 1.0);
//On startup, we'll generate a new bot, then make it move when we touch it
//Create the bot with the given first/last name and the user whose appearance it will duplicate
//userToDuplicate = llGetOwner();
userToDuplicate = "121419d4-a04d-4018-83f7-64cae13c86bf";
botID = botCreateBot(first, last, userToDuplicate);
//You can either put an avatar's name or UUID here
//botFollowAvatar(botID, llGetOwner());

toFollow = "f13f4fb8-035a-4bca-b9f5-553d5b773f86";
botFollowAvatar(botID,toFollow);
}
touch_start(integer a)
{
botRemoveBot(botID);
}
}

Saturday 26 March 2011

So what can the basic aurora bots do?

Lolz I'm having fun tonight. Rev's code works and I loaded up 3 bots.

How you do it is rezz a prim and dump the script from the previous post in. That rezzes the bot. Then there are chat commands you can give it.

!stop makes the bot stop what it's doing and not move any more.
!go forward makes the bot take a step forward
!go back makes the bot take a step backward
!go left makes the bot take a step to the left
!go right makes the bot take a step to the right
!fly makes the bot fly.
!teleport makes the bot teleport.

Obviously the code could be beefed up (I'm thinking of Ken Rougeau's AIML chatbot script for one). It would be *very* interesting to add in some decent gaming AI then Aurora would be a pretty reasonable gaming platform given the ease of building things and dressing up/redesigning the avatar.

Little glitches I've noticed: all the bots respond to the same command at the same time. Also, the bots wear the last outfit the avatar was wearing last time someone logged in with them as a user BUT they *don't* wear attachments. That's definitely going to have to be looked into.

Anyways, good times.

Friday 25 March 2011

This is the LSL script to initialize the Aurora NPC bots

Dump this LSL into a prim end then touch it.... it should create a bot in your own image.


string first = "Test";
string last = "Bot";
key userToDuplicate;
string botID;
default
{
state_entry()
{
//On startup, we'll generate a new bot, then make it move when we touch it
//Create the bot with the given first/last name and the user whose appearance it will duplicate
userToDuplicate = llGetOwner();
botID = botCreateBot(first, last, userToDuplicate);

llListen( 0, "", NULL_KEY, "" );
}
touch_start(integer number)
{
//Now give it a list of positions to go around
list positions = [llGetPos(), llGetPos() + <0, 20, 20>, llGetPos() + <20, 0, 20>];
//Now tell it how it will get there
//0 - Walk to the next target
//1 - Fly to the next target
list types = [1,1,1];
//Now tell the bot what to do
botSetMap(botID, positions, types);
}
listen( integer channel, string name, key id, string message )
{
if ( id == llGetOwner() )
{
if(message == "pause")
{
//This disables the bots movement, however, the bot will warp to its next location once the alloted time runs out for movement
botPause(botID);
}
if(message == "resume")
{
//This reenables movement for the bot and does not turn on the movement timer
botResume(botID);
}
if(message == "stop")
{
//This disables the bots movement, as well as the auto warp that will occur if the bot does not get to its position in the alloted period of time
botStop(botID);
}
if(message == "start")
{
//This reenables movement for the bot and does turn on the movement timer
botStart(botID);
}
}
}
}

Rev may have fixed the cloud rezzing problem at least in Aurora

https://github.com/aurora-sim/Aurora-Sim/compare/e09d77b...04fef5c

I'm gonna see if I can't get that hacked into my branch of aurora.

Hopefully if this code works, it will find its way into the master branch of aurora soon.

Maybe NPCs have been picked up again by the Aurora guys

Just hanging out with the Aurora guys for a bit listening to their conversation and they've been playing with the NPC code same as me over the last little while. Rev Smythe is doing some nice work. Seems there is an exception when fetching the appearance, which is related to XML.

How to get access to help....

http://webchat.freenode.net/

channel is #aurora-dev

Digging around I found some forum posts confirming the bake theory

Bots largely depend on viewer compositing, this means they
send the
individual clothing layers, but no baked ones, and the viewing
user's viewer composites them into a viewable avatar.

Starting from 1.23, LL viewer no longer send, or expect,
compositing
layers. Avatars no longer carry texture information about their
individual clothing items. This is to combat theft, avatars now
carry only the 3 baked textures. Therefore, Copybot can no
longer
rip clothing from an avatar it sees.

Because of this, the "Cloud" stage is perceived to be longer
on 1.23
users, as they don't render until the bakes have been pushed
to the
server and then downloaded by the other clients. An avatar
counts as
unloaded if it's visual params are the default ones OR it
has no
baked textures. Previously, it would count as unloaded only
if it
had no textures at all, or all default visual params.

Since bots don't bake, they will never render for users of
the 1.23,
since it neither creates not expects compositing layers.

The following are the minimum textures that need to be baked for an
avatar to be considered "complete"

TEX_HEAD_BAKED
TEX_UPPER_BAKED
TEX_LOWER_BAKED
TEX_EYES_BAKED
TEX_HAIR_BAKED*

This is the radegast bake code

The following is the radegast bake code. Note that this is not all the code you need because there is a call to Baker.Bake() and Baker.AddTexture() et cetera.
That said, here it is for posterity:


/// Blocking method to create and upload baked textures for all of the
/// missing bakes
///
/// True on success, otherwise false
private bool CreateBakes()
{
bool success = true;
List pendingBakes = new List();

// Check each bake layer in the Textures array for missing bakes
for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++) { AvatarTextureIndex textureIndex = BakeTypeToAgentTextureIndex((BakeType)bakedIndex); if (Textures[(int)textureIndex].TextureID == UUID.Zero) { // If this is the skirt layer and we're not wearing a skirt then skip it if (bakedIndex == (int)BakeType.Skirt && !Wearables.ContainsKey(WearableType.Skirt)) continue; pendingBakes.Add((BakeType)bakedIndex); } } if (pendingBakes.Count > 0)
{
DownloadTextures(pendingBakes);

Parallel.ForEach(Math.Min(MAX_CONCURRENT_UPLOADS, pendingBakes.Count), pendingBakes,
delegate(BakeType bakeType)
{
if (!CreateBake(bakeType))
success = false;
}
);
}

// Free up all the textures we're holding on to
for (int i = 0; i < Textures.Length; i++) { Textures[i].Texture = null; } // We just allocated and freed a ridiculous amount of memory while // baking. Signal to the GC to clean up GC.Collect(); return success; } ///
/// Blocking method to create and upload a baked texture for a single
/// bake layer
///

/// Layer to bake /// True on success, otherwise false
private bool CreateBake(BakeType bakeType)
{
List textureIndices = BakeTypeToTextures(bakeType);
Baker oven = new Baker(bakeType);

for (int i = 0; i < textureIndices.Count; i++) { AvatarTextureIndex textureIndex = textureIndices[i]; TextureData texture = Textures[(int)textureIndex]; texture.TextureIndex = textureIndex; oven.AddTexture(texture); } int start = Environment.TickCount; oven.Bake(); Logger.DebugLog("Baking " + bakeType + " took " + (Environment.TickCount - start) + "ms"); UUID newAssetID = UUID.Zero; int retries = UPLOAD_RETRIES; while (newAssetID == UUID.Zero && retries > 0)
{
newAssetID = UploadBake(oven.BakedTexture.AssetData);
--retries;
}

Textures[(int)BakeTypeToAgentTextureIndex(bakeType)].TextureID = newAssetID;

if (newAssetID == UUID.Zero)
{
Logger.Log("Failed uploading bake " + bakeType, Helpers.LogLevel.Warning);
return false;
}

return true;
}

///
/// Blocking method to upload a baked texture
///

/// Five channel JPEG2000 texture data to upload /// UUID of the newly created asset on success, otherwise UUID.Zero
private UUID UploadBake(byte[] textureData)
{
UUID bakeID = UUID.Zero;
AutoResetEvent uploadEvent = new AutoResetEvent(false);

Client.Assets.RequestUploadBakedTexture(textureData,
delegate(UUID newAssetID)
{
bakeID = newAssetID;
uploadEvent.Set();
}
);

// FIXME: evalute the need for timeout here, RequestUploadBakedTexture() will
// timout either on Client.Settings.TRANSFER_TIMEOUT or Client.Settings.CAPS_TIMEOUT
// depending on which upload method is used.
uploadEvent.WaitOne(UPLOAD_TIMEOUT, false);

return bakeID;
}

Hunting down the Bake code.

So after a bit of sweat and tears I tracked down the client side bake code.
I suspect that maybe the reason why the NPCs stay as clouds (in addition to all the other properties I've not set right in e.g. the AgentCircuitData) that due to the convoluted way baked textures get passed around, the NPC code will be missing the bake code.

The way it appears to work to display the avatars to the rest of the connected clients is this: Scene gets a request to create an avatar in a scenepresence so it sends a request for baked textures to the client because the baking isn't done on the server. (Was it done on the server before? i.e. why did it work in 0.6.9? Need to investigate how 0.6.9 did it).

Anyways, the way it works *now* is that the client then receives the textures from the servers which it has to bake or else it picks up the textures it has from its cache. At that point it runs the baking code, effectively compressing all the different jpeg (or whatever) layers into a single jpeg (or whatever). This "baked" image is then sent back up to the Scene on the server. This is done for each texture for each section of the avatar's body (i.e. head, upper body and lower body). There are also alpha layers ant whatnot but I don't fully understand how those work.

Once the Scene has received the appropriate bakedtextures it somehow allocates them as temporary assets and associates them somehow with the agent or with the scenepresence(?) - a little unclear on the *exact* mechanics but more or less that's it.

Next step is it sends the baked textures down to all the other scenepresences in the scene. What that means is that only your own client has the real textures for your avatar. Everybody else only has baked textures, which makes it difficult for other viewers to rip your content out of the scene.

Anyways, the corresponding bake code is in the libopenmetaverse. I can't find any bake code like that in imprudence. It has to be there but I can't find it. Any case, in an ideal world we want C# and not have to convert from C++ to C# so libopenmetaverse is probably the best choice.

The code module is ibopenmetaverse/trunk/openmetaverse/imaging/bakelayer.cs
How this code is used can be found in the radegast code also: look for code like oven.bake and oven.addtexture to locate it in the radegast code (appearancemanage.cs in the radegast trunk). So in theory that's all the code you need to get the baking implemented.

I was hoping there was an easier way to do it than this, but if not well at least I know where to look for the relevant code.

Also: opensim does use some libraries from openmetaverse but I'm unclear on whether the package required to do the baking is in or not. The required package is OpenMetaverse.Imaging.

If it's not in it, then there's a further dependency on OpenMetaverse.Assets.

The following are the required "usings" in the bakelayer.cs code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using OpenMetaverse.Assets;

namespace OpenMetaverse.Imaging

So hacking the way through the TODO list for today

I couldn't find very easily the code for [SCENE] Incoming client which appears to be Scene.VerifyClient because I don't have my laptop here but I found code for LindenUDP.LLUDPServer.HandleUseCircuitCode.

Now this code is possibly not exactly the same as what I have on my test box at home and I'm looking at both vanilla opensim and aurora so it's not a 100% match but it should give some ideas as to what's going on. Anyways.. let's dig through the code:

2.1 Looking at HandleUseCircuitCode(object o) (follows). You will notice that this calls AddNewClient with a circuitcode packet and a remoteendpoint, so these are possibly necessary. Right now we don't call this function in our code, but instead mimic in the background and our c ircuitcode is built up manually and passed to the scene manually instead of coming in as a packet. We also have a null endpoint. So definitely we can say that the flow is different here though the steps are similar. So next, jump past the code to section 2.2 to see what AddNewClient with two parameters does.

private void HandleUseCircuitCode(object o)
{
object[] array = (object[])o;
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
UseCircuitCodePacket packet = (UseCircuitCodePacket)array[1];

IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;

// Begin the process of adding the client to the simulator
AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint);

// Acknowledge the UseCircuitCode packet
SendAckImmediate(remoteEndPoint, packet.Header.Sequence);
}

2.2 two parameter AddNewClient. What does this do? Let's see... It checks circuitcode to see if it's valid, asking for a sessionID, a remoteEndPoint and sessioninfo which it uses to call AddClient. Right off the bat our sessionID is 00000's, our remoteEndPoint is null and we haven't set sessionInfo either. So we possibly need to look into that. It also Authenticates the response with sessioninfo and also checks to see if the client is authorized before it calls AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo). So let's jump past this code block to 2.3
private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
{
UUID agentID = useCircuitCode.CircuitCode.ID;
UUID sessionID = useCircuitCode.CircuitCode.SessionID;
uint circuitCode = useCircuitCode.CircuitCode.Code;

if (m_scene.RegionStatus != RegionStatus.SlaveScene)
{
AuthenticateResponse sessionInfo;
if (IsClientAuthorized(useCircuitCode, out sessionInfo))
{
AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
}
else
{
// Don't create circuits for unauthorized clients
m_log.WarnFormat(
"[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
}
}
else
{
// Slave regions don't accept new clients
m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
}
}

2.3 In this section we're looking at AddClient. There are a bunch of things we are not doing here such as adding a LogoutHandler event as well as doing client.Start in the vanilla code. I'd like to get a look at client.Start to see what it does but I don't seem to have that code here so instead I'm going to look at the Aurora version which I can see more easily on the web. The aurora version has the line m_scene.AddNewClient(client) which is an overriden single parameter version. So in 2.4 we'll look at that: m_scene.AddNewClient
protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
{
// Create the LLUDPClient
LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
IClientAPI existingClient;

if (!m_scene.TryGetClient(agentID, out existingClient))
{
// Create the LLClientView
LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
client.OnLogout += LogoutHandler;

// Start the IClientAPI
client.Start();
}
else
{
m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
udpClient.AgentID, remoteEndPoint, circuitCode);
}
}

2.4 This is the aurora code for m_scene.AddNewClient which is pretty interesting and might in fact have most of what we need. I think I should look at this and do a compare of what I have in the relevant section of NPCModule because this might be the majority of code needed and it appears like it gives a significant number of clues as to what we might be missing. For example: it's pulling the appearance out of the circuitdata whereas I know we have null for appearance in circuit data. Maybe need to run a test and intercept this code to see what a real client has in it's circuit data….
00547 ///
00548 /// Adding a New Client and Create a Presence for it.
00549 ///

00550 /// 00551 public void AddNewClient(IClientAPI client)
00552 {
00553 System.Net.IPEndPoint ep = (System.Net.IPEndPoint)client.GetClientEP();
00554 AgentCircuitData aCircuit = AuthenticateHandler.AuthenticateSession(client.SessionId, client.AgentId, client.CircuitCode, ep);
00555
00556 if (aCircuit == null) // no good, didn't pass NewUserConnection successfully
00557 return;
00558
00559 //Create the scenepresence, then update it with any info that we have about it
00560 ScenePresence sp = m_sceneGraph.CreateAndAddChildScenePresence(client);
00561 lock (m_incomingChildAgentData)
00562 {
00563 if (m_incomingChildAgentData.ContainsKey(sp.UUID))
00564 {
00565 //Found info, update the agent then remove it
00566 sp.ChildAgentDataUpdate(m_incomingChildAgentData[sp.UUID]);
00567 m_incomingChildAgentData.Remove(sp.UUID);
00568 }
00569 }
00570 //Make sure the appearanace is updated
00571 if (aCircuit != null)
00572 sp.Appearance = aCircuit.Appearance;
00573 sp.IsChildAgent = aCircuit.child;
00574
00575 m_clientManager.Add(client);
00576
00577 //Trigger events
00578 m_eventManager.TriggerOnNewPresence(sp);
00579
00580 if (GetScenePresence(client.AgentId) != null)
00581 {
00582 EventManager.TriggerOnNewClient(client);
00583 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0)
00584 EventManager.TriggerOnClientLogin(client);
00585 }
00586
00587 //Add the client to login stats
00588 ILoginMonitor monitor = (ILoginMonitor)RequestModuleInterface().GetMonitor("", "LoginMonitor");
00589 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0 && monitor != null)
00590 {
00591 monitor.AddSuccessfulLogin();
00592 }
00593 }

Thursday 24 March 2011

OK after some hunting through the console logs a new TODO list

I tracked down each of the messages logged in the console comparing 8ball and Jane Doe. Luckily the message texts are 1:n (where n is low) for each function call in the code base, meaning I was able to track down each of the functions.

Looks like my hunch was right about the baking. The server requests baked textures from the client, the client does it and then sends the baked textures up to the server which receives them and probably distributes them down to the other clients via one of the scenepresence methods. That's my hunch.

Anyways, here is the list of associated function calls for each of the console messages, which I will use as a TODO.

TODO: Go take a look at each of the function calls made when a real client was connecting... The list of function calls follows:

[SCENE]: Incoming client x8Ball in region chibacity1 via regular login. Client IP verification not performed.
--> This could be OpenSim.Region.Framework.Scenes.Scene.VerifyClient(AgentCircuitData..

[LLUDPSERVER}: Handling UseCircuitCode packet from 10.211.55.3:1076
--> This is OpenSim.Region.ClientStack.LindenUDP.LLUDPServer

[SCENE]: Adding new agent x8Ball to scene chibacity1
--> This is OpenSim.Region.Framework.Scenes.Scene.AddNewClient

[SCENE]: Upgrading child to root agent for x8Ball in chibacity1
--> This is OpenSim.Region.Framework.Scenes.ScenePresence.MakeRootAgent(Vector3 pos, bool isFlying)

[PRESENCE DETECTOR]: Detected root presence 3efbb294-e1d6-430e-a508-fa5ca4748dbb in chibacity1
--> This is OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.PresenceDetector.OnMakeRootAgent(ScenePresence sp)

[PRESENCE SERVICE]: ReportAgent with session .... in region ....
--> This is OpenSim.Services.PresenceService.PresenceService.ReportAgent(UUID sessionID, UUID regionID)

[ACTIVITY DETECTOR]: Detected root presence 3efbb.... in chibacity1
--> This is OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser.ActivityDetector.OnMakeRootAgent(ScenePresence sp)

[SCENE]: Received request for wearables of x8Ball
--> This is OpenSim.Region.Framework.Scenes.ScenePresence

[CAPS]: UploadBakedTexture Request in region: chibacity1
--> This is OpenSim.Framework.Capabilities.Caps.UploadBakedTexture(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)

[CAPS]: Received baked texture ef7b9.....
--> This is OpenSim.Framework.Capabilities.Caps.BakedTextureUploaded(UUID assetID, byte[] data)

[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 83a04...
[CAPS]: Received baked texture 3ce3adc2...
[CAPS]: Received baked texture 47a32....
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 9308...
[CAPS]: Received baked texture d331...
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 5a84...
[CAPS]: Received baked texture 48cd...

[SCENE]: Adding new agent Jane Doe to scene chibacity1
[APPEARANCE]: Appearance not found in chibacity1, returning default
--> This is OpenSim.Region.Framework.Scenes.Scene.GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
[SCENE]: Upgrading child to root agent for Jane Doe in chibacity1

[ATTACHMENT]: Appearance has not been initialized for agent 8d69...
--> This is OpenSim.Region.Framework.Scenes.ScenePresence.RezAttachments()

[SCENE PRESENCE]: null appearance in MakeRoot in chibacity1
--> OpenSim.Region.Framework.Scenes.ScenePresence.MakeRootAgent(Vector3 pos, bool isFlying)

[PRESENCE DETECTOR]: Detected root presence 8d69... in chibacity1
[PRESENCE SERVICE]: ReportAgent with session 000000.... in region
003fdfc7.....
[ACTIVITY DETECTOR]: Detected root presence 8d693dc7.... in chibacity1
[SCENE]: Received request for wearables of Jane Doe

Experiments with ScenePresence.Appearance.

So I got the Jane Does to appear as clouds and I wanted to experiment. So I added the following lines of code (totally blindly) to the bottom of the NPC instantiation I posted earlier tonight:

sp.Appearance.ClearAttachments();
sp.Appearance.ClearWearables();
sp.Appearance.SetDefaultWearables();
sp.SendInitialFullUpdateToAllClients();
sp.SendWearables();
sp.SendFullUpdateToAllClients();

Sadly it didn't work. But what *was* of interest was the differences in the console logs between watching x8ball log in via imprudence, and Jane Doe suddenly appear in the region as an NPC. Following is a record of the events that took place in the console. You will notice there is a bunch more for the x8Ball stuff than for the Jane Doe stuff. A couple of points that stand out are error messages about null appearances and a zero session ID. Maybe session ID is important.... Anyway's we'll see. Here are the logs below:

[SCENE]: Incoming client x8Ball in region chibacity1 via regular login. Client IP verification not performed.
[LLUDPSERVER}: Handling UseCircuitCode packet from 192.168.1.3:1076
[SCENE]: Adding new agent x8Ball to scene chibacity1
[SCENE]: Upgrading child to root agent for x8Ball in chibacity1
[PRESENCE DETECTOR]: Detected root presence 3efbb294-e1d6-430e-a508-fa5ca4748dbb in chibacity1
[PRESENCE SERVICE]: ReportAgent with session .... in region ....
[ACTIVITY DETECTOR]: Detected root presence 3efbb.... in chibacity1
[SCENE]: Received request for wearables of x8Ball
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture ef7b9.....
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 83a04...
[CAPS]: Received baked texture 3ce3adc2...
[CAPS]: Received baked texture 47a32....
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 9308...
[CAPS]: Received baked texture d331...
[CAPS]: UploadBakedTexture Request in region: chibacity1
[CAPS]: Received baked texture 5a84...
[CAPS]: Received baked texture 48cd...

[SCENE]: Adding new agent Jane Doe to scene chibacity1
[APPEARANCE]: Appearance not found in chibacity1, returning default
[SCENE]: Upgrading child to root agent for Jane Doe in chibacity1
[ATTACHMENT]: Appearance has not been initialized for agent 8d69...
[SCENE PRESENCE]: null appearance in MakeRoot in chibacity1
[PRESENCE DETECTOR]: Detected root presence 8d69... in chibacity1
[PRESENCE SERVICE]: ReportAgent with session 000000.... in region
003fdfc7.....
[ACTIVITY DETECTOR]: Detected root presence 8d693dc7.... in chibacity1
[SCENE]: Received request for wearables of Jane Doe

OK - Partial Success!!!

K so I've been hacking vanilla opensim 0.7.2 which initially wasn't doing anything. Discovered that for whatever reason the osNPCCreate commands aren't working. Probably something to do with the %$%^#$#%-ing virtual machine I'm running on my trusty little mac (which is more than a *little* bit slow).

Anyways, I digress. I'm now back to where Haplo Voss got us near christmas: the code below this picture of success (yay!) rezzes a nice couple of physical (though cloudlike) Jane Doe NPCs...




void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (p_lock)
{
if (p_inUse)
{
p_inUse = false;

p_scene = m_scene;

p_firstname = "Jane";
p_lastname = "Doe";
p_position.X = 128;
p_position.Y = 128;
p_position.Z = 23;



NPCAvatar npcAvatar = new NPCAvatar(p_firstname,
p_lastname, p_position, p_scene);


//
AgentCircuitData ACD = new AgentCircuitData(); ;
uint circuitcode;


circuitcode = (uint) Util.RandomClass.Next(0, int.MaxValue);
ACD.circuitcode = circuitcode;
npcAvatar.CircuitCode = circuitcode;
ACD.firstname = p_firstname;
ACD.lastname = p_lastname;
ACD.startpos = p_position;
ACD.AgentID = npcAvatar.getAgentId();
ACD.SessionID = UUID.Zero;
ACD.SecureSessionID = UUID.Zero;
ACD.child = false; //should be a root instead of a child - yes beacause it's being instantiated for the first time
ACD.Viewer = "NPC";
//ACD.Appearance = ; //this should be set to something I think...

// not setting everything in the AgentCircuitData: missing out the following:
// child, InventoryFolder,
// BaseFolder, CapsPath, ChildrenCapSeeds
// Are they needed? Don't know....
//dan

p_scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode,ACD);

//


p_scene.AddNewClient(npcAvatar);

ScenePresence sp;
ScenePresence sp_tmp;
//up to this next line works - but this code returns a null scenepresence...
//find out why....

if (p_scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
{
p_scene.TryGetAvatarByName("Jane Doe", out sp_tmp);

p_cloneAppearanceFrom = sp_tmp.UUID;

AvatarAppearance x =
GetAppearance(p_cloneAppearanceFrom, p_scene);

sp.SetAppearance(x.Texture,
(byte[])x.VisualParams.Clone());
}

m_avatars.Add(npcAvatar.AgentId, npcAvatar);

p_returnUuid = npcAvatar.AgentId;
}
}
}

TO DO List as of today

OK so skimming through our version of the code which I think is the last working version I made this checklist for the calling sequence to get an NPC instantiated and good to go.
Note that this does not include any of the other leads to check. This is a preliminary before I can do any of that....


Calling sequence points to check when an NPC appears in a region:

• First part is register the client interface with the scene.
○ i.e. Scene.RegisterModuleInterface(this);
§ here check the Scene is valid
• next is create the avatar instance
○ npcAvatar = new NPCAvatar(first, last, pos, p_scene)
§ here you need to check the p_scene is valid
• next is create the circuit data
○ check each piece of the circuit data object
• next is adding the circuit to the scene
○ p_scene.AuthenticatedHandler.AddNewCircuit(circuitdata, ACD)
§ make sure p_scene is valid
§ make sure ACD is valid
§ make sure circuitdata is not null
• next is add the client (NPCAvatar) to the scene
○ p_scene.addnewclient(npca)
§ make sure p_scene is valid
§ make sure npca is valid
• next is get the scenepresence back out of the scene
○ p_scene.TryGetScenePresence(npca.agentID, out sp)
§ check p_scene is valid
§ check npca is valid
§ check npca.agentID is not null
§ make sure you get a scenepresence back in sp
• next is get the avatar appearance
○ AvatarAppearance x = GetAppearance(p_cloneappearancefrom, p_scene)
§ check p_cloneappearancefrom is a valid and existing uuid
§ check p_scene is valid
• get the avatar data - what is this? what does avatar data mean?
○ AvatarData adata = scene.AvatarService.GetAvatar(agentID)
§ make sure adata returns a non-null AvatarData - a new one at the worst
§ make sure scene is valid
§ make sure agentID is not null
• then set the appearance of the avatar corresponding to the scenepresence
○ sp.setappearance(x.texture, (byte[])x.VisualParams.Clone());
§ what does this mean?
§ check sp is valid
§ check x.texture is valid
§ check x.VisualParams.Clone returns something
• Add the newly rezzed avatar to the list of npcs
○ m_avatars.add(npca.AgentID, npca)
§ make sure m_avatars isn't null
§ check npca.AgentID is valid
§ check npca is valid
• get the UUID of the NPC Avie
○ P_returnUUID = npca.agentID
§ make sure npca is valid
§ make sure npca.agentID is not null

I keep circling round OpenSim.Framework.AvatarAppearance

I wonder if this might be where the relevant code is to at least force the NPC to be a ruth so we have something to work with while figuring out how to get the correct appearance we want.

The Aurora documentation says the following (cryptic) little piece about AvatarAppearance:
"Contain's the Avatar's appearance and methods to manipulate the appearance".

Certainly does sound promising.

Once I get the code working (again) which at least rezzes an NPC cloud I'm going to hack in some of these methods one at a time to see what happens. If that works, I'm gong to start trying to hack the movement code we had from the 0.6.9 back in.

Once I get that working (lol - not too much to ask right) I'm going to hack that code into the rexbot implementation in Aurora.

Wish me luck....

Maybe this is something to do with why the 0.7 code fails but the 0.6.9 code works

The following code appears to be the default settings for a newly initialized avatar.
Conspicously they have turned *off* the default which equals BAKE AVATAR = YES and reset it
to BAKE AVATAR = NO. That appears to suggest in my mind that this hands off the baking
mechanism to the viewer and THUS it's impossible to get a baked avatar (i.e. it will always be a cloud)
unless the viewer bakes the textures and then sends them up to the server.
clutching at straws but this might be it, since it appears to be in the zone of where I think the problem is and it's also exactly the opposite of the way it worked in 0.6.9 where it *did* work.

http://opensimulator.org/viewgit/?a=commitdiff&p=opensim&h=9668fb4e31c612ce457fc4d6e7708ea43234dbac

The relevant lines of code are the following where in the old code it was m_serial = 1 and it's now set to m_serial=0. I don't know what serial means but it *may* have something to do with it.
- protected int m_serial = 1;
+ protected int m_serial = 0;

OK so this is interesting

Scene.TryGetScenePresence goes through a bunch of wrapper calls but ultimately calls ScenePresence.AddToPhysicalScene.

What's interesting about that is that it checks if it's a physics actor. If it's null then it doesn't try to add the avatar to the physical scene. But if it *is* a physics actor then it checks to see if it's NOT a child agent. So that suggests that the AgentCircuitData.child has to be set to false in order to add the av to the scene.

If all goes well in SetAppearance it ultimately calls m_controllingClient.SendAvatarDataImmediate.

In our case our version of the client doesn't have an implementation of SendAvatarDataImmediate.

The wrapper function is there but there's no code in it. I wonder if that's the code we need to look at in other IClient interface implementations.

So this is Haplo's last word on where the 0.7.2 code is at

Ok sure... so the hair deal is this:

The code as you sent it to me, allows a 'blank' NPC to be created and
respond to Say and Remove commands. It retains the correct first and
lastname information from the osNpcCreate call and carries a unique
UUID. Using the for loop to create 10 NPCs and a list of their UUIDs
(or keys) each one retains name and unique ID and can be commanded to
Say and Remove respectively.

Notes: Depending on viewer - these NPCs will either be nothing but a
puffy cloud, or the 'witch king' (which is basically Hippo, Second
Life first gen viewer, and some viewers versions of a failed AV load.
It is what all settings to '0' would look like on hair - with no body
present. It looks like a grey Helm of the Witch King floating in space
lol)

Now then - if you change this:
ACD.AgentID = p_cloneAppearanceFrom; //npcAvatar.getAgentId();

Then for some reason any viewer will load a default hair floating in
space for every NPC. It is textured, colored, and loads in completion.
No body, skin, etc. Just friggin hair by itself. It does not make any
sense that assigning an entirely different ID would only make this
small of a difference (rather than just make or entirely break it?
Escpecially since the NPC still obeys all working commands)


p_scene: Ok so this will look really shitty in an email - but paste it
into a code editor and it will make better sense. I commented out
things, leaving them in place so I knew where to just 'crop' them back
in later.

As you can see below I hacked out the fact checking on the scene
presence in an attempt to force the current code to kick in. If I
leave it back in it's original 'IF' check, the function never fires
according to the debug message. Obviously the way I have it here - it
always fires without fail since I am forcing it to do so.



p_scene.AddNewClient(npcAvatar);

ScenePresence sp;
//if (
p_scene.TryGetScenePresence(p_cloneAppearanceFrom, out sp); //)
//{
AvatarAppearance x =
GetAppearance(p_cloneAppearanceFrom, p_scene);
m_log.Debug("[TryGetScenePrescence]: Function
Has Fired"); // Debug

sp.SetAppearance(x.Texture,
(byte[])x.VisualParams.Clone());
//}

m_avatars.Add(npcAvatar.AgentId, npcAvatar);

p_returnUuid = npcAvatar.AgentId;


Also if you want to have console logging enabled - you need the
following at the top of your file: using log4net; This will output
debug messages into your console window. Nice to have when you run the
osNPC* commands you can flip to your console and see what the hell is
going on ;)

ANYway ... so that is where I am at. Flat busted. Really none of the
changes I have made ended up taking me anywhere but back to your
original code you sent me. I also tried creating a user, then taking
that user, folder and asset ID information and hard coding it into
what I thought would be the appropriate slots for the information we
weren't sure we needed. Results were the same - still worked fine, but
no 'physical' appearance. Just a floaty name in space. So I am
probably not coding it in properly or something is missing entirely.

Also, I don't know if it matters or not but just in case - there is
definitely an actual 'ghost-presence' being created. You can bump into
and knock around the NPC even though it is just a point in space - so
the capsule is there.

*This* is the latest version of the NPCModule code

This version of the code should work to instantiate a cloud NPC in 0.7.2. Not tried any version of this in Aurora yet.

/*
* 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.Collections.Generic;
using System.Threading;
using OpenMetaverse;
using Nini.Config;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules.Avatar.NPC;
using OpenSim.Framework;
using Timer=System.Timers.Timer;
using OpenSim.Services.Interfaces;

namespace OpenSim.Region.OptionalModules.World.NPC
{
public class NPCModule : IRegionModule, INPCModule
{
// private const bool m_enabled = false;

private Mutex m_createMutex;
private Timer m_timer;

private Dictionary m_avatars = new Dictionary();
private Dictionary m_appearanceCache = new Dictionary();

// Timer vars.
private bool p_inUse = false;
private readonly object p_lock = new object();
// Private Temporary Variables.
private string p_firstname;
private string p_lastname;
private Vector3 p_position;
private Scene p_scene;
private UUID p_cloneAppearanceFrom;
private UUID p_returnUuid;

private AvatarAppearance GetAppearance(UUID target, Scene scene)
{
if (m_appearanceCache.ContainsKey(target))
return m_appearanceCache[target];

AvatarData adata = scene.AvatarService.GetAvatar(target);
if (adata != null)
{
AvatarAppearance x = adata.ToAvatarAppearance(target);

m_appearanceCache.Add(target, x);

return x;
}
return new AvatarAppearance();
}

public UUID CreateNPC(string firstname, string lastname,Vector3 position, Scene scene, UUID cloneAppearanceFrom)
{
// Block.
m_createMutex.WaitOne();

// Copy Temp Variables for Timer to pick up.
lock (p_lock)
{
p_firstname = firstname;
p_lastname = lastname;
p_position = position;
p_scene = scene;
p_cloneAppearanceFrom = cloneAppearanceFrom;
p_inUse = true;
p_returnUuid = UUID.Zero;
}

while (p_returnUuid == UUID.Zero)
{
Thread.Sleep(250);
}

m_createMutex.ReleaseMutex();

return p_returnUuid;
}

public void Autopilot(UUID agentID, Scene scene, Vector3 pos)
{
lock (m_avatars)
{
if (m_avatars.ContainsKey(agentID))
{
ScenePresence sp;
scene.TryGetScenePresence(agentID, out sp);
sp.DoAutoPilot(0, pos, m_avatars[agentID]);
}
}
}

public void Say(UUID agentID, Scene scene, string text)
{
lock (m_avatars)
{
if (m_avatars.ContainsKey(agentID))
{
m_avatars[agentID].Say(text);
}
}
}

public void DeleteNPC(UUID agentID, Scene scene)
{
lock (m_avatars)
{
if (m_avatars.ContainsKey(agentID))
{
scene.RemoveClient(agentID);
m_avatars.Remove(agentID);
}
}
}


public void Initialise(Scene scene, IConfigSource source)
{
m_createMutex = new Mutex(false);

m_timer = new Timer(500);
m_timer.Elapsed += m_timer_Elapsed;
m_timer.Start();

scene.RegisterModuleInterface(this);
}

void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (p_lock)
{
if (p_inUse)
{
p_inUse = false;

NPCAvatar npcAvatar = new NPCAvatar(p_firstname, p_lastname, p_position, p_scene);


//
AgentCircuitData ACD;
uint circuitcode;

ACD = new AgentCircuitData();
circuitcode = (uint) Util.RandomClass.Next(0, int.MaxValue);
ACD.circuitcode = circuitcode;
npcAvatar.CircuitCode = circuitcode;
ACD.firstname = p_firstname;
ACD.lastname = p_lastname;
ACD.startpos = p_position;
ACD.AgentID = npcAvatar.getAgentId();
ACD.SessionID = UUID.Zero;
ACD.SecureSessionID = UUID.Zero;
ACD.Viewer = "NPC";

// not setting everything in the AgentCircuitData: missing out the following:
// child, InventoryFolder,
// BaseFolder, CapsPath, ChildrenCapSeeds
// Are they needed? Don't know....
p_scene.AuthenticateHandler.AddNewCircuit(npcAvatar.CircuitCode, ACD);

//


p_scene.AddNewClient(npcAvatar);

ScenePresence sp;
if (p_scene.TryGetScenePresence(npcAvatar.AgentId, out sp))
{
AvatarAppearance x = GetAppearance(p_cloneAppearanceFrom, p_scene);

sp.SetAppearance(x.Texture, (byte[])x.VisualParams.Clone());
}

m_avatars.Add(npcAvatar.AgentId, npcAvatar);

p_returnUuid = npcAvatar.AgentId;
}
}
}

public void PostInitialise()
{
}

public void Close()
{
}

public string Name
{
get { return "NPCModule"; }
}

public bool IsSharedModule
{
get { return true; }
}
}
}

*this* scenepresence code might also be interesting

sp.ControllingClient.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial);

sp.SendAvatarDataToAllAgents();

sp.SendAppearanceToAgent(sp);

sp.SendAppearanceToAllOtherAgents();

If the problem is rebake not implemented in our bot, this is interesting

public void SendRebakeAvatarTextures(UUID textureID)
12223 {
12224 RebakeAvatarTexturesPacket pack =
12225 (RebakeAvatarTexturesPacket)PacketPool.Instance.GetPacket(PacketType.RebakeAvatarTextures);
12226
12227 pack.TextureData = new RebakeAvatarTexturesPacket.TextureDataBlock();
12228 pack.TextureData.TextureID = textureID;
12229 OutPacket(pack, ThrottleOutPacketType.Texture);
12230 }

A useful link for documentation

When trying to browse the source code, there is limited documentation in the source itself and as anyone who has ever worked on a multi section solution, it's spaghetti like and hard to figure out what links back to what.

The guys working on the Aurora flavor have done a pretty good job of documenting the codebase and though it won't be exactly the same as the Vanilla code, it gives a pretty good idea of how things are laid out. With time the two will continue to diverge, but right now there is enough similarity that you can get your head around the various sections by using the Aurora documentation.

It can be found here: http://grid.aurora-sim.org/docs/d2/def/_client_manager_8cs_source.html

A comparison of Vanilla and Aurora's (broken) implementation of NPCs

So I browsed the aurora rexbot code and here's what I came up with so far.
All the versions of the bots seem to use the IClientAPI interface so the aurora bot ought to be similar to the vanilla version in terms of reasons why it's bust..

So... some speculation....

Since the Aurora code is using more or less the same scene code as from the original opensim 0.7 codebase and then subsequently modifying it, combined with the fact that it was mods to the larger codebase that broke the Aurora version of the NPC bot I could hypothesize that the rexbot code (which was left alone) may have some clues as to why the code in the original vanilla 0.7 isn't working.

So I went and looked and there is indeed a chunk load of differences between how to instantiate a bot in the vanilla NPCModule class which is the wrapper for the NPCAvatar class which is the bot itself and the Aurora version (rexbot).

In the Aurora version version, a fast eyeball of the code it looks like Aurora.BotManager.RexBotManager.cs is the wrapper class i.e. the equivalent of NPCModule.cs and Rexbot.cs is the equivalent of NPCAvatar. There are differences of course since Rexbot is way more complicated and implements a bunch more interfaces than just the IClientAPI which is implemented in the vanilla code. The vanilla code is way simpler with many less moving parts.

So... moving onwards... I looked at the relevant code sections to instantiate a bot (the vanilla code is void m_timer_Elapsed) and the aurora code is RexBotManager.CreaterAvatar

The flow is more or less the same but with some differences.

The Aurora code passes in a full AgentCircuitData whereas the vanilla builds up an AgentCircuitData after the fact by using only a randomly generated CircuitCode. Maybe more research is needed on all the other associated crap such as how to generate valid endpoints etc in order to get a valid AgentCircuitData.... (Subsequently Rev Smythe says endpoints can be left as null because an NPC shouldn't really case about networks - but we'll leave that out there in case the code actually *does* care even though it *shouldn't*).

The Aurora code also runs m_scene.AuthenticateHandler (whereas the vanilla code doesn't).
then they both run m_scene.AddNewClient.

Vanilla does a conditional check to return the scenepresence back from the scene by doing scene.TryGetScenePresence and Aurora is just a direct call (no if statement) to m_scene.GetScenePresence.

Then Aurora does a scenepresence.appearance.setappearance which some texture stuff and visual params stuff
whereas Vanilla does a settextureentries then a separate setvisualparams.

Next Aurora does a sp.SendAppearanceToAllOtherAgents and so does vanilla.

Then Aurora has a line of code Vanilla doesn't have which is sp.sendavatardatatoallagents.

Then Aurora does some wrapper class crap which is functionally the same as vanilla does.

So... speculation.... I suspect that the missing feedback stuff *might* be in sp.sendavatardatatoallagents, so that piece might be worth adding in.

Certainly does sound like it because I know we're missing the bake-on-local-machine-and-then-upload-to-server piece which I've been trying to piece together out of radegast et cetera.

I'n going to do a bit more digging and I'll let you know what I find.

An eyeball look at ScenePresence.Appearance.AvatarAppearance

Given that the major problem with the 0.7.2 vanilla release is that the NPC avie's stay as a cloud and don't rezz, we need to figure out why that might be. One possible answer to that might be that the correctly baked textures are not sent down the pipe to the viewer for an NPC because they are baked on the viewer and sent up to the server and then resdistributed to each of the agents via scenepresence.

Hypothesizing: if you could access the scenepresence of the particular agent corresponding to the NPC you could maybe use the following methods?


sp.Appearance.AvatarAppearance(uuid) which should set the appearance to default.

and

sp.Appearance.SetDefaultWearables()

and

sp.Appearance.SetDefaultTexture()

and

sp.Apperance.SetAttachment()

and
sp.Appearance.ClearAttachments()

etc etc

These should be at some point an avenue of investigation...

The major chunks of code that will have something to do with NPCs in Opensim.

To the best of my vague understanding the major players in the Opensim NPC universes as designed in the Vanilla version (and in theory the Aurora version too because it's based on IClientAPI) are Scene, ScenePresence, Agent, AgentCircuitData, AvatarService/AvatarFactory and to a certain extent Client.

I'll attempt to give a brief description of what my understanding of each of them is:

Scene
This is a representation of all the objects which are located in a region, whether they are visible to a user in a viewer or not.

ScenePresence
This is the physical presence and to a certain extent the view of the scene the viewer/client/agent combo has.

Agent
This is the object encapsulating all the associated information to do with an avatar and some user data too. An Agent is a root agent if it is just rezzing by either walking/flying onto a Region, Teleporting or Logging in to a region.

AgentCircuitData
This is effectively data telling the region/scene where the Agent has come from (e.g. just logged in or whatever). It also may have some physical data like IP address of user associated with it.

AvatarService/AvatarFactory
These are classes which relate to the actual rezzing of the Avatar as well as the visible inventory.

Client
This is the server side code which interacts/handshakes with the viewer. This code intercepts user commands from the viewer over the network and then relays those commands to the server which reports back. Then the Client code serializes the responses, packs them up and sends them back over the network to the user's viewer so any updates to the users view of the scene can be viewed in the viewer.

This is the latest NPCAvatar code from the vanilla team

/*
* 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.Net;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;


namespace OpenSim.Region.OptionalModules.World.NPC
{
public class NPCAvatar : IClientAPI
{
private readonly string m_firstname;
private readonly string m_lastname;
private readonly Vector3 m_startPos;
private readonly UUID m_uuid = UUID.Random();
private readonly Scene m_scene;


public NPCAvatar(string firstname, string lastname, Vector3
position, Scene scene)
{
m_firstname = firstname;
m_lastname = lastname;
m_startPos = position;
m_scene = scene;


}

public IScene Scene
{
get { return m_scene; }
}

public void Say(string message)
{
SendOnChatFromClient(message, ChatTypeEnum.Say);
}

public void Shout(string message)
{
SendOnChatFromClient(message, ChatTypeEnum.Shout);
}

public void Whisper(string message)
{
SendOnChatFromClient(message, ChatTypeEnum.Whisper);
}

public void Broadcast(string message)
{
SendOnChatFromClient(message, ChatTypeEnum.Broadcast);
}

public void GiveMoney(UUID target, int amount)
{
OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment");
}

public void InstantMessage(UUID target, string message)
{
OnInstantMessage(this, new GridInstantMessage(m_scene,
m_uuid, m_firstname + " " + m_lastname,
target, 0, false, message,
UUID.Zero, false, Position, new byte[0]));
}

public void SendAgentOffline(UUID[] agentIDs)
{

}

public void SendAgentOnline(UUID[] agentIDs)
{

}
public void SendSitResponse(UUID TargetID, Vector3 OffsetPos,
Quaternion SitOrientation, bool autopilot,
Vector3 CameraAtOffset,
Vector3 CameraEyeOffset, bool ForceMouseLook)
{

}

public void SendAdminResponse(UUID Token, uint AdminLevel)
{

}

public void SendGroupMembership(GroupMembershipData[] GroupMembership)
{

}

public UUID getAgentId()
{
return m_uuid;
}

public UUID GetDefaultAnimation(string name)
{
return UUID.Zero;
}

public Vector3 Position
{
get { return m_scene.Entities[m_uuid].AbsolutePosition; }
set { m_scene.Entities[m_uuid].AbsolutePosition = value; }
}

public bool SendLogoutPacketWhenClosing
{
set { }
}

#region Internal Functions

private void SendOnChatFromClient(string message, ChatTypeEnum chatType)
{
OSChatMessage chatFromClient = new OSChatMessage();
chatFromClient.Channel = 0;
chatFromClient.From = Name;
chatFromClient.Message = message;
chatFromClient.Position = StartPos;
chatFromClient.Scene = m_scene;
chatFromClient.Sender = this;
chatFromClient.SenderUUID = AgentId;
chatFromClient.Type = chatType;

OnChatFromClient(this, chatFromClient);
}

#endregion

#region Event Definitions IGNORE

// disable warning: public events constituting public API
#pragma warning disable 67
public event Action OnLogout;
public event ObjectPermissions OnObjectPermissions;

public event MoneyTransferRequest OnMoneyTransferRequest;
public event ParcelBuy OnParcelBuy;
public event Action OnConnectionClosed;
public event GenericMessage OnGenericMessage;
public event ImprovedInstantMessage OnInstantMessage;
public event ChatMessage OnChatFromClient;
public event TextureRequest OnRequestTexture;
public event RezObject OnRezObject;
public event ModifyTerrain OnModifyTerrain;
public event SetAppearance OnSetAppearance;
public event AvatarNowWearing OnAvatarNowWearing;
public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv;
public event RezMultipleAttachmentsFromInv
OnRezMultipleAttachmentsFromInv;
public event UUIDNameRequest OnDetachAttachmentIntoInv;
public event ObjectAttach OnObjectAttach;
public event ObjectDeselect OnObjectDetach;
public event ObjectDrop OnObjectDrop;
public event StartAnim OnStartAnim;
public event StopAnim OnStopAnim;
public event LinkObjects OnLinkObjects;
public event DelinkObjects OnDelinkObjects;
public event RequestMapBlocks OnRequestMapBlocks;
public event RequestMapName OnMapNameRequest;
public event TeleportLocationRequest OnTeleportLocationRequest;
public event TeleportLandmarkRequest OnTeleportLandmarkRequest;
public event DisconnectUser OnDisconnectUser;
public event RequestAvatarProperties OnRequestAvatarProperties;
public event SetAlwaysRun OnSetAlwaysRun;

public event DeRezObject OnDeRezObject;
public event Action OnRegionHandShakeReply;
public event GenericCall2 OnRequestWearables;
public event GenericCall1 OnCompleteMovementToRegion;
public event UpdateAgent OnPreAgentUpdate;
public event UpdateAgent OnAgentUpdate;
public event AgentRequestSit OnAgentRequestSit;
public event AgentSit OnAgentSit;
public event AvatarPickerRequest OnAvatarPickerRequest;
public event Action OnRequestAvatarsData;
public event AddNewPrim OnAddPrim;
public event RequestGodlikePowers OnRequestGodlikePowers;
public event GodKickUser OnGodKickUser;
public event ObjectDuplicate OnObjectDuplicate;
public event GrabObject OnGrabObject;
public event DeGrabObject OnDeGrabObject;
public event MoveObject OnGrabUpdate;
public event SpinStart OnSpinStart;
public event SpinObject OnSpinUpdate;
public event SpinStop OnSpinStop;
public event ViewerEffectEventHandler OnViewerEffect;

public event FetchInventory OnAgentDataUpdateRequest;
public event TeleportLocationRequest OnSetStartLocationRequest;

public event UpdateShape OnUpdatePrimShape;
public event ObjectExtraParams OnUpdateExtraParams;
public event RequestObjectPropertiesFamily
OnRequestObjectPropertiesFamily;
public event ObjectRequest OnObjectRequest;
public event ObjectSelect OnObjectSelect;
public event GenericCall7 OnObjectDescription;
public event GenericCall7 OnObjectName;
public event GenericCall7 OnObjectClickAction;
public event GenericCall7 OnObjectMaterial;
public event UpdatePrimFlags OnUpdatePrimFlags;
public event UpdatePrimTexture OnUpdatePrimTexture;
public event UpdateVector OnUpdatePrimGroupPosition;
public event UpdateVector OnUpdatePrimSinglePosition;
public event UpdatePrimRotation OnUpdatePrimGroupRotation;
public event UpdatePrimSingleRotationPosition
OnUpdatePrimSingleRotationPosition;
public event UpdatePrimSingleRotation OnUpdatePrimSingleRotation;
public event UpdatePrimGroupRotation OnUpdatePrimGroupMouseRotation;
public event UpdateVector OnUpdatePrimScale;
public event UpdateVector OnUpdatePrimGroupScale;
public event StatusChange OnChildAgentStatus;
public event GenericCall2 OnStopMovement;
public event Action OnRemoveAvatar;

public event CreateNewInventoryItem OnCreateNewInventoryItem;
public event LinkInventoryItem OnLinkInventoryItem;
public event CreateInventoryFolder OnCreateNewInventoryFolder;
public event UpdateInventoryFolder OnUpdateInventoryFolder;
public event MoveInventoryFolder OnMoveInventoryFolder;
public event RemoveInventoryFolder OnRemoveInventoryFolder;
public event RemoveInventoryItem OnRemoveInventoryItem;
public event FetchInventoryDescendents OnFetchInventoryDescendents;
public event PurgeInventoryDescendents OnPurgeInventoryDescendents;
public event FetchInventory OnFetchInventory;
public event RequestTaskInventory OnRequestTaskInventory;
public event UpdateInventoryItem OnUpdateInventoryItem;
public event CopyInventoryItem OnCopyInventoryItem;
public event MoveInventoryItem OnMoveInventoryItem;
public event UDPAssetUploadRequest OnAssetUploadRequest;
public event XferReceive OnXferReceive;
public event RequestXfer OnRequestXfer;
public event AbortXfer OnAbortXfer;
public event ConfirmXfer OnConfirmXfer;
public event RezScript OnRezScript;
public event UpdateTaskInventory OnUpdateTaskInventory;
public event MoveTaskInventory OnMoveTaskItem;
public event RemoveTaskInventory OnRemoveTaskItem;
public event RequestAsset OnRequestAsset;

public event UUIDNameRequest OnNameFromUUIDRequest;
public event UUIDNameRequest OnUUIDGroupNameRequest;

public event ParcelPropertiesRequest OnParcelPropertiesRequest;
public event ParcelDivideRequest OnParcelDivideRequest;
public event ParcelJoinRequest OnParcelJoinRequest;
public event ParcelPropertiesUpdateRequest
OnParcelPropertiesUpdateRequest;
public event ParcelAbandonRequest OnParcelAbandonRequest;
public event ParcelGodForceOwner OnParcelGodForceOwner;
public event ParcelReclaim OnParcelReclaim;
public event ParcelReturnObjectsRequest OnParcelReturnObjectsRequest;
public event ParcelAccessListRequest OnParcelAccessListRequest;
public event ParcelAccessListUpdateRequest
OnParcelAccessListUpdateRequest;
public event ParcelSelectObjects OnParcelSelectObjects;
public event ParcelObjectOwnerRequest OnParcelObjectOwnerRequest;
public event ParcelDeedToGroup OnParcelDeedToGroup;
public event ObjectDeselect OnObjectDeselect;
public event RegionInfoRequest OnRegionInfoRequest;
public event EstateCovenantRequest OnEstateCovenantRequest;
public event RequestTerrain OnRequestTerrain;
public event RequestTerrain OnUploadTerrain;
public event ObjectDuplicateOnRay OnObjectDuplicateOnRay;

public event FriendActionDelegate OnApproveFriendRequest;
public event FriendActionDelegate OnDenyFriendRequest;
public event FriendshipTermination OnTerminateFriendship;
public event GrantUserFriendRights OnGrantUserRights;

public event EconomyDataRequest OnEconomyDataRequest;
public event MoneyBalanceRequest OnMoneyBalanceRequest;
public event UpdateAvatarProperties OnUpdateAvatarProperties;

public event ObjectIncludeInSearch OnObjectIncludeInSearch;
public event UUIDNameRequest OnTeleportHomeRequest;

public event ScriptAnswer OnScriptAnswer;
public event RequestPayPrice OnRequestPayPrice;
public event ObjectSaleInfo OnObjectSaleInfo;
public event ObjectBuy OnObjectBuy;
public event BuyObjectInventory OnBuyObjectInventory;
public event AgentSit OnUndo;
public event AgentSit OnRedo;
public event LandUndo OnLandUndo;

public event ForceReleaseControls OnForceReleaseControls;
public event GodLandStatRequest OnLandStatRequest;
public event RequestObjectPropertiesFamily OnObjectGroupRequest;

public event DetailedEstateDataRequest OnDetailedEstateDataRequest;
public event SetEstateFlagsRequest OnSetEstateFlagsRequest;
public event SetEstateTerrainBaseTexture OnSetEstateTerrainBaseTexture;
public event SetEstateTerrainDetailTexture
OnSetEstateTerrainDetailTexture;
public event SetEstateTerrainTextureHeights
OnSetEstateTerrainTextureHeights;
public event CommitEstateTerrainTextureRequest
OnCommitEstateTerrainTextureRequest;
public event SetRegionTerrainSettings OnSetRegionTerrainSettings;
public event BakeTerrain OnBakeTerrain;
public event EstateRestartSimRequest OnEstateRestartSimRequest;
public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
public event UpdateEstateAccessDeltaRequest
OnUpdateEstateAccessDeltaRequest;
public event SimulatorBlueBoxMessageRequest
OnSimulatorBlueBoxMessageRequest;
public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
public event EstateTeleportOneUserHomeRequest
OnEstateTeleportOneUserHomeRequest;
public event EstateTeleportAllUsersHomeRequest
OnEstateTeleportAllUsersHomeRequest;
public event EstateChangeInfo OnEstateChangeInfo;
public event ScriptReset OnScriptReset;
public event GetScriptRunning OnGetScriptRunning;
public event SetScriptRunning OnSetScriptRunning;
public event UpdateVector OnAutoPilotGo;

public event TerrainUnacked OnUnackedTerrain;

public event RegionHandleRequest OnRegionHandleRequest;
public event ParcelInfoRequest OnParcelInfoRequest;

public event ActivateGesture OnActivateGesture;
public event DeactivateGesture OnDeactivateGesture;
public event ObjectOwner OnObjectOwner;

public event DirPlacesQuery OnDirPlacesQuery;
public event DirFindQuery OnDirFindQuery;
public event DirLandQuery OnDirLandQuery;
public event DirPopularQuery OnDirPopularQuery;
public event DirClassifiedQuery OnDirClassifiedQuery;
public event EventInfoRequest OnEventInfoRequest;
public event ParcelSetOtherCleanTime OnParcelSetOtherCleanTime;

public event MapItemRequest OnMapItemRequest;

public event OfferCallingCard OnOfferCallingCard;
public event AcceptCallingCard OnAcceptCallingCard;
public event DeclineCallingCard OnDeclineCallingCard;
public event SoundTrigger OnSoundTrigger;

public event StartLure OnStartLure;
public event TeleportLureRequest OnTeleportLureRequest;
public event NetworkStats OnNetworkStatsUpdate;

public event ClassifiedInfoRequest OnClassifiedInfoRequest;
public event ClassifiedInfoUpdate OnClassifiedInfoUpdate;
public event ClassifiedDelete OnClassifiedDelete;
public event ClassifiedDelete OnClassifiedGodDelete;

public event EventNotificationAddRequest OnEventNotificationAddRequest;
public event EventNotificationRemoveRequest
OnEventNotificationRemoveRequest;
public event EventGodDelete OnEventGodDelete;

public event ParcelDwellRequest OnParcelDwellRequest;

public event UserInfoRequest OnUserInfoRequest;
public event UpdateUserInfo OnUpdateUserInfo;

public event RetrieveInstantMessages OnRetrieveInstantMessages;

public event PickDelete OnPickDelete;
public event PickGodDelete OnPickGodDelete;
public event PickInfoUpdate OnPickInfoUpdate;
public event AvatarNotesUpdate OnAvatarNotesUpdate;

public event MuteListRequest OnMuteListRequest;

public event AvatarInterestUpdate OnAvatarInterestUpdate;

public event PlacesQuery OnPlacesQuery;

public event FindAgentUpdate OnFindAgent;
public event TrackAgentUpdate OnTrackAgent;
public event NewUserReport OnUserReport;
public event SaveStateHandler OnSaveState;
public event GroupAccountSummaryRequest OnGroupAccountSummaryRequest;
public event GroupAccountDetailsRequest OnGroupAccountDetailsRequest;
public event GroupAccountTransactionsRequest
OnGroupAccountTransactionsRequest;
public event FreezeUserUpdate OnParcelFreezeUser;
public event EjectUserUpdate OnParcelEjectUser;
public event ParcelBuyPass OnParcelBuyPass;
public event ParcelGodMark OnParcelGodMark;
public event GroupActiveProposalsRequest OnGroupActiveProposalsRequest;
public event GroupVoteHistoryRequest OnGroupVoteHistoryRequest;
public event SimWideDeletesDelegate OnSimWideDeletes;
public event SendPostcard OnSendPostcard;
public event MuteListEntryUpdate OnUpdateMuteListEntry;
public event MuteListEntryRemove OnRemoveMuteListEntry;
public event GodlikeMessage onGodlikeMessage;
public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;

#pragma warning restore 67

#endregion

public void ActivateGesture(UUID assetId, UUID gestureId)
{
}
public void DeactivateGesture(UUID assetId, UUID gestureId)
{
}

#region Overrriden Methods IGNORE

public virtual Vector3 StartPos
{
get { return m_startPos; }
set { }
}

public virtual UUID AgentId
{
get { return m_uuid; }
}

public UUID SessionId
{
get { return UUID.Zero; }
}

public UUID SecureSessionId
{
get { return UUID.Zero; }
}

public virtual string FirstName
{
get { return m_firstname; }
}

public virtual string LastName
{
get { return m_lastname; }
}

public virtual String Name
{
get { return FirstName + " " + LastName; }
}

public bool IsActive
{
get { return true; }
set { }
}

public bool IsLoggingOut
{
get { return false; }
set { }
}
public UUID ActiveGroupId
{
get { return UUID.Zero; }
}

public string ActiveGroupName
{
get { return String.Empty; }
}

public ulong ActiveGroupPowers
{
get { return 0; }
}

public bool IsGroupMember(UUID groupID)
{
return false;
}

public ulong GetGroupPowers(UUID groupID)
{
return 0;
}

public virtual int NextAnimationSequenceNumber
{
get { return 1; }
}

public virtual void SendWearables(AvatarWearable[] wearables,
int serial)
{
}

public virtual void SendAppearance(UUID agentID, byte[]
visualParams, byte[] textureEntry)
{
}

public virtual void Kick(string message)
{
}

public virtual void SendStartPingCheck(byte seq)
{
}

public virtual void
SendAvatarPickerReply(AvatarPickerReplyAgentDataArgs AgentData,
List Data)
{
}

public virtual void SendAgentDataUpdate(UUID agentid, UUID
activegroupid, string firstname, string lastname, ulong grouppowers,
string groupname, string grouptitle)
{

}

public virtual void SendKillObject(ulong regionHandle, uint localID)
{
}

public virtual void SetChildAgentThrottle(byte[] throttle)
{
}
public byte[] GetThrottlesPacked(float multiplier)
{
return new byte[0];
}


public virtual void SendAnimations(UUID[] animations, int[]
seqs, UUID sourceAgentId, UUID[] objectIDs)
{
}

public virtual void SendChatMessage(string message, byte type,
Vector3 fromPos, string fromName,
UUID fromAgentID, byte
source, byte audible)
{
}

public virtual void SendChatMessage(byte[] message, byte type,
Vector3 fromPos, string fromName,
UUID fromAgentID, byte
source, byte audible)
{
}

public void SendInstantMessage(GridInstantMessage im)
{

}

public void SendGenericMessage(string method, List message)
{

}

public void SendGenericMessage(string method, List message)
{

}

public virtual void SendLayerData(float[] map)
{
}

public virtual void SendLayerData(int px, int py, float[] map)
{
}
public virtual void SendLayerData(int px, int py, float[] map,
bool track)
{
}

public virtual void SendWindData(Vector2[] windSpeeds) { }

public virtual void SendCloudData(float[] cloudCover) { }

public virtual void MoveAgentIntoRegion(RegionInfo regInfo,
Vector3 pos, Vector3 look)
{
}

public virtual void InformClientOfNeighbour(ulong
neighbourHandle, IPEndPoint neighbourExternalEndPoint)
{
}

public virtual AgentCircuitData RequestClientInfo()
{
return new AgentCircuitData();
}

public virtual void CrossRegion(ulong newRegionHandle, Vector3
pos, Vector3 lookAt,
IPEndPoint
newRegionExternalEndPoint, string capsURL)
{
}

public virtual void SendMapBlock(List mapBlocks,
uint flag)
{
}

public virtual void SendLocalTeleport(Vector3 position,
Vector3 lookAt, uint flags)
{
}

public virtual void SendRegionTeleport(ulong regionHandle,
byte simAccess, IPEndPoint regionExternalEndPoint,
uint locationID, uint
flags, string capsURL)
{
}

public virtual void SendTeleportFailed(string reason)
{
}

public virtual void SendTeleportLocationStart()
{
}

public virtual void SendMoneyBalance(UUID transaction, bool
success, byte[] description, int balance)
{
}

public virtual void SendPayPrice(UUID objectID, int[] payPrice)
{
}

public virtual void SendCoarseLocationUpdate(List users,
List CoarseLocations)
{
}

public virtual void AttachObject(uint localID, Quaternion
rotation, byte attachPoint, UUID ownerID)
{
}

public virtual void SendDialog(string objectname, UUID
objectID, string ownerFirstName, string ownerLastName, string msg,
UUID textureID, int ch, string[] buttonlabels)
{
}

public void SendAvatarDataImmediate(ISceneEntity avatar)
{

ScenePresence presence = avatar as ScenePresence;
if (presence == null)
return;

ObjectUpdatePacket objupdate =
(ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate);
objupdate.Header.Zerocoded = true;

objupdate.RegionData.RegionHandle = presence.RegionHandle;
objupdate.RegionData.TimeDilation = ushort.MaxValue;

objupdate.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
objupdate.ObjectData[0] = CreateAvatarUpdateBlock(presence);

OutPacket(objupdate, ThrottleOutPacketType.Task);

// We need to record the avatar local id since the root
prim of an attachment points to this.
// m_attachmentsSent.Add(avatar.LocalId);

}

public void SendPrimUpdate(ISceneEntity entity,
PrimUpdateFlags updateFlags)
{
}

public void ReprioritizeUpdates()
{
}

public void FlushPrimUpdates()
{
}

public virtual void SendInventoryFolderDetails(UUID ownerID,
UUID folderID,

List items,

List folders,
int version,
bool fetchFolders,
bool fetchItems)
{
}

public virtual void SendInventoryItemDetails(UUID ownerID,
InventoryItemBase item)
{
}

public virtual void
SendInventoryItemCreateUpdate(InventoryItemBase Item, uint callbackID)
{
}

public virtual void SendRemoveInventoryItem(UUID itemID)
{
}

public virtual void SendBulkUpdateInventory(InventoryNodeBase node)
{
}

public void SendTakeControls(int controls, bool passToAgent,
bool TakeControls)
{
}

public virtual void SendTaskInventory(UUID taskID, short
serial, byte[] fileName)
{
}

public virtual void SendXferPacket(ulong xferID, uint packet,
byte[] data)
{
}

public virtual void SendEconomyData(float EnergyEfficiency,
int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
int PriceGroupCreate, int
PriceObjectClaim, float PriceObjectRent, float PriceObjectScaleFactor,
int PriceParcelClaim,
float PriceParcelClaimFactor, int PriceParcelRent, int
PricePublicObjectDecay,
int
PricePublicObjectDelete, int PriceRentLight, int PriceUpload, int
TeleportMinPrice, float TeleportPriceExponent)
{

}
public virtual void SendNameReply(UUID profileId, string
firstname, string lastname)
{
}

public virtual void SendPreLoadSound(UUID objectID, UUID
ownerID, UUID soundID)
{
}

public virtual void SendPlayAttachedSound(UUID soundID, UUID
objectID, UUID ownerID, float gain,
byte flags)
{
}

public void SendTriggeredSound(UUID soundID, UUID ownerID,
UUID objectID, UUID parentID, ulong handle, Vector3 position, float
gain)
{
}

public void SendAttachedSoundGainChange(UUID objectID, float gain)
{

}

public void SendAlertMessage(string message)
{
}

public void SendAgentAlertMessage(string message, bool modal)
{
}

public void SendSystemAlertMessage(string message)
{
}

public void SendLoadURL(string objectname, UUID objectID, UUID
ownerID, bool groupOwned, string message,
string url)
{
}

public virtual void SendRegionHandshake(RegionInfo regionInfo,
RegionHandshakeArgs args)
{
if (OnRegionHandShakeReply != null)
{
OnRegionHandShakeReply(this);
}

if (OnCompleteMovementToRegion != null)
{
OnCompleteMovementToRegion(this);
}
}
public void SendAssetUploadCompleteMessage(sbyte AssetType,
bool Success, UUID AssetFullID)
{
}

public void SendConfirmXfer(ulong xferID, uint PacketID)
{
}

public void SendXferRequest(ulong XferID, short AssetType,
UUID vFileID, byte FilePath, byte[] FileName)
{
}

public void SendInitiateDownload(string simFileName, string
clientFileName)
{
}

public void SendImageFirstPart(ushort numParts, UUID
ImageUUID, uint ImageSize, byte[] ImageData, byte imageCodec)
{
}

public void SendImageNotFound(UUID imageid)
{
}

public void SendImageNextPart(ushort partNumber, UUID
imageUuid, byte[] imageData)
{
}

public void SendShutdownConnectionNotice()
{
}

public void SendSimStats(SimStats stats)
{
}

public void SendObjectPropertiesFamilyData(uint RequestFlags,
UUID ObjectUUID, UUID OwnerID, UUID GroupID,
uint BaseMask, uint
OwnerMask, uint GroupMask, uint EveryoneMask,
uint NextOwnerMask,
int OwnershipCost, byte SaleType, int SalePrice, uint Category,
UUID LastOwnerID,
string ObjectName, string Description)
{
}

public void SendObjectPropertiesReply(UUID ItemID, ulong
CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID,
UUID GroupUUID, short
InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID,
UUID OwnerUUID, string
TouchTitle, byte[] TextureID, string SitTitle, string ItemName,
string ItemDescription,
uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask,
uint BaseMask, byte
saleType, int salePrice)
{
}

public bool AddMoney(int debit)
{
return false;
}

public void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong
time, uint dlen, uint ylen, float phase)
{
}

public void SendViewerEffect(ViewerEffectPacket.EffectBlock[]
effectBlocks)
{
}

public void SendViewerTime(int phase)
{
}

public void SendAvatarProperties(UUID avatarID, string
aboutText, string bornOn, Byte[] charterMember,
string flAbout, uint flags,
UUID flImageID, UUID imageID, string profileURL,
UUID partnerID)
{
}

public void SendAsset(AssetRequestToClient req)
{
}

public void SendTexture(AssetBase TextureAsset)
{
}

public void SetDebugPacketLevel(int newDebug)
{
}

public void InPacket(object NewPack)
{
}

public void ProcessInPacket(Packet NewPack)
{
}

public void Close()
{
}

public void Start()
{
}

public void Stop()
{
}

private uint m_circuitCode;
private IPEndPoint m_remoteEndPoint;

public uint CircuitCode
{
get { return m_circuitCode; }
set
{
m_circuitCode = value;
m_remoteEndPoint = new IPEndPoint(IPAddress.Loopback,
(ushort)m_circuitCode);
}
}

public IPEndPoint RemoteEndPoint
{
get { return m_remoteEndPoint; }
}

public void SendBlueBoxMessage(UUID FromAvatarID, String
FromAvatarName, String Message)
{

}
public void SendLogoutPacket()
{
}

public void Terminate()
{
}

public EndPoint GetClientEP()
{
return null;
}

public ClientInfo GetClientInfo()
{
return null;
}

public void SetClientInfo(ClientInfo info)
{
}

public void SendScriptQuestion(UUID objectID, string taskName,
string ownerName, UUID itemID, int question)
{
}
public void SendHealth(float health)
{
}

public void SendEstateList(UUID invoice, int code, UUID[]
Data, uint estateID)
{
}

public void SendBannedUserList(UUID invoice, EstateBan[]
banlist, uint estateID)
{
}

public void SendRegionInfoToEstateMenu(RegionInfoForEstateMenuArgs args)
{
}
public void SendEstateCovenantInformation(UUID covenant)
{
}
public void SendDetailedEstateData(UUID invoice, string
estateName, uint estateID, uint parentEstate, uint estateFlags, uint
sunPosition, UUID covenant, string abuseEmail, UUID estateOwner)
{
}

public void SendLandProperties(int sequence_id, bool
snap_selection, int request_result, LandData landData, float
simObjectBonusFactor,int parcelObjectCapacity, int simObjectCapacity,
uint regionFlags)
{
}
public void SendLandAccessListData(List avatars, uint
accessFlag, int localLandID)
{
}
public void SendForceClientSelectObjects(List objectIDs)
{
}
public void SendCameraConstraint(Vector4 ConstraintPlane)
{
}
public void SendLandObjectOwners(LandData land, List
groups, Dictionary ownersAndCount)
{
}
public void SendLandParcelOverlay(byte[] data, int sequence_id)
{
}

public void SendGroupNameReply(UUID groupLLUID, string GroupName)
{
}

public void SendScriptRunningReply(UUID objectID, UUID itemID,
bool running)
{
}

public void SendLandStatReply(uint reportType, uint
requestFlags, uint resultCount, LandStatReportItem[] lsrpia)
{
}
#endregion


public void SendParcelMediaCommand(uint flags,
ParcelMediaCommandEnum command, float time)
{
}

public void SendParcelMediaUpdate(string mediaUrl, UUID mediaTextureID,
byte autoScale, string mediaType,
string mediaDesc, int mediaWidth, int mediaHeight,
byte mediaLoop)
{
}

public void SendSetFollowCamProperties (UUID objectID,
SortedDictionary parameters)
{
}

public void SendClearFollowCamProperties (UUID objectID)
{
}

public void SendRegionHandle (UUID regoinID, ulong handle)
{
}

public void SendParcelInfo (RegionInfo info, LandData land,
UUID parcelID, uint x, uint y)
{
}

public void SetClientOption(string option, string value)
{
}

public string GetClientOption(string option)
{
return string.Empty;
}

public void SendScriptTeleportRequest (string objName, string
simName, Vector3 pos, Vector3 lookAt)
{
}

public void SendDirPlacesReply(UUID queryID, DirPlacesReplyData[] data)
{
}

public void SendDirPeopleReply(UUID queryID, DirPeopleReplyData[] data)
{
}

public void SendDirEventsReply(UUID queryID, DirEventsReplyData[] data)
{
}

public void SendDirGroupsReply(UUID queryID, DirGroupsReplyData[] data)
{
}

public void SendDirClassifiedReply(UUID queryID,
DirClassifiedReplyData[] data)
{
}

public void SendDirLandReply(UUID queryID, DirLandReplyData[] data)
{
}

public void SendDirPopularReply(UUID queryID,
DirPopularReplyData[] data)
{
}

public void SendMapItemReply(mapItemReply[] replies, uint
mapitemtype, uint flags)
{
}

public void KillEndDone()
{
}

public void SendEventInfoReply (EventData info)
{
}

public void SendOfferCallingCard (UUID destID, UUID transactionID)
{
}

public void SendAcceptCallingCard (UUID transactionID)
{
}

public void SendDeclineCallingCard (UUID transactionID)
{
}

public void SendJoinGroupReply(UUID groupID, bool success)
{
}

public void SendEjectGroupMemberReply(UUID agentID, UUID
groupID, bool success)
{
}

public void SendLeaveGroupReply(UUID groupID, bool success)
{
}

public void SendAvatarGroupsReply(UUID avatarID,
GroupMembershipData[] data)
{
}

public void SendTerminateFriend(UUID exFriendID)
{
}

#region IClientAPI Members


public bool AddGenericPacketHandler(string MethodName,
GenericMessage handler)
{
//throw new NotImplementedException();
return false;
}

public void SendAvatarClassifiedReply(UUID targetID, UUID[]
classifiedID, string[] name)
{
}

public void SendClassifiedInfoReply(UUID classifiedID, UUID
creatorID, uint creationDate, uint expirationDate, uint category,
string name, string description, UUID parcelID, uint parentEstate,
UUID snapshotID, string simName, Vector3 globalPos, string parcelName,
byte classifiedFlags, int price)
{
}

public void SendAgentDropGroup(UUID groupID)
{
}

public void SendAvatarNotesReply(UUID targetID, string text)
{
}

public void SendAvatarPicksReply(UUID targetID,
Dictionary picks)
{
}

public void SendAvatarClassifiedReply(UUID targetID,
Dictionary classifieds)
{
}

public void SendParcelDwellReply(int localID, UUID parcelID,
float dwell)
{
}

public void SendUserInfoReply(bool imViaEmail, bool visible,
string email)
{
}

public void SendCreateGroupReply(UUID groupID, bool success,
string message)
{
}

public void RefreshGroupMembership()
{
}

public void SendUseCachedMuteList()
{
}

public void SendMuteListUpdate(string filename)
{
}

public void SendPickInfoReply(UUID pickID,UUID creatorID, bool
topPick, UUID parcelID, string name, string desc, UUID snapshotID,
string user, string originalName, string simName, Vector3 posGlobal,
int sortOrder, bool enabled)
{
}
#endregion

public void SendRebakeAvatarTextures(UUID textureID)
{
}

public void SendAvatarInterestsReply(UUID avatarID, uint
wantMask, string wantText, uint skillsMask, string skillsText, string
languages)
{
}

public void SendGroupAccountingDetails(IClientAPI sender,UUID
groupID, UUID transactionID, UUID sessionID, int amt)
{
}

public void SendGroupAccountingSummary(IClientAPI sender,UUID
groupID, uint moneyAmt, int totalTier, int usedTier)
{
}

public void SendGroupTransactionsSummaryDetails(IClientAPI
sender,UUID groupID, UUID transactionID, UUID sessionID,int amt)
{
}

public void SendGroupVoteHistory(UUID groupID, UUID
transactionID, GroupVoteHistory[] Votes)
{
}

public void SendGroupActiveProposals(UUID groupID, UUID
transactionID, GroupActiveProposals[] Proposals)
{
}

public void SendChangeUserRights(UUID agentID, UUID friendID,
int rights)
{
}

public void SendTextBoxRequest(string message, int
chatChannel, string objectname, string ownerFirstName, string
ownerLastName, UUID objectId)
{
}

public void StopFlying(ISceneEntity presence)
{
}
}
}