* Created an LLUDP folder to hold extensions that are purely LLUDP packet handlers. This is not a complete abstraction away from transport protocols, but it's a start
* Moved physics code from Movement.cs into PhysicsSimple.cs, and moved the physics loop into a thread in SceneManager
* Simian.ini cleanup


git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2490 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2009-03-17 22:33:22 +00:00
parent 3c5d40402f
commit 241b480320
22 changed files with 997 additions and 877 deletions

View File

@@ -1,154 +0,0 @@
using System;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class ConnectionManagement : IExtension<ISceneProvider>
{
ISceneProvider scene;
public ConnectionManagement()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.UseCircuitCode, UseCircuitCodeHandler);
scene.UDP.RegisterPacketCallback(PacketType.StartPingCheck, StartPingCheckHandler);
scene.UDP.RegisterPacketCallback(PacketType.LogoutRequest, LogoutRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentThrottle, AgentThrottleHandler);
scene.UDP.RegisterPacketCallback(PacketType.RegionHandshakeReply, RegionHandshakeReplyHandler);
return true;
}
public void Stop()
{
}
void UseCircuitCodeHandler(Packet packet, Agent agent)
{
RegionHandshakePacket handshake = new RegionHandshakePacket();
handshake.RegionInfo.BillableFactor = 0f;
handshake.RegionInfo.CacheID = UUID.Random();
handshake.RegionInfo.IsEstateManager = false;
handshake.RegionInfo.RegionFlags = (uint)scene.RegionFlags;
handshake.RegionInfo.SimOwner = UUID.Random();
handshake.RegionInfo.SimAccess = (byte)SimAccess.Min;
handshake.RegionInfo.SimName = Utils.StringToBytes(scene.RegionName);
handshake.RegionInfo.WaterHeight = scene.WaterHeight;
handshake.RegionInfo.TerrainBase0 = UUID.Zero;
handshake.RegionInfo.TerrainBase1 = UUID.Zero;
handshake.RegionInfo.TerrainBase2 = UUID.Zero;
handshake.RegionInfo.TerrainBase3 = UUID.Zero;
handshake.RegionInfo.TerrainDetail0 = UUID.Zero;
handshake.RegionInfo.TerrainDetail1 = UUID.Zero;
handshake.RegionInfo.TerrainDetail2 = UUID.Zero;
handshake.RegionInfo.TerrainDetail3 = UUID.Zero;
handshake.RegionInfo.TerrainHeightRange00 = 0f;
handshake.RegionInfo.TerrainHeightRange01 = 20f;
handshake.RegionInfo.TerrainHeightRange10 = 0f;
handshake.RegionInfo.TerrainHeightRange11 = 20f;
handshake.RegionInfo.TerrainStartHeight00 = 0f;
handshake.RegionInfo.TerrainStartHeight01 = 40f;
handshake.RegionInfo.TerrainStartHeight10 = 0f;
handshake.RegionInfo.TerrainStartHeight11 = 40f;
handshake.RegionInfo2.RegionID = scene.RegionID;
scene.UDP.SendPacket(agent.ID, handshake, PacketCategory.Transaction);
}
void StartPingCheckHandler(Packet packet, Agent agent)
{
StartPingCheckPacket start = (StartPingCheckPacket)packet;
CompletePingCheckPacket complete = new CompletePingCheckPacket();
complete.Header.Reliable = false;
complete.PingID.PingID = start.PingID.PingID;
scene.UDP.SendPacket(agent.ID, complete, PacketCategory.Overhead);
}
void LogoutRequestHandler(Packet packet, Agent agent)
{
LogoutReplyPacket reply = new LogoutReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.AgentData.SessionID = agent.SessionID;
reply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1];
reply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock();
reply.InventoryData[0].ItemID = UUID.Zero;
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
scene.ObjectRemove(this, agent.ID);
}
void AgentThrottleHandler(Packet packet, Agent agent)
{
AgentThrottlePacket throttle = (AgentThrottlePacket)packet;
// TODO: These need to be transmitted to neighbor sims before child agent connections can be established
//throttle.Throttle.Throttles
// Initiate the connection process for this agent to neighboring regions
scene.InformClientOfNeighbors(agent);
}
void RegionHandshakeReplyHandler(Packet packet, Agent agent)
{
// Send updates and appearances for every avatar to this new avatar
SynchronizeStateTo(agent);
}
// HACK: The reduction provider will deprecate this at some point
void SynchronizeStateTo(Agent agent)
{
// Send the parcel overlay
scene.Parcels.SendParcelOverlay(agent);
// Send object updates for objects and avatars
scene.ForEachObject(delegate(SimulationObject obj)
{
ObjectUpdatePacket update = new ObjectUpdatePacket();
update.RegionData.RegionHandle = scene.RegionHandle;
update.RegionData.TimeDilation = (ushort)(scene.Physics.TimeDilation * (float)UInt16.MaxValue);
update.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[1];
update.ObjectData[0] = SimulationObject.BuildUpdateBlock(obj.Prim, obj.Prim.Flags, obj.CRC);
scene.UDP.SendPacket(agent.ID, update, PacketCategory.State);
});
// Send appearances for all avatars
scene.ForEachAgent(
delegate(Agent otherAgent)
{
if (otherAgent != agent)
{
// Send appearances for this avatar
AvatarAppearancePacket appearance = otherAgent.BuildAppearancePacket();
scene.UDP.SendPacket(agent.ID, appearance, PacketCategory.State);
}
}
);
// Send terrain data
SendLayerData(agent);
}
void SendLayerData(Agent agent)
{
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x++)
{
float[,] heightmap = scene.GetTerrainPatch((uint)x, (uint)y);
LayerDataPacket layer = TerrainCompressor.CreateLandPacket(heightmap, x, y);
scene.UDP.SendPacket(agent.ID, layer, PacketCategory.Terrain);
}
}
}
}
}

View File

@@ -1,278 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class ImageDownload
{
public const int FIRST_IMAGE_PACKET_SIZE = 600;
public const int IMAGE_PACKET_SIZE = 1000;
public AssetTexture Texture;
public Agent Agent;
public int DiscardLevel;
public float Priority;
public int CurrentPacket;
public int StopPacket;
public ImageDownload(AssetTexture texture, Agent agent, int discardLevel, float priority, int packet)
{
Texture = texture;
Agent = agent;
Update(discardLevel, priority, packet);
}
/// <summary>
/// Updates an image transfer with new information and recalculates
/// offsets
/// </summary>
/// <param name="discardLevel">New requested discard level</param>
/// <param name="priority">New requested priority</param>
/// <param name="packet">New requested packet offset</param>
public void Update(int discardLevel, float priority, int packet)
{
Priority = priority;
if (Texture != null)
{
if (Texture.LayerInfo != null && Texture.LayerInfo.Length > 0)
{
DiscardLevel = Utils.Clamp(discardLevel, 0, Texture.LayerInfo.Length - 1);
StopPacket = GetPacketForBytePosition(Texture.LayerInfo[(Texture.LayerInfo.Length - 1) - DiscardLevel].End);
}
else
{
// No layers, send the full image
DiscardLevel = 0;
StopPacket = GetPacketForBytePosition(Texture.AssetData.Length - 1);
}
CurrentPacket = Utils.Clamp(packet, 1, TexturePacketCount());
}
else
{
DiscardLevel = discardLevel;
Priority = priority;
CurrentPacket = packet;
}
}
/// <summary>
/// Returns the total number of packets needed to transfer this texture,
/// including the first packet of size FIRST_IMAGE_PACKET_SIZE
/// </summary>
/// <returns>Total number of packets needed to transfer this texture</returns>
public int TexturePacketCount()
{
return ((Texture.AssetData.Length - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1;
}
/// <summary>
/// Returns the current byte offset for this transfer, calculated from
/// the CurrentPacket
/// </summary>
/// <returns>Current byte offset for this transfer</returns>
public int CurrentBytePosition()
{
return FIRST_IMAGE_PACKET_SIZE + (CurrentPacket - 1) * IMAGE_PACKET_SIZE;
}
/// <summary>
/// Returns the size, in bytes, of the last packet. This will be somewhere
/// between 1 and IMAGE_PACKET_SIZE bytes
/// </summary>
/// <returns>Size of the last packet in the transfer</returns>
public int LastPacketSize()
{
return Texture.AssetData.Length - (FIRST_IMAGE_PACKET_SIZE + ((TexturePacketCount() - 2) * IMAGE_PACKET_SIZE));
}
/// <summary>
/// Find the packet number that contains a given byte position
/// </summary>
/// <param name="bytePosition">Byte position</param>
/// <returns>Packet number that contains the given byte position</returns>
int GetPacketForBytePosition(int bytePosition)
{
return ((bytePosition - FIRST_IMAGE_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE);
}
}
public class ImageDelivery : IExtension<ISceneProvider>
{
ISceneProvider scene;
Dictionary<UUID, ImageDownload> CurrentDownloads = new Dictionary<UUID, ImageDownload>();
public ImageDelivery()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.RequestImage, RequestImageHandler);
return true;
}
public void Stop()
{
}
void RequestImageHandler(Packet packet, Agent agent)
{
RequestImagePacket request = (RequestImagePacket)packet;
for (int i = 0; i < request.RequestImage.Length; i++)
{
RequestImagePacket.RequestImageBlock block = request.RequestImage[i];
ImageDownload download;
bool downloadFound = CurrentDownloads.TryGetValue(block.Image, out download);
if (downloadFound)
{
lock (download)
{
if (block.DiscardLevel == -1 && block.DownloadPriority == 0.0f)
{
Logger.DebugLog(String.Format("Image download {0} is aborting", block.Image));
}
else
{
if (block.DiscardLevel < download.DiscardLevel)
Logger.DebugLog(String.Format("Image download {0} is changing from DiscardLevel {1} to {2}",
block.Image, download.DiscardLevel, block.DiscardLevel));
if (block.DownloadPriority != download.Priority)
Logger.DebugLog(String.Format("Image download {0} is changing from Priority {1} to {2}",
block.Image, download.Priority, block.DownloadPriority));
if (block.Packet != download.CurrentPacket)
Logger.DebugLog(String.Format("Image download {0} is changing from Packet {1} to {2}",
block.Image, download.CurrentPacket, block.Packet));
}
// Update download
download.Update(block.DiscardLevel, block.DownloadPriority, (int)block.Packet);
}
}
else if (block.DiscardLevel == -1 && block.DownloadPriority == 0.0f)
{
// Aborting a download we are not tracking, ignore
}
else
{
//bool bake = ((ImageType)block.Type == ImageType.Baked);
// New download, check if we have this image
Asset asset;
if (scene.Server.Assets.TryGetAsset(block.Image, out asset) && asset is AssetTexture)
{
SendTexture(agent, (AssetTexture)asset, block.DiscardLevel, (int)block.Packet, block.DownloadPriority);
}
else
{
Logger.Log("Request for a missing texture " + block.Image.ToString(), Helpers.LogLevel.Warning);
ImageNotInDatabasePacket notfound = new ImageNotInDatabasePacket();
notfound.ImageID.ID = block.Image;
scene.UDP.SendPacket(agent.ID, notfound, PacketCategory.Texture);
}
}
}
}
void SendTexture(Agent agent, AssetTexture texture, int discardLevel, int packet, float priority)
{
ImageDownload download = new ImageDownload(texture, agent, discardLevel, priority, packet);
Logger.DebugLog(String.Format(
"Starting new download for {0}, DiscardLevel: {1}, Priority: {2}, Start: {3}, End: {4}, Total: {5}",
texture.AssetID, discardLevel, priority, download.CurrentPacket, download.StopPacket,
download.TexturePacketCount()));
// Send initial data
ImageDataPacket data = new ImageDataPacket();
data.ImageID.Codec = (byte)ImageCodec.J2C;
data.ImageID.ID = download.Texture.AssetID;
data.ImageID.Packets = (ushort)download.TexturePacketCount();
data.ImageID.Size = (uint)download.Texture.AssetData.Length;
// The first bytes of the image are always sent in the ImageData packet
data.ImageData = new ImageDataPacket.ImageDataBlock();
int imageDataSize = (download.Texture.AssetData.Length >= ImageDownload.FIRST_IMAGE_PACKET_SIZE) ?
ImageDownload.FIRST_IMAGE_PACKET_SIZE : download.Texture.AssetData.Length;
try
{
data.ImageData.Data = new byte[imageDataSize];
Buffer.BlockCopy(download.Texture.AssetData, 0, data.ImageData.Data, 0, imageDataSize);
}
catch (Exception ex)
{
Logger.Log(String.Format("{0}: imageDataSize={1}", ex.Message, imageDataSize),
Helpers.LogLevel.Error);
}
scene.UDP.SendPacket(agent.ID, data, PacketCategory.Texture);
// Check if ImagePacket packets need to be sent to complete this transfer
if (download.CurrentPacket <= download.StopPacket)
{
// Insert this download into the dictionary
lock (CurrentDownloads)
CurrentDownloads[texture.AssetID] = download;
// Send all of the remaining packets
ThreadPool.QueueUserWorkItem(
delegate(object obj)
{
while (download.CurrentPacket <= download.StopPacket)
{
if (download.Priority == 0.0f && download.DiscardLevel == -1)
break;
lock (download)
{
int imagePacketSize = (download.CurrentPacket == download.TexturePacketCount() - 1) ?
download.LastPacketSize() : ImageDownload.IMAGE_PACKET_SIZE;
ImagePacketPacket transfer = new ImagePacketPacket();
transfer.ImageID.ID = texture.AssetID;
transfer.ImageID.Packet = (ushort)download.CurrentPacket;
transfer.ImageData.Data = new byte[imagePacketSize];
try
{
Buffer.BlockCopy(download.Texture.AssetData, download.CurrentBytePosition(),
transfer.ImageData.Data, 0, imagePacketSize);
}
catch (Exception ex)
{
Logger.Log(String.Format(
"{0}: CurrentBytePosition()={1}, AssetData.Length={2} imagePacketSize={3}",
ex.Message, download.CurrentBytePosition(), download.Texture.AssetData.Length,
imagePacketSize), Helpers.LogLevel.Error);
}
scene.UDP.SendPacket(agent.ID, transfer, PacketCategory.Texture);
++download.CurrentPacket;
}
}
Logger.DebugLog("Completed image transfer for " + texture.AssetID.ToString());
// Transfer is complete, remove the reference
lock (CurrentDownloads)
CurrentDownloads.Remove(texture.AssetID);
}
);
}
}
}
}

View File

@@ -1,406 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class LLAgents : IExtension<ISceneProvider>
{
ISceneProvider scene;
int currentWearablesSerialNum = -1;
int currentAnimSequenceNum = 0;
Timer coarseLocationTimer;
public LLAgents()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.AvatarPropertiesRequest, AvatarPropertiesRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentWearablesRequest, AgentWearablesRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentIsNowWearing, AgentIsNowWearingHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentSetAppearance, AgentSetAppearanceHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentCachedTexture, AgentCachedTextureHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentHeightWidth, AgentHeightWidthHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentAnimation, AgentAnimationHandler);
scene.UDP.RegisterPacketCallback(PacketType.SoundTrigger, SoundTriggerHandler);
scene.UDP.RegisterPacketCallback(PacketType.ViewerEffect, ViewerEffectHandler);
scene.UDP.RegisterPacketCallback(PacketType.UUIDNameRequest, UUIDNameRequestHandler);
if (coarseLocationTimer != null) coarseLocationTimer.Dispose();
coarseLocationTimer = new Timer(coarseLocationTimer_Elapsed);
coarseLocationTimer.Change(1000, 1000);
return true;
}
public void Stop()
{
if (coarseLocationTimer != null)
{
coarseLocationTimer.Dispose();
coarseLocationTimer = null;
}
}
void AgentAnimationHandler(Packet packet, Agent agent)
{
AgentAnimationPacket animPacket = (AgentAnimationPacket)packet;
bool changed = false;
for (int i = 0; i < animPacket.AnimationList.Length; i++)
{
AgentAnimationPacket.AnimationListBlock block = animPacket.AnimationList[i];
if (block.StartAnim)
{
if (agent.Animations.Add(block.AnimID, ref currentAnimSequenceNum))
changed = true;
}
else
{
if (agent.Animations.Remove(block.AnimID))
changed = true;
}
}
if (changed)
scene.Avatars.SendAnimations(agent);
}
void ViewerEffectHandler(Packet packet, Agent agent)
{
ViewerEffectPacket incomingEffects = (ViewerEffectPacket)packet;
ViewerEffect[] outgoingEffects = new ViewerEffect[incomingEffects.Effect.Length];
for (int i = 0; i < outgoingEffects.Length; i++)
{
ViewerEffectPacket.EffectBlock block = incomingEffects.Effect[i];
outgoingEffects[i] = new ViewerEffect(block.ID, (EffectType)block.Type, block.AgentID,
new Color4(block.Color, 0, true), block.Duration, block.TypeData);
}
scene.TriggerEffects(this, outgoingEffects);
}
void AvatarPropertiesRequestHandler(Packet packet, Agent agent)
{
AvatarPropertiesRequestPacket request = (AvatarPropertiesRequestPacket)packet;
Agent foundAgent;
if (scene.TryGetAgent(request.AgentData.AvatarID, out foundAgent))
{
AvatarPropertiesReplyPacket reply = new AvatarPropertiesReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.AgentData.AvatarID = request.AgentData.AvatarID;
reply.PropertiesData.AboutText = Utils.StringToBytes(foundAgent.Info.ProfileAboutText);
reply.PropertiesData.BornOn = Utils.StringToBytes(foundAgent.Info.ProfileBornOn);
reply.PropertiesData.CharterMember = new byte[1];
reply.PropertiesData.FLAboutText = Utils.StringToBytes(foundAgent.Info.ProfileFirstText);
reply.PropertiesData.Flags = (uint)foundAgent.Info.ProfileFlags;
reply.PropertiesData.FLImageID = foundAgent.Info.ProfileFirstImage;
reply.PropertiesData.ImageID = foundAgent.Info.ProfileImage;
reply.PropertiesData.PartnerID = foundAgent.Info.PartnerID;
reply.PropertiesData.ProfileURL = Utils.StringToBytes(foundAgent.Info.ProfileURL);
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
else
{
Logger.Log("AvatarPropertiesRequest for unknown agent " + request.AgentData.AvatarID.ToString(),
Helpers.LogLevel.Warning);
}
}
void AgentWearablesRequestHandler(Packet packet, Agent agent)
{
SendWearables(agent);
}
void AgentIsNowWearingHandler(Packet packet, Agent agent)
{
AgentIsNowWearingPacket wearing = (AgentIsNowWearingPacket)packet;
for (int i = 0; i < wearing.WearableData.Length; i++)
{
UUID itemID = wearing.WearableData[i].ItemID;
#region Update Wearables
switch ((WearableType)wearing.WearableData[i].WearableType)
{
case WearableType.Shape:
agent.Info.ShapeItem = itemID;
break;
case WearableType.Skin:
agent.Info.SkinItem = itemID;
break;
case WearableType.Hair:
agent.Info.HairItem = itemID;
break;
case WearableType.Eyes:
agent.Info.EyesItem = itemID;
break;
case WearableType.Shirt:
agent.Info.ShirtItem = itemID;
break;
case WearableType.Pants:
agent.Info.PantsItem = itemID;
break;
case WearableType.Shoes:
agent.Info.ShoesItem = itemID;
break;
case WearableType.Socks:
agent.Info.SocksItem = itemID;
break;
case WearableType.Jacket:
agent.Info.JacketItem = itemID;
break;
case WearableType.Gloves:
agent.Info.GlovesItem = itemID;
break;
case WearableType.Undershirt:
agent.Info.UndershirtItem = itemID;
break;
case WearableType.Underpants:
agent.Info.UnderpantsItem = itemID;
break;
case WearableType.Skirt:
agent.Info.SkirtItem = itemID;
break;
}
#endregion Update Wearables
}
// FIXME: GetCurrentWearables() is a very expensive call, remove it from this debug line
Logger.DebugLog("Updated agent wearables, new count: " + GetCurrentWearables(agent).Count);
}
void AgentSetAppearanceHandler(Packet packet, Agent agent)
{
AgentSetAppearancePacket set = (AgentSetAppearancePacket)packet;
Logger.DebugLog("Updating avatar appearance");
//TODO: Store this for cached bake responses
for (int i = 0; i < set.WearableData.Length; i++)
{
AppearanceManager.TextureIndex index = (AppearanceManager.TextureIndex)set.WearableData[i].TextureIndex;
UUID cacheID = set.WearableData[i].CacheID;
Logger.DebugLog(String.Format("WearableData: {0} is now {1}", index, cacheID));
}
// Create a TextureEntry
Primitive.TextureEntry textureEntry = new Primitive.TextureEntry(set.ObjectData.TextureEntry, 0,
set.ObjectData.TextureEntry.Length);
// Create a block of VisualParams
byte[] visualParams = new byte[set.VisualParam.Length];
for (int i = 0; i < set.VisualParam.Length; i++)
visualParams[i] = set.VisualParam[i].ParamValue;
scene.AgentAppearance(this, agent, textureEntry, visualParams);
}
void AgentCachedTextureHandler(Packet packet, Agent agent)
{
AgentCachedTexturePacket cached = (AgentCachedTexturePacket)packet;
AgentCachedTextureResponsePacket response = new AgentCachedTextureResponsePacket();
response.AgentData.AgentID = agent.ID;
response.AgentData.SerialNum = cached.AgentData.SerialNum;
response.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cached.WearableData.Length];
// TODO: Respond back with actual cache entries if we have them
for (int i = 0; i < cached.WearableData.Length; i++)
{
response.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
response.WearableData[i].TextureIndex = cached.WearableData[i].TextureIndex;
response.WearableData[i].TextureID = UUID.Zero;
response.WearableData[i].HostName = Utils.EmptyBytes;
}
response.Header.Zerocoded = true;
scene.UDP.SendPacket(agent.ID, response, PacketCategory.Transaction);
}
void AgentHeightWidthHandler(Packet packet, Agent agent)
{
//AgentHeightWidthPacket heightWidth = (AgentHeightWidthPacket)packet;
// TODO: These are the screen size dimensions. Useful when we start doing frustum culling
//Logger.Log(String.Format("Agent wants to set height={0}, width={1}",
// heightWidth.HeightWidthBlock.Height, heightWidth.HeightWidthBlock.Width), Helpers.LogLevel.Info);
}
void SoundTriggerHandler(Packet packet, Agent agent)
{
SoundTriggerPacket trigger = (SoundTriggerPacket)packet;
TriggerSound(agent, trigger.SoundData.SoundID, trigger.SoundData.Gain);
}
void UUIDNameRequestHandler(Packet packet, Agent agent)
{
UUIDNameRequestPacket request = (UUIDNameRequestPacket)packet;
UUIDNameReplyPacket reply = new UUIDNameReplyPacket();
reply.UUIDNameBlock = new UUIDNameReplyPacket.UUIDNameBlockBlock[request.UUIDNameBlock.Length];
for (int i = 0; i < request.UUIDNameBlock.Length; i++)
{
UUID id = request.UUIDNameBlock[i].ID;
reply.UUIDNameBlock[i] = new UUIDNameReplyPacket.UUIDNameBlockBlock();
reply.UUIDNameBlock[i].ID = id;
Agent foundAgent;
if (scene.TryGetAgent(id, out foundAgent))
{
reply.UUIDNameBlock[i].FirstName = Utils.StringToBytes(foundAgent.Info.FirstName);
reply.UUIDNameBlock[i].LastName = Utils.StringToBytes(foundAgent.Info.LastName);
}
else
{
reply.UUIDNameBlock[i].FirstName = Utils.EmptyBytes;
reply.UUIDNameBlock[i].LastName = Utils.EmptyBytes;
}
}
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
void TriggerSound(Agent agent, UUID soundID, float gain)
{
scene.TriggerSound(this, agent.ID, agent.ID, agent.ID, soundID, agent.Avatar.Prim.Position, gain);
}
void SendWearables(Agent agent)
{
AgentWearablesUpdatePacket update = new AgentWearablesUpdatePacket();
update.AgentData.AgentID = agent.ID;
Dictionary<WearableType, InventoryItem> wearables = GetCurrentWearables(agent);
update.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[wearables.Count];
int i = 0;
foreach (KeyValuePair<WearableType, InventoryItem> kvp in wearables)
{
update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
update.WearableData[i].AssetID = kvp.Value.AssetID;
update.WearableData[i].ItemID = kvp.Value.ID;
update.WearableData[i].WearableType = (byte)kvp.Key;
++i;
}
// Technically this should be per-agent, but if the only requirement is that it
// increments this is easier
update.AgentData.SerialNum = (uint)Interlocked.Increment(ref currentWearablesSerialNum);
Logger.DebugLog(String.Format("Sending info about {0} wearables", wearables.Count));
scene.UDP.SendPacket(agent.ID, update, PacketCategory.Asset);
}
Dictionary<WearableType, InventoryItem> GetCurrentWearables(Agent agent)
{
Dictionary<WearableType, InventoryItem> wearables = new Dictionary<WearableType, InventoryItem>();
TryAddWearable(agent.ID, wearables, WearableType.Shape, agent.Info.ShapeItem);
TryAddWearable(agent.ID, wearables, WearableType.Skin, agent.Info.SkinItem);
TryAddWearable(agent.ID, wearables, WearableType.Hair, agent.Info.HairItem);
TryAddWearable(agent.ID, wearables, WearableType.Eyes, agent.Info.EyesItem);
TryAddWearable(agent.ID, wearables, WearableType.Shirt, agent.Info.ShirtItem);
TryAddWearable(agent.ID, wearables, WearableType.Pants, agent.Info.PantsItem);
TryAddWearable(agent.ID, wearables, WearableType.Shoes, agent.Info.ShoesItem);
TryAddWearable(agent.ID, wearables, WearableType.Socks, agent.Info.SocksItem);
TryAddWearable(agent.ID, wearables, WearableType.Jacket, agent.Info.JacketItem);
TryAddWearable(agent.ID, wearables, WearableType.Gloves, agent.Info.GlovesItem);
TryAddWearable(agent.ID, wearables, WearableType.Undershirt, agent.Info.UndershirtItem);
TryAddWearable(agent.ID, wearables, WearableType.Underpants, agent.Info.UnderpantsItem);
TryAddWearable(agent.ID, wearables, WearableType.Skirt, agent.Info.SkirtItem);
return wearables;
}
bool TryAddWearable(UUID agentID, Dictionary<WearableType, InventoryItem> wearables, WearableType type, UUID itemID)
{
InventoryObject obj;
if (itemID != UUID.Zero && scene.Server.Inventory.TryGetInventory(agentID, itemID, out obj) &&
obj is InventoryItem)
{
wearables.Add(type, (InventoryItem)obj);
return true;
}
else
{
return false;
}
}
void coarseLocationTimer_Elapsed(object sender)
{
// Create lists containing all of the agent blocks
List<CoarseLocationUpdatePacket.AgentDataBlock> agentDatas = new List<CoarseLocationUpdatePacket.AgentDataBlock>();
List<CoarseLocationUpdatePacket.LocationBlock> agentLocations = new List<CoarseLocationUpdatePacket.LocationBlock>();
scene.ForEachAgent(
delegate(Agent agent)
{
CoarseLocationUpdatePacket.AgentDataBlock dataBlock = new CoarseLocationUpdatePacket.AgentDataBlock();
dataBlock.AgentID = agent.ID;
CoarseLocationUpdatePacket.LocationBlock locationBlock = new CoarseLocationUpdatePacket.LocationBlock();
locationBlock.X = (byte)agent.Avatar.Prim.Position.X;
locationBlock.Y = (byte)agent.Avatar.Prim.Position.Y;
locationBlock.Z = (byte)((int)agent.Avatar.Prim.Position.Z / 4);
agentDatas.Add(dataBlock);
agentLocations.Add(locationBlock);
}
);
// Send location updates out to each agent
scene.ForEachAgent(
delegate(Agent agent)
{
CoarseLocationUpdatePacket update = new CoarseLocationUpdatePacket();
update.Index.Prey = -1;
update.Index.You = 0;
// Count the number of blocks to send out
int count = 0;
for (int i = 0; i < agentDatas.Count; i++)
{
if (agentDatas[i].AgentID != agent.ID)
++count;
}
update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[count];
update.Location = new CoarseLocationUpdatePacket.LocationBlock[count];
int j = 0;
for (int i = 0; i < agentDatas.Count; i++)
{
if (agentDatas[i].AgentID != agent.ID)
{
update.AgentData[j] = agentDatas[i];
update.Location[j] = agentLocations[i];
++j;
}
}
scene.UDP.SendPacket(agent.ID, update, PacketCategory.State);
}
);
}
}
}

View File

@@ -1,683 +0,0 @@
using System;
using System.Collections.Generic;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class LLInventory : IExtension<ISceneProvider>
{
ISceneProvider scene;
public LLInventory()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.CreateInventoryItem, CreateInventoryItemHandler);
scene.UDP.RegisterPacketCallback(PacketType.CreateInventoryFolder, CreateInventoryFolderHandler);
scene.UDP.RegisterPacketCallback(PacketType.UpdateInventoryItem, UpdateInventoryItemHandler);
scene.UDP.RegisterPacketCallback(PacketType.FetchInventoryDescendents, FetchInventoryDescendentsHandler);
scene.UDP.RegisterPacketCallback(PacketType.FetchInventory, FetchInventoryHandler);
scene.UDP.RegisterPacketCallback(PacketType.CopyInventoryItem, CopyInventoryItemHandler);
scene.UDP.RegisterPacketCallback(PacketType.MoveInventoryItem, MoveInventoryItemHandler);
scene.UDP.RegisterPacketCallback(PacketType.MoveInventoryFolder, MoveInventoryFolderHandler);
scene.UDP.RegisterPacketCallback(PacketType.PurgeInventoryDescendents, PurgeInventoryDescendentsHandler);
scene.UDP.RegisterPacketCallback(PacketType.DeRezObject, DeRezObjectHandler);
return true;
}
public void Stop()
{
}
void CreateInventoryItemHandler(Packet packet, Agent agent)
{
CreateInventoryItemPacket create = (CreateInventoryItemPacket)packet;
UUID assetID;
if (create.InventoryBlock.TransactionID != UUID.Zero)
assetID = UUID.Combine(create.InventoryBlock.TransactionID, agent.SecureSessionID);
else
assetID = UUID.Random();
UUID parentID = (create.InventoryBlock.FolderID != UUID.Zero) ? create.InventoryBlock.FolderID : agent.Info.InventoryRoot;
AssetType assetType = (AssetType)create.InventoryBlock.Type;
switch (assetType)
{
case AssetType.Gesture:
Logger.Log("Need to create a default gesture asset!", Helpers.LogLevel.Warning);
break;
}
if (parentID == UUID.Zero)
parentID = agent.Info.InventoryRoot;
// Create the inventory item
InventoryItem item = scene.Server.Inventory.CreateItem(agent.ID, Utils.BytesToString(create.InventoryBlock.Name),
"Created in Simian", (InventoryType)create.InventoryBlock.InvType, assetType, assetID, parentID,
PermissionMask.All, (PermissionMask)create.InventoryBlock.NextOwnerMask, agent.ID,
agent.ID, create.InventoryBlock.TransactionID, create.InventoryBlock.CallbackID);
// Send a success response
SendItemCreatedPacket(agent, item, create.InventoryBlock.TransactionID, create.InventoryBlock.CallbackID);
}
void CreateInventoryFolderHandler(Packet packet, Agent agent)
{
CreateInventoryFolderPacket create = (CreateInventoryFolderPacket)packet;
UUID folderID = create.FolderData.FolderID;
if (folderID == UUID.Zero)
folderID = agent.Info.InventoryRoot;
scene.Server.Inventory.CreateFolder(agent.ID, folderID, Utils.BytesToString(create.FolderData.Name),
(AssetType)create.FolderData.Type, create.FolderData.ParentID, agent.ID);
}
void UpdateInventoryItemHandler(Packet packet, Agent agent)
{
UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)packet;
// No packet is sent back to the client, we just need to update the
// inventory item locally
for (int i = 0; i < update.InventoryData.Length; i++)
{
UpdateInventoryItemPacket.InventoryDataBlock block = update.InventoryData[i];
InventoryObject obj;
if (scene.Server.Inventory.TryGetInventory(agent.ID, block.ItemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
//item.Permissions.BaseMask = (PermissionMask)block.BaseMask;
item.Permissions.BaseMask = PermissionMask.All;
//item.Permissions.EveryoneMask = (PermissionMask)block.EveryoneMask;
item.Permissions.EveryoneMask = PermissionMask.All;
//item.Permissions.GroupMask = (PermissionMask)block.GroupMask;
item.Permissions.GroupMask = PermissionMask.All;
//item.Permissions.NextOwnerMask = (PermissionMask)block.NextOwnerMask;
item.Permissions.NextOwnerMask = PermissionMask.All;
//item.Permissions.OwnerMask = (PermissionMask)block.OwnerMask;
item.Permissions.OwnerMask = PermissionMask.All;
//block.CRC;
item.CreationDate = Utils.UnixTimeToDateTime(block.CreationDate);
item.CreatorID = block.CreatorID;
item.Name = Utils.BytesToString(block.Description);
item.Flags = block.Flags;
item.ParentID = block.FolderID;
item.GroupID = block.GroupID;
item.GroupOwned = block.GroupOwned;
item.InventoryType = (InventoryType)block.InvType;
item.Name = Utils.BytesToString(block.Name);
item.OwnerID = block.OwnerID;
item.SalePrice = block.SalePrice;
item.SaleType = (SaleType)block.SaleType;
item.AssetType = (AssetType)block.Type;
item.AssetID = UUID.Combine(block.TransactionID, agent.SecureSessionID);
Logger.DebugLog(String.Format(
"UpdateInventoryItem: CallbackID: {0}, TransactionID: {1}",
block.CallbackID, block.TransactionID));
}
else
{
Logger.Log("Received an UpdateInventoryItem packet for unknown inventory item " +
block.ItemID.ToString(), Helpers.LogLevel.Warning);
}
}
}
void FetchInventoryDescendentsHandler(Packet packet, Agent agent)
{
// A very safe estimate of the fixed minimum packet size
const int PACKET_OVERHEAD = 96;
FetchInventoryDescendentsPacket fetch = (FetchInventoryDescendentsPacket)packet;
bool sendFolders = fetch.InventoryData.FetchFolders;
bool sendItems = fetch.InventoryData.FetchItems;
// TODO: Obey SortOrder
//InventorySortOrder order = (InventorySortOrder)fetch.InventoryData.SortOrder;
// TODO: Use OwnerID
// TODO: Do we need to obey InventorySortOrder?
InventoryObject invObject;
if (scene.Server.Inventory.TryGetInventory(agent.ID, fetch.InventoryData.FolderID, out invObject) && invObject is InventoryFolder)
{
InventoryFolder folder = (InventoryFolder)invObject;
int descendCount;
int version;
List<InventoryItem> items = new List<InventoryItem>();
List<InventoryFolder> folders = new List<InventoryFolder>();
InventoryDescendentsPacket.FolderDataBlock[] folderBlocks;
InventoryDescendentsPacket.ItemDataBlock[] itemBlocks;
lock (folder.Children.Dictionary)
{
// These two are coupled to the actual items in the dictionary,
// so they are set inside the lock
descendCount = folder.Children.Count;
version = folder.Version;
if (sendItems || sendFolders)
{
// Create a list of all of the folders and items under this folder
folder.Children.ForEach(
delegate(InventoryObject obj)
{
if (obj is InventoryItem)
items.Add((InventoryItem)obj);
else
folders.Add((InventoryFolder)obj);
}
);
}
}
if (sendFolders)
{
folderBlocks = new InventoryDescendentsPacket.FolderDataBlock[folders.Count];
for (int i = 0; i < folders.Count; i++)
{
InventoryFolder currentFolder = folders[i];
folderBlocks[i] = new InventoryDescendentsPacket.FolderDataBlock();
folderBlocks[i].FolderID = currentFolder.ID;
folderBlocks[i].Name = Utils.StringToBytes(currentFolder.Name);
folderBlocks[i].ParentID = currentFolder.ParentID;
folderBlocks[i].Type = (sbyte)currentFolder.PreferredType;
}
}
else
{
folderBlocks = new InventoryDescendentsPacket.FolderDataBlock[0];
}
if (sendItems)
{
itemBlocks = new InventoryDescendentsPacket.ItemDataBlock[items.Count];
for (int i = 0; i < items.Count; i++)
{
InventoryItem currentItem = items[i];
itemBlocks[i] = new InventoryDescendentsPacket.ItemDataBlock();
itemBlocks[i].AssetID = currentItem.AssetID;
itemBlocks[i].BaseMask = (uint)currentItem.Permissions.BaseMask;
itemBlocks[i].CRC = currentItem.CRC;
itemBlocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(currentItem.CreationDate);
itemBlocks[i].CreatorID = currentItem.CreatorID;
itemBlocks[i].Description = Utils.StringToBytes(currentItem.Description);
itemBlocks[i].EveryoneMask = (uint)currentItem.Permissions.EveryoneMask;
itemBlocks[i].Flags = currentItem.Flags;
itemBlocks[i].FolderID = currentItem.ParentID;
itemBlocks[i].GroupID = currentItem.GroupID;
itemBlocks[i].GroupMask = (uint)currentItem.Permissions.GroupMask;
itemBlocks[i].GroupOwned = currentItem.GroupOwned;
itemBlocks[i].InvType = (sbyte)currentItem.InventoryType;
itemBlocks[i].ItemID = currentItem.ID;
itemBlocks[i].Name = Utils.StringToBytes(currentItem.Name);
itemBlocks[i].NextOwnerMask = (uint)currentItem.Permissions.NextOwnerMask;
itemBlocks[i].OwnerID = currentItem.OwnerID;
itemBlocks[i].OwnerMask = (uint)currentItem.Permissions.OwnerMask;
itemBlocks[i].SalePrice = currentItem.SalePrice;
itemBlocks[i].SaleType = (byte)currentItem.SaleType;
itemBlocks[i].Type = (sbyte)currentItem.AssetType;
}
}
else
{
itemBlocks = new InventoryDescendentsPacket.ItemDataBlock[0];
}
// FolderDataBlock and ItemDataBlock are both variable and possibly very large,
// so we handle the splitting separately. This could be replaced by some custom
// splitting
if (folderBlocks.Length > 0)
{
List<int> splitPoints = Helpers.SplitBlocks(folderBlocks, PACKET_OVERHEAD);
Logger.DebugLog(String.Format("Sending {0} InventoryDescendents packets containing {1} folders",
splitPoints.Count, folderBlocks.Length));
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
folderBlocks.Length - splitPoints[i];
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[count];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[0];
for (int j = 0; j < count; j++)
descendents.FolderData[j] = folderBlocks[splitPoints[i] + j];
scene.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
}
else
{
Logger.DebugLog("Sending a single InventoryDescendents for folders");
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[0];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[0];
scene.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
if (itemBlocks.Length > 0)
{
List<int> splitPoints = Helpers.SplitBlocks(itemBlocks, PACKET_OVERHEAD);
Logger.DebugLog(String.Format("Sending {0} InventoryDescendents packets containing {1} items",
splitPoints.Count, itemBlocks.Length));
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
itemBlocks.Length - splitPoints[i];
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[0];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[count];
for (int j = 0; j < count; j++)
descendents.ItemData[j] = itemBlocks[splitPoints[i] + j];
scene.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
}
}
else
{
Logger.Log("FetchInventoryDescendents called for an unknown folder " + fetch.InventoryData.FolderID,
Helpers.LogLevel.Warning);
}
}
void FetchInventoryHandler(Packet packet, Agent agent)
{
// This is probably too large, but better to be on the safe side
const int PACKET_OVERHEAD = 32;
FetchInventoryPacket fetch = (FetchInventoryPacket)packet;
// Create all of the blocks first. These will be split up into different packets
FetchInventoryReplyPacket.InventoryDataBlock[] blocks =
new FetchInventoryReplyPacket.InventoryDataBlock[fetch.InventoryData.Length];
for (int i = 0; i < fetch.InventoryData.Length; i++)
{
UUID itemID = fetch.InventoryData[i].ItemID;
blocks[i] = new FetchInventoryReplyPacket.InventoryDataBlock();
blocks[i].ItemID = itemID;
InventoryObject obj;
if (scene.Server.Inventory.TryGetInventory(agent.ID, itemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
blocks[i].AssetID = item.AssetID;
blocks[i].BaseMask = (uint)item.Permissions.BaseMask;
blocks[i].CRC = item.CRC;
blocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
blocks[i].CreatorID = item.CreatorID;
blocks[i].Description = Utils.StringToBytes(item.Description);
blocks[i].EveryoneMask = (uint)item.Permissions.EveryoneMask;
blocks[i].Flags = item.Flags;
blocks[i].FolderID = item.ParentID;
blocks[i].GroupID = item.GroupID;
blocks[i].GroupMask = (uint)item.Permissions.GroupMask;
blocks[i].GroupOwned = item.GroupOwned;
blocks[i].InvType = (sbyte)item.InventoryType;
blocks[i].Name = Utils.StringToBytes(item.Name);
blocks[i].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
blocks[i].OwnerID = item.OwnerID;
blocks[i].OwnerMask = (uint)item.Permissions.OwnerMask;
blocks[i].SalePrice = item.SalePrice;
blocks[i].SaleType = (byte)item.SaleType;
blocks[i].Type = (sbyte)item.AssetType;
}
else
{
Logger.Log("FetchInventory called for an unknown item " + itemID.ToString(),
Helpers.LogLevel.Warning);
blocks[i].Name = Utils.EmptyBytes;
blocks[i].Description = Utils.EmptyBytes;
}
}
// Split the blocks up into multiple packets
List<int> splitPoints = Helpers.SplitBlocks(blocks, PACKET_OVERHEAD);
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
blocks.Length - splitPoints[i];
FetchInventoryReplyPacket reply = new FetchInventoryReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[count];
for (int j = 0; j < count; j++)
reply.InventoryData[j] = blocks[splitPoints[i] + j];
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Inventory);
}
}
void CopyInventoryItemHandler(Packet packet, Agent agent)
{
CopyInventoryItemPacket copy = (CopyInventoryItemPacket)packet;
for (int i = 0; i < copy.InventoryData.Length; i++)
{
CopyInventoryItemPacket.InventoryDataBlock block = copy.InventoryData[i];
// TODO: This allows someone to copy objects from another
// agent's inventory. Should we allow that, or do any
// permission checks?
// Get the original object
InventoryObject obj;
if (scene.Server.Inventory.TryGetInventory(agent.ID, block.OldItemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
// Get the new folder
InventoryObject folderObj;
if (scene.Server.Inventory.TryGetInventory(agent.ID, block.NewFolderID, out folderObj) && folderObj is InventoryFolder)
{
string newName = Utils.BytesToString(block.NewName);
if (String.IsNullOrEmpty(newName))
newName = item.Name;
// Create the copy
InventoryItem newItem = scene.Server.Inventory.CreateItem(agent.ID, newName, item.Description, item.InventoryType,
item.AssetType, item.AssetID, folderObj.ID, item.Permissions.OwnerMask, item.Permissions.NextOwnerMask,
agent.ID, item.CreatorID, UUID.Zero, block.CallbackID);
SendItemCreatedPacket(agent, newItem, UUID.Zero, block.CallbackID);
}
else
{
Logger.Log("CopyInventoryItem called with an unknown target folder " + block.NewFolderID,
Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log("CopyInventoryItem called for an unknown item " + block.OldItemID,
Helpers.LogLevel.Warning);
}
}
}
void MoveInventoryItemHandler(Packet packet, Agent agent)
{
MoveInventoryItemPacket move = (MoveInventoryItemPacket)packet;
// TODO: What is move.AgentData.Stamp for?
List<InventoryObject> objs = new List<InventoryObject>(move.InventoryData.Length);
for (int i = 0; i < move.InventoryData.Length; i++)
{
MoveInventoryItemPacket.InventoryDataBlock block = move.InventoryData[i];
UUID newFolderID = block.FolderID;
if (newFolderID == UUID.Zero)
newFolderID = agent.Info.InventoryRoot;
InventoryObject obj = scene.Server.Inventory.MoveInventory(agent.ID, block.ItemID, newFolderID,
Utils.BytesToString(block.NewName), UUID.Zero, 0);
if (obj != null) objs.Add(obj);
}
SendBulkUpdate(agent, objs, UUID.Zero, 0);
}
void MoveInventoryFolderHandler(Packet packet, Agent agent)
{
MoveInventoryFolderPacket move = (MoveInventoryFolderPacket)packet;
// TODO: What is move.AgentData.Stamp for?
List<InventoryObject> objs = new List<InventoryObject>(move.InventoryData.Length);
for (int i = 0; i < move.InventoryData.Length; i++)
{
MoveInventoryFolderPacket.InventoryDataBlock block = move.InventoryData[i];
UUID newFolderID = block.ParentID;
if (newFolderID == UUID.Zero)
newFolderID = agent.Info.InventoryRoot;
InventoryObject obj = scene.Server.Inventory.MoveInventory(agent.ID, block.FolderID, newFolderID,
null, UUID.Zero, 0);
if (obj != null) objs.Add(obj);
}
SendBulkUpdate(agent, objs, UUID.Zero, 0);
}
void PurgeInventoryDescendentsHandler(Packet packet, Agent agent)
{
PurgeInventoryDescendentsPacket purge = (PurgeInventoryDescendentsPacket)packet;
scene.Server.Inventory.PurgeFolder(agent.ID, purge.InventoryData.FolderID);
}
void DeRezObjectHandler(Packet packet, Agent agent)
{
DeRezObjectPacket derez = (DeRezObjectPacket)packet;
DeRezDestination destination = (DeRezDestination)derez.AgentBlock.Destination;
// TODO: Check permissions
for (int i = 0; i < derez.ObjectData.Length; i++)
{
uint localID = derez.ObjectData[i].ObjectLocalID;
SimulationObject obj;
if (scene.TryGetObject(localID, out obj))
{
switch (destination)
{
case DeRezDestination.AgentInventorySave:
Logger.Log("DeRezObject: Got an AgentInventorySave, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.AgentInventoryCopy:
Logger.Log("DeRezObject: Got an AgentInventorySave, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.TaskInventory:
Logger.Log("DeRezObject: Got a TaskInventory, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.Attachment:
Logger.Log("DeRezObject: Got an Attachment, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.AgentInventoryTake:
Logger.Log("DeRezObject: Got an AgentInventoryTake, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.ForceToGodInventory:
Logger.Log("DeRezObject: Got a ForceToGodInventory, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.TrashFolder:
InventoryObject invObj;
if (scene.Server.Inventory.TryGetInventory(agent.ID, derez.AgentBlock.DestinationID, out invObj) &&
invObj is InventoryFolder)
{
// FIXME: Handle children
InventoryFolder trash = (InventoryFolder)invObj;
InventoryItem item = scene.Server.Inventory.CreateItem(agent.ID, obj.Prim.Properties.Name,
obj.Prim.Properties.Description, InventoryType.Object, AssetType.Object, obj.Prim.ID,
trash.ID, PermissionMask.All, PermissionMask.All, agent.ID, obj.Prim.Properties.CreatorID,
derez.AgentBlock.TransactionID, 0);
scene.ObjectRemove(this, obj.Prim.LocalID);
SendItemCreatedPacket(agent, item, derez.AgentBlock.TransactionID, 0);
Logger.DebugLog(String.Format("Derezzed prim {0} to agent inventory trash", obj.Prim.LocalID));
}
else
{
Logger.Log("DeRezObject: Got a TrashFolder with an invalid trash folder: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
}
break;
case DeRezDestination.AttachmentToInventory:
Logger.Log("DeRezObject: Got an AttachmentToInventory, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.AttachmentExists:
Logger.Log("DeRezObject: Got an AttachmentExists, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.ReturnToOwner:
Logger.Log("DeRezObject: Got a ReturnToOwner, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
case DeRezDestination.ReturnToLastOwner:
Logger.Log("DeRezObject: Got a ReturnToLastOwner, DestID: " +
derez.AgentBlock.DestinationID.ToString(), Helpers.LogLevel.Warning);
break;
}
}
}
}
void SendItemCreatedPacket(Agent agent, InventoryItem item, UUID transactionID, uint callbackID)
{
UpdateCreateInventoryItemPacket update = new UpdateCreateInventoryItemPacket();
update.AgentData.AgentID = agent.ID;
update.AgentData.SimApproved = true;
if (transactionID != UUID.Zero)
update.AgentData.TransactionID = transactionID;
else
update.AgentData.TransactionID = UUID.Random();
update.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
update.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
update.InventoryData[0].AssetID = item.AssetID;
update.InventoryData[0].BaseMask = (uint)item.Permissions.BaseMask;
update.InventoryData[0].CallbackID = callbackID;
update.InventoryData[0].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
update.InventoryData[0].CRC = item.CRC;
update.InventoryData[0].CreatorID = item.CreatorID;
update.InventoryData[0].Description = Utils.StringToBytes(item.Description);
update.InventoryData[0].EveryoneMask = (uint)item.Permissions.EveryoneMask;
update.InventoryData[0].Flags = item.Flags;
update.InventoryData[0].FolderID = item.ParentID;
update.InventoryData[0].GroupID = item.GroupID;
update.InventoryData[0].GroupMask = (uint)item.Permissions.GroupMask;
update.InventoryData[0].GroupOwned = item.GroupOwned;
update.InventoryData[0].InvType = (sbyte)item.InventoryType;
update.InventoryData[0].ItemID = item.ID;
update.InventoryData[0].Name = Utils.StringToBytes(item.Name);
update.InventoryData[0].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
update.InventoryData[0].OwnerID = item.OwnerID;
update.InventoryData[0].OwnerMask = (uint)item.Permissions.OwnerMask;
update.InventoryData[0].SalePrice = item.SalePrice;
update.InventoryData[0].SaleType = (byte)item.SaleType;
update.InventoryData[0].Type = (sbyte)item.AssetType;
scene.UDP.SendPacket(agent.ID, update, PacketCategory.Inventory);
}
void SendBulkUpdate(Agent agent, List<InventoryObject> objs, UUID transactionID, uint callbackID)
{
BulkUpdateInventoryPacket update = new BulkUpdateInventoryPacket();
update.AgentData.AgentID = agent.ID;
update.AgentData.TransactionID = transactionID;
// Count the number of folders and items
int items = 0;
int folders = 0;
for (int i = 0; i < objs.Count; i++)
{
if (objs[i] is InventoryItem)
++items;
else
++folders;
}
update.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[folders];
update.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[items];
items = 0;
folders = 0;
for (int i = 0; i < objs.Count; i++)
{
InventoryObject obj = objs[i];
if (obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
update.ItemData[items] = new BulkUpdateInventoryPacket.ItemDataBlock();
update.ItemData[items].AssetID = item.AssetID;
update.ItemData[items].BaseMask = (uint)item.Permissions.BaseMask;
update.ItemData[items].CallbackID = callbackID;
update.ItemData[items].CRC = item.CRC;
update.ItemData[items].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
update.ItemData[items].CreatorID = item.CreatorID;
update.ItemData[items].Description = Utils.StringToBytes(item.Description);
update.ItemData[items].EveryoneMask = (uint)item.Permissions.EveryoneMask;
update.ItemData[items].Flags = item.Flags;
update.ItemData[items].FolderID = item.ParentID;
update.ItemData[items].GroupID = item.GroupID;
update.ItemData[items].GroupMask = (uint)item.Permissions.GroupMask;
update.ItemData[items].GroupOwned = item.GroupOwned;
update.ItemData[items].InvType = (sbyte)item.InventoryType;
update.ItemData[items].ItemID = item.ID;
update.ItemData[items].Name = Utils.StringToBytes(item.Name);
update.ItemData[items].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
update.ItemData[items].OwnerID = item.OwnerID;
update.ItemData[items].OwnerMask = (uint)item.Permissions.OwnerMask;
update.ItemData[items].SalePrice = item.SalePrice;
update.ItemData[items].SaleType = (byte)item.SaleType;
update.ItemData[items].Type = (sbyte)item.InventoryType;
++items;
}
else
{
InventoryFolder folder = (InventoryFolder)obj;
update.FolderData[folders] = new BulkUpdateInventoryPacket.FolderDataBlock();
update.FolderData[folders].FolderID = folder.ID;
update.FolderData[folders].Name = Utils.StringToBytes(folder.Name);
update.FolderData[folders].ParentID = folder.ParentID;
update.FolderData[folders].Type = (sbyte)folder.PreferredType;
++folders;
}
}
Logger.DebugLog("Sending bulk update for " + items + " items and " + folders + " folders");
scene.UDP.SendPacket(agent.ID, update, PacketCategory.Inventory);
}
}
}

View File

@@ -1,686 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Xml;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
namespace Simian
{
class HyperGridLink
{
public string RegionName;
public ulong RegionHandle;
public UUID RegionID;
public UUID RegionImage;
public int UDPPort;
public int RemotingPort;
}
public class LLMap : IExtension<ISceneProvider>
{
static readonly UUID WATER_TEXTURE = new UUID("af588c7c-52b0-4d9e-a888-1fe9d6c35f45");
static readonly UUID HYPERGRID_MAP_TEXTURE = new UUID("3f1f56ad-7811-42e6-b3c1-98b79fc5c360");
ISceneProvider scene;
public LLMap()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.MapLayerRequest, MapLayerRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.MapBlockRequest, MapBlockRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.MapItemRequest, MapItemRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.TeleportRequest, TeleportRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.TeleportLocationRequest, TeleportLocationRequestHandler);
return true;
}
public void Stop()
{
}
void MapLayerRequestHandler(Packet packet, Agent agent)
{
MapLayerRequestPacket request = (MapLayerRequestPacket)packet;
GridLayerType type = (GridLayerType)request.AgentData.Flags;
// FIXME: Do this properly. Use the grid service to get the aggregated map layers
// (lots of map tiles in a single texture == layer)
MapLayerReplyPacket reply = new MapLayerReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.AgentData.Flags = (uint)type;
reply.LayerData = new MapLayerReplyPacket.LayerDataBlock[1];
reply.LayerData[0] = new MapLayerReplyPacket.LayerDataBlock();
reply.LayerData[0].Bottom = 0;
reply.LayerData[0].Left = 0;
reply.LayerData[0].Top = UInt16.MaxValue;
reply.LayerData[0].Right = UInt16.MaxValue;
reply.LayerData[0].ImageID = WATER_TEXTURE;
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
void MapBlockRequestHandler(Packet packet, Agent agent)
{
MapBlockRequestPacket request = (MapBlockRequestPacket)packet;
bool returnNonexistent = (request.AgentData.Flags == 0x10000);
GridLayerType type = (GridLayerType)(request.AgentData.Flags &~0x10000);
IList<RegionInfo> regions = scene.Server.Grid.GetRegionsInArea(request.PositionData.MinX, request.PositionData.MinY,
request.PositionData.MaxX, request.PositionData.MaxY);
MapBlockReplyPacket reply = new MapBlockReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.AgentData.Flags = (uint)type;
MapBlockReplyPacket.DataBlock[] blocks;
if (returnNonexistent)
{
int blockCountX = request.PositionData.MaxX + 1 - request.PositionData.MinX;
int blockCountY = request.PositionData.MaxY + 1 - request.PositionData.MinY;
blocks = new MapBlockReplyPacket.DataBlock[blockCountX * blockCountY];
int i = 0;
for (int y = request.PositionData.MinY; y <= request.PositionData.MaxY; y++)
{
for (int x = request.PositionData.MinX; x <= request.PositionData.MaxX; x++)
{
blocks[i] = new MapBlockReplyPacket.DataBlock();
blocks[i].X = (ushort)x;
blocks[i].Y = (ushort)y;
// See if we have data for this region
RegionInfo? region = null;
for (int j = 0; j < regions.Count; j++)
{
if (regions[j].X == x && regions[j].Y == y)
{
region = regions[j];
break;
}
}
if (region.HasValue)
{
blocks[i].Access = (byte)SimAccess.Min;
blocks[i].Agents = (byte)region.Value.AgentCount;
blocks[i].MapImageID = region.Value.MapTextureID;
blocks[i].Name = Utils.StringToBytes(region.Value.Name);
blocks[i].RegionFlags = (uint)region.Value.Flags;
blocks[i].WaterHeight = (byte)region.Value.WaterHeight;
}
else
{
blocks[i].Name = Utils.EmptyBytes;
blocks[i].MapImageID = WATER_TEXTURE;
}
++i;
}
}
}
else
{
blocks = new MapBlockReplyPacket.DataBlock[regions.Count];
for (int i = 0; i < regions.Count; i++)
{
RegionInfo region = regions[i];
blocks[i] = new MapBlockReplyPacket.DataBlock();
blocks[i].X = (ushort)region.X;
blocks[i].Y = (ushort)region.Y;
blocks[i].Access = (byte)SimAccess.Min;
blocks[i].Agents = (byte)region.AgentCount;
blocks[i].MapImageID = region.MapTextureID;
blocks[i].Name = Utils.StringToBytes(region.Name);
blocks[i].RegionFlags = (uint)region.Flags;
blocks[i].WaterHeight = (byte)region.WaterHeight;
}
}
// FIXME: Handle large numbers of blocks by splitting things up
reply.Data = blocks;
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
void MapItemRequestHandler(Packet packet, Agent agent)
{
MapItemRequestPacket request = (MapItemRequestPacket)packet;
GridLayerType layerType = (GridLayerType)request.AgentData.Flags;
GridItemType itemType = (GridItemType)request.RequestData.ItemType;
uint regionX, regionY;
Utils.LongToUInts(request.RequestData.RegionHandle, out regionX, out regionY);
RegionInfo regionInfo;
if (scene.Server.Grid.TryGetRegion(regionX, regionY, scene.RegionCertificate, out regionInfo))
{
Logger.Log("MapItemRequest for " + itemType + " from layer " + layerType + " in " + regionInfo.Name, Helpers.LogLevel.Info);
MapItemReplyPacket reply = new MapItemReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.AgentData.Flags = request.AgentData.Flags;
reply.RequestData.ItemType = (uint)itemType;
reply.Data = new MapItemReplyPacket.DataBlock[0];
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
else
{
Logger.Log("MapItemRequest for " + itemType + " from layer " + layerType + " in unknown region at " + regionX + "," + regionY,
Helpers.LogLevel.Warning);
}
}
void TeleportRequestHandler(Packet packet, Agent agent)
{
TeleportRequestPacket request = (TeleportRequestPacket)packet;
// TODO: Stand the avatar up first
if (request.Info.RegionID == scene.RegionID)
{
// Local teleport
agent.Avatar.Prim.Position = request.Info.Position;
agent.CurrentLookAt = request.Info.LookAt;
// TODO: Actually adjust the agent's LookAt
TeleportLocalPacket reply = new TeleportLocalPacket();
reply.Info.AgentID = agent.ID;
reply.Info.LocationID = 0; // Unused by the client
reply.Info.LookAt = agent.CurrentLookAt;
reply.Info.Position = agent.Avatar.Prim.Position;
// TODO: Need a "Flying" boolean for Agent
reply.Info.TeleportFlags = (uint)TeleportFlags.ViaRegionID;
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
else
{
TeleportFailedPacket reply = new TeleportFailedPacket();
reply.Info.AgentID = agent.ID;
reply.Info.Reason = Utils.StringToBytes("Unknown region");
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
}
void TeleportLocationRequestHandler(Packet packet, Agent agent)
{
TeleportLocationRequestPacket request = (TeleportLocationRequestPacket)packet;
// TODO: Stand the avatar up first
if (request.Info.RegionHandle == scene.RegionHandle)
{
// Local teleport
agent.Avatar.Prim.Position = request.Info.Position;
agent.CurrentLookAt = request.Info.LookAt;
TeleportLocalPacket reply = new TeleportLocalPacket();
reply.Info.AgentID = agent.ID;
reply.Info.LocationID = 0; // Unused by the client
reply.Info.LookAt = agent.CurrentLookAt;
reply.Info.Position = agent.Avatar.Prim.Position;
// TODO: Need a "Flying" boolean for Agent
reply.Info.TeleportFlags = (uint)TeleportFlags.ViaLocation;
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
// FIXME: Add XML config support for HyperGrid destinations
/*else if (request.Info.RegionHandle == Utils.UIntsToLong((scene.RegionX + 1) * 256, scene.RegionY * 256))
{
// Special case: adjacent simulator is the HyperGrid portal
HyperGridTeleport(agent, new Uri("http://osl2.nac.uci.edu:9006/"), request.Info.Position);
}*/
else
{
TeleportFailedPacket reply = new TeleportFailedPacket();
reply.Info.AgentID = agent.ID;
reply.Info.Reason = Utils.StringToBytes("Unknown region");
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
}
bool HyperGridTeleport(Agent agent, Uri destination, Vector3 destPos)
{
HyperGridLink link;
TeleportProgress(agent, "Resolving destination IP address", TeleportFlags.ViaLocation);
IPHostEntry entry = Dns.GetHostEntry(destination.DnsSafeHost);
if (entry.AddressList != null && entry.AddressList.Length >= 1)
{
TeleportProgress(agent, "Retrieving destination details", TeleportFlags.ViaLocation);
if (LinkRegion(destination, out link))
{
TeleportProgress(agent, "Creating foreign agent", TeleportFlags.ViaLocation);
// This is a crufty part of the HyperGrid protocol. We need to generate a fragment of a UUID
// (missing the last four digits) and send that as the caps_path variable. Locally, we expand
// that out to http://foreignsim:httpport/CAPS/fragment0000/ and use it as the seed caps path
// that is sent to the client
UUID seedID = UUID.Random();
string seedCapFragment = seedID.ToString().Substring(0, 32);
Uri seedCap = new Uri(destination, "/CAPS/" + seedCapFragment + "0000/");
if (ExpectHyperGridUser(agent, destination, destPos, link, seedCap))
{
TeleportProgress(agent, "Establishing foreign agent presence", TeleportFlags.ViaLocation);
if (CreateChildAgent(agent, destination, destPos, link, seedCapFragment))
{
// Send the final teleport message to the client
if (scene.HasRunningEventQueue(agent))
{
uint x, y;
Utils.LongToUInts(link.RegionHandle, out x, out y);
x /= 256;
y /= 256;
Logger.Log(String.Format("HyperGrid teleporting to {0} ({1}, {2}) @ {3}",
link.RegionName, x, y, destination), Helpers.LogLevel.Info);
OSDMap info = new OSDMap();
info.Add("AgentID", OSD.FromUUID(agent.ID));
info.Add("LocationID", OSD.FromInteger(4)); // Unused by the client
info.Add("RegionHandle", OSD.FromULong(link.RegionHandle));
info.Add("SeedCapability", OSD.FromUri(seedCap));
info.Add("SimAccess", OSD.FromInteger((byte)SimAccess.Min));
info.Add("SimIP", OSD.FromBinary(entry.AddressList[0].GetAddressBytes()));
info.Add("SimPort", OSD.FromInteger(link.UDPPort));
info.Add("TeleportFlags", OSD.FromUInteger((uint)TeleportFlags.ViaLocation));
OSDArray infoArray = new OSDArray(1);
infoArray.Add(info);
OSDMap teleport = new OSDMap();
teleport.Add("Info", infoArray);
scene.SendEvent(agent, "TeleportFinish", teleport);
}
else
{
Logger.Log("No running EventQueue for " + agent.FullName + ", sending TeleportFinish over UDP",
Helpers.LogLevel.Warning);
TeleportFinishPacket teleport = new TeleportFinishPacket();
teleport.Info.AgentID = agent.ID;
teleport.Info.LocationID = 0; // Unused by the client
teleport.Info.RegionHandle = link.RegionHandle;
teleport.Info.SeedCapability = Utils.StringToBytes(seedCap.ToString());
teleport.Info.SimAccess = (byte)SimAccess.Min;
teleport.Info.SimIP = Utils.BytesToUInt(entry.AddressList[0].GetAddressBytes());
teleport.Info.SimPort = (ushort)link.UDPPort;
teleport.Info.TeleportFlags = (uint)TeleportFlags.ViaLocation;
scene.UDP.SendPacket(agent.ID, teleport, PacketCategory.Transaction);
}
// Remove the agent from the local scene (will also tear down the UDP connection)
//scene.ObjectRemove(this, agent.ID);
return true;
}
}
}
}
return false;
}
bool LinkRegion(Uri destination, out HyperGridLink link)
{
try
{
#region Build Request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "text/xml";
MemoryStream memoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(memoryStream))
{
writer.WriteStartElement("methodCall");
{
writer.WriteElementString("methodName", "link_region");
writer.WriteStartElement("params");
writer.WriteStartElement("param");
writer.WriteStartElement("value");
writer.WriteStartElement("struct");
{
WriteStringMember(writer, "region_name", String.Empty);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
}
request.ContentLength = memoryStream.Length;
using (Stream writeStream = request.GetRequestStream())
{
writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
#endregion Build Request
#region Parse Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
{
link = new HyperGridLink();
reader.ReadStartElement("methodResponse");
{
reader.ReadStartElement("params");
reader.ReadStartElement("param");
reader.ReadStartElement("value");
reader.ReadStartElement("struct");
{
while (reader.Name == "member")
{
reader.ReadStartElement("member");
{
string name = reader.ReadElementContentAsString("name", String.Empty);
reader.ReadStartElement("value");
{
switch (name)
{
case "region_name":
link.RegionName = reader.ReadElementContentAsString("string", String.Empty);
break;
case "handle":
string handle = reader.ReadElementContentAsString("string", String.Empty);
link.RegionHandle = UInt64.Parse(handle);
break;
case "uuid":
string uuid = reader.ReadElementContentAsString("string", String.Empty);
link.RegionID = UUID.Parse(uuid);
break;
case "internal_port":
link.UDPPort = reader.ReadElementContentAsInt("string", String.Empty);
break;
case "region_image":
string imageuuid = reader.ReadElementContentAsString("string", String.Empty);
link.RegionImage = UUID.Parse(imageuuid);
break;
case "remoting_port":
link.RemotingPort = reader.ReadElementContentAsInt("string", String.Empty);
break;
default:
Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
Helpers.LogLevel.Warning);
break;
}
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
}
reader.ReadEndElement();
return true;
}
#endregion Parse Response
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
link = null;
return false;
}
bool ExpectHyperGridUser(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link, Uri seedCap)
{
try
{
#region Build Request
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "text/xml";
MemoryStream memoryStream = new MemoryStream();
using (XmlWriter writer = XmlWriter.Create(memoryStream))
{
writer.WriteStartElement("methodCall");
{
writer.WriteElementString("methodName", "expect_hg_user");
writer.WriteStartElement("params");
writer.WriteStartElement("param");
writer.WriteStartElement("value");
writer.WriteStartElement("struct");
{
WriteStringMember(writer, "session_id", agent.SessionID.ToString());
WriteStringMember(writer, "secure_session_id", agent.SecureSessionID.ToString());
WriteStringMember(writer, "firstname", agent.Info.FirstName);
WriteStringMember(writer, "lastname", agent.Info.LastName);
WriteStringMember(writer, "agent_id", agent.ID.ToString());
WriteStringMember(writer, "circuit_code", agent.CircuitCode.ToString());
WriteStringMember(writer, "startpos_x", destPos.X.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "startpos_y", destPos.Y.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "startpos_z", destPos.Z.ToString(Utils.EnUsCulture));
WriteStringMember(writer, "caps_path", seedCap.ToString());
WriteStringMember(writer, "region_uuid", link.RegionID.ToString());
//WriteStringMember(writer, "userserver_id", "");
//WriteStringMember(writer, "assetserver_id", "");
//WriteStringMember(writer, "inventoryserver_id", "");
WriteStringMember(writer, "root_folder_id", agent.Info.InventoryRoot.ToString());
string port = scene.Server.HttpUri.Port.ToString();
WriteStringMember(writer, "internal_port", port);
WriteStringMember(writer, "regionhandle", scene.RegionHandle.ToString());
WriteStringMember(writer, "home_address", IPAddress.Loopback.ToString());
WriteStringMember(writer, "home_port", port);
WriteStringMember(writer, "home_remoting", port);
}
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.Flush();
}
request.ContentLength = memoryStream.Length;
using (Stream writeStream = request.GetRequestStream())
{
writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
#endregion Build Request
#region Parse Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreComments = true;
settings.IgnoreWhitespace = true;
using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
{
bool success = false;
string reason = String.Empty;
reader.ReadStartElement("methodResponse");
{
reader.ReadStartElement("params");
reader.ReadStartElement("param");
reader.ReadStartElement("value");
reader.ReadStartElement("struct");
{
while (reader.Name == "member")
{
reader.ReadStartElement("member");
{
string name = reader.ReadElementContentAsString("name", String.Empty);
reader.ReadStartElement("value");
{
switch (name)
{
case "success":
success = (reader.ReadElementContentAsString("string", String.Empty).ToUpper() == "TRUE");
break;
case "reason":
reason = reader.ReadElementContentAsString("string", String.Empty);
break;
default:
Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
Helpers.LogLevel.Warning);
break;
}
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
reader.ReadEndElement();
}
reader.ReadEndElement();
if (!success)
Logger.Log("[HyperGrid] Teleport failed, reason: " + reason, Helpers.LogLevel.Warning);
return success;
}
#endregion Parse Response
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
return false;
}
bool CreateChildAgent(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link, string seedCapFragment)
{
try
{
destination = new Uri(destination, "/agent/" + agent.ID.ToString() + "/");
OSDMap args = new OSDMap();
args["agent_id"] = OSD.FromUUID(agent.ID);
args["base_folder"] = OSD.FromUUID(UUID.Zero);
args["caps_path"] = OSD.FromString(seedCapFragment);
args["children_seeds"] = OSD.FromBoolean(false);
args["child"] = OSD.FromBoolean(false);
args["circuit_code"] = OSD.FromString(agent.CircuitCode.ToString());
args["first_name"] = OSD.FromString(agent.Info.FirstName);
args["last_name"] = OSD.FromString(agent.Info.LastName);
args["inventory_folder"] = OSD.FromUUID(agent.Info.InventoryRoot);
args["secure_session_id"] = OSD.FromUUID(agent.SecureSessionID);
args["session_id"] = OSD.FromUUID(agent.SessionID);
args["start_pos"] = OSD.FromString(destPos.ToString());
args["destination_handle"] = OSD.FromString(link.RegionHandle.ToString());
LitJson.JsonData jsonData = OSDParser.SerializeJson(args);
byte[] data = System.Text.Encoding.UTF8.GetBytes(jsonData.ToJson());
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = data.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(data, 0, data.Length);
requestStream.Flush();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
bool success = false;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
Boolean.TryParse(reader.ReadToEnd(), out success);
}
return success;
}
catch (Exception ex)
{
Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
}
return false;
}
void TeleportProgress(Agent agent, string message, TeleportFlags flags)
{
TeleportProgressPacket progress = new TeleportProgressPacket();
progress.AgentData.AgentID = agent.ID;
progress.Info.Message = Utils.StringToBytes(message);
progress.Info.TeleportFlags = (uint)flags;
scene.UDP.SendPacket(agent.ID, progress, PacketCategory.Transaction);
}
static void WriteStringMember(XmlWriter writer, string name, string value)
{
writer.WriteStartElement("member");
{
writer.WriteElementString("name", name);
writer.WriteStartElement("value");
{
writer.WriteElementString("string", value);
}
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
}

View File

@@ -1,146 +0,0 @@
using System;
using System.Collections.Generic;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class LLMessaging : IExtension<ISceneProvider>
{
ISceneProvider scene;
public LLMessaging()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.ChatFromViewer, ChatFromViewerHandler);
scene.UDP.RegisterPacketCallback(PacketType.ImprovedInstantMessage, ImprovedInstantMessageHandler);
return true;
}
public void Stop()
{
}
void ChatFromViewerHandler(Packet packet, Agent agent)
{
ChatFromViewerPacket viewerChat = (ChatFromViewerPacket)packet;
scene.ObjectChat(this, agent.ID, agent.ID, ChatAudibleLevel.Fully, (ChatType)viewerChat.ChatData.Type,
ChatSourceType.Agent, agent.FullName, agent.Avatar.GetSimulatorPosition(), viewerChat.ChatData.Channel,
Utils.BytesToString(viewerChat.ChatData.Message));
}
void ImprovedInstantMessageHandler(Packet packet, Agent agent)
{
ImprovedInstantMessagePacket im = (ImprovedInstantMessagePacket)packet;
InstantMessageDialog dialog = (InstantMessageDialog)im.MessageBlock.Dialog;
if (dialog == InstantMessageDialog.MessageFromAgent)
{
// HACK: Only works for agents currently online
Agent recipient;
if (scene.TryGetAgent(im.MessageBlock.ToAgentID, out recipient))
{
// FIXME: Look into the fields we are setting to default values
ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket();
sendIM.MessageBlock.RegionID = scene.RegionID;
sendIM.MessageBlock.ParentEstateID = 1;
sendIM.MessageBlock.FromGroup = false;
sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.FullName);
sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID;
sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog;
sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online;
sendIM.MessageBlock.ID = agent.ID;
sendIM.MessageBlock.Message = im.MessageBlock.Message;
sendIM.MessageBlock.BinaryBucket = Utils.EmptyBytes;
sendIM.MessageBlock.Timestamp = Utils.DateTimeToUnixTime(DateTime.Now);
sendIM.MessageBlock.Position = agent.Avatar.GetSimulatorPosition();
sendIM.AgentData.AgentID = agent.ID;
scene.UDP.SendPacket(recipient.ID, sendIM, PacketCategory.Messaging);
}
}
else if (dialog == InstantMessageDialog.FriendshipOffered ||
dialog == InstantMessageDialog.FriendshipAccepted ||
dialog == InstantMessageDialog.FriendshipDeclined)
{
// HACK: Only works for agents currently online
Agent recipient;
if (scene.TryGetAgent(im.MessageBlock.ToAgentID, out recipient))
{
ImprovedInstantMessagePacket sendIM = new ImprovedInstantMessagePacket();
sendIM.MessageBlock.RegionID = scene.RegionID;
sendIM.MessageBlock.ParentEstateID = 1;
sendIM.MessageBlock.FromGroup = false;
sendIM.MessageBlock.FromAgentName = Utils.StringToBytes(agent.FullName);
sendIM.MessageBlock.ToAgentID = im.MessageBlock.ToAgentID;
sendIM.MessageBlock.Dialog = im.MessageBlock.Dialog;
sendIM.MessageBlock.Offline = (byte)InstantMessageOnline.Online;
sendIM.MessageBlock.ID = agent.ID;
sendIM.MessageBlock.Message = im.MessageBlock.Message;
sendIM.MessageBlock.BinaryBucket = Utils.EmptyBytes;
sendIM.MessageBlock.Timestamp = 0;
sendIM.MessageBlock.Position = agent.Avatar.GetSimulatorPosition();
sendIM.AgentData.AgentID = agent.ID;
scene.UDP.SendPacket(recipient.ID, sendIM, PacketCategory.Transaction);
if (dialog == InstantMessageDialog.FriendshipAccepted)
{
bool receiverOnline = scene.ContainsObject(agent.ID);
bool senderOnline = scene.ContainsObject(recipient.ID);
if (receiverOnline)
{
if (senderOnline)
{
OnlineNotificationPacket notify = new OnlineNotificationPacket();
notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0];
notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock();
notify.AgentBlock[0].AgentID = agent.ID;
scene.UDP.SendPacket(recipient.ID, notify, PacketCategory.State);
}
else
{
OfflineNotificationPacket notify = new OfflineNotificationPacket();
notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0];
notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
notify.AgentBlock[0].AgentID = agent.ID;
scene.UDP.SendPacket(recipient.ID, notify, PacketCategory.State);
}
}
if (senderOnline)
{
if (receiverOnline)
{
OnlineNotificationPacket notify = new OnlineNotificationPacket();
notify.AgentBlock = new OnlineNotificationPacket.AgentBlockBlock[0];
notify.AgentBlock[0] = new OnlineNotificationPacket.AgentBlockBlock();
notify.AgentBlock[0].AgentID = recipient.ID;
scene.UDP.SendPacket(agent.ID, notify, PacketCategory.State);
}
else
{
OfflineNotificationPacket notify = new OfflineNotificationPacket();
notify.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[0];
notify.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
notify.AgentBlock[0].AgentID = recipient.ID;
scene.UDP.SendPacket(agent.ID, notify, PacketCategory.State);
}
}
}
}
}
}
}
}

View File

@@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class LLMoney : IExtension<ISceneProvider>
{
ISceneProvider scene;
public LLMoney()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.MoneyBalanceRequest, MoneyBalanceRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.MoneyTransferRequest, MoneyTransferRequestHandler);
return true;
}
public void Stop()
{
}
void SendBalance(Agent agent, UUID transactionID, string message)
{
MoneyBalanceReplyPacket reply = new MoneyBalanceReplyPacket();
reply.MoneyData.AgentID = agent.ID;
reply.MoneyData.MoneyBalance = agent.Info.Balance;
reply.MoneyData.TransactionID = transactionID;
reply.MoneyData.Description = Utils.StringToBytes(message);
scene.UDP.SendPacket(agent.ID, reply, PacketCategory.Transaction);
}
void MoneyBalanceRequestHandler(Packet packet, Agent agent)
{
MoneyBalanceRequestPacket request = (MoneyBalanceRequestPacket)packet;
SendBalance(agent, request.MoneyData.TransactionID, String.Empty);
}
void MoneyTransferRequestHandler(Packet packet, Agent agent)
{
MoneyTransferRequestPacket request = (MoneyTransferRequestPacket)packet;
if (request.MoneyData.Amount < 0 || request.MoneyData.Amount > agent.Info.Balance)
return;
// HACK: Only works for sending money to someone who is online
Agent recipient;
if (scene.TryGetAgent(request.MoneyData.DestID, out recipient))
{
agent.Info.Balance -= request.MoneyData.Amount;
recipient.Info.Balance += request.MoneyData.Amount;
SendBalance(agent, UUID.Zero, String.Format("You paid L${0} to {1}.", request.MoneyData.Amount, recipient.FullName));
SendBalance(agent, UUID.Zero, String.Format("{1} paid you L${0}.", request.MoneyData.Amount, agent.FullName));
}
}
}
}

View File

@@ -1,518 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Rendering;
namespace Simian
{
public class Movement : IExtension<ISceneProvider>
{
const int UPDATE_ITERATION = 100; //rate in milliseconds to send ObjectUpdate
const bool ENVIRONMENT_SOUNDS = true; //collision sounds, splashing, etc
const float GRAVITY = 9.8f; //meters/sec
const float WALK_SPEED = 3f; //meters/sec
const float RUN_SPEED = 5f; //meters/sec
const float FLY_SPEED = 10f; //meters/sec
const float FALL_DELAY = 0.33f; //seconds before starting animation
const float FALL_FORGIVENESS = .25f; //fall buffer in meters
const float JUMP_IMPULSE_VERTICAL = 8.5f; //boost amount in meters/sec
const float JUMP_IMPULSE_HORIZONTAL = 10f; //boost amount in meters/sec
const float INITIAL_HOVER_IMPULSE = 2f; //boost amount in meters/sec
const float PREJUMP_DELAY = 0.25f; //seconds before actually jumping
const float AVATAR_TERMINAL_VELOCITY = 54f; //~120mph
static readonly UUID BIG_SPLASH_SOUND = new UUID("486475b9-1460-4969-871e-fad973b38015");
static readonly Vector3 SEATING_FUDGE = new Vector3(0.3f, 0.0f, 0.0f);
const float SQRT_TWO = 1.41421356f;
ISceneProvider scene;
Timer updateTimer;
long lastTick;
public int LastTick
{
get { return (int) Interlocked.Read(ref lastTick); }
set { Interlocked.Exchange(ref lastTick, value); }
}
public Movement()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.OnObjectAddOrUpdate += Scene_OnObjectAddOrUpdate;
scene.UDP.RegisterPacketCallback(PacketType.AgentRequestSit, AgentRequestSitHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentSit, AgentSitHandler);
scene.UDP.RegisterPacketCallback(PacketType.AgentUpdate, AgentUpdateHandler);
scene.UDP.RegisterPacketCallback(PacketType.SetAlwaysRun, SetAlwaysRunHandler);
updateTimer = new Timer(new TimerCallback(UpdateTimer_Elapsed));
LastTick = Environment.TickCount;
updateTimer.Change(UPDATE_ITERATION, UPDATE_ITERATION);
return true;
}
public void Stop()
{
if (updateTimer != null)
{
updateTimer.Dispose();
updateTimer = null;
}
}
void Scene_OnObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags update)
{
bool forceMeshing = false;
bool forceTransform = false;
if ((update & UpdateFlags.Scale) != 0 ||
(update & UpdateFlags.Position) != 0 ||
(update & UpdateFlags.Rotation) != 0)
{
forceTransform = true;
}
if ((update & UpdateFlags.PrimData) != 0)
{
forceMeshing = true;
}
// TODO: This doesn't update children prims when their parents move
obj.GetWorldMesh(DetailLevel.Low, forceMeshing, forceTransform);
}
void UpdateTimer_Elapsed(object sender)
{
int tick = Environment.TickCount;
float seconds = (float)((tick - LastTick) / 1000f);
LastTick = tick;
scene.ForEachAgent(
delegate(Agent agent)
{
if ((agent.Avatar.Prim.Flags & PrimFlags.Physics) == 0)
return;
bool animsChanged = false;
// Create forward and left vectors from the current avatar rotation
Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(agent.Avatar.Prim.Rotation);
Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix);
Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix);
// Check control flags
bool heldForward = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
bool heldBack = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG;
bool heldLeft = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS;
bool heldRight = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG;
//bool heldTurnLeft = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT;
//bool heldTurnRight = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT;
bool heldUp = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS;
bool heldDown = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG;
bool flying = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY;
//bool mouselook = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) == AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK;
// direction in which the avatar is trying to move
Vector3 move = Vector3.Zero;
if (heldForward) { move.X += fwd.X; move.Y += fwd.Y; }
if (heldBack) { move.X -= fwd.X; move.Y -= fwd.Y; }
if (heldLeft) { move.X += left.X; move.Y += left.Y; }
if (heldRight) { move.X -= left.X; move.Y -= left.Y; }
if (heldUp) { move.Z += 1; }
if (heldDown) { move.Z -= 1; }
// is the avatar trying to move?
bool moving = move != Vector3.Zero;
bool jumping = agent.TickJump != 0;
// 2-dimensional speed multipler
float speed = seconds * (flying ? FLY_SPEED : agent.Running && !jumping ? RUN_SPEED : WALK_SPEED);
if ((heldForward || heldBack) && (heldLeft || heldRight))
speed /= SQRT_TWO;
Vector3 agentPosition = agent.Avatar.GetSimulatorPosition();
float oldFloor = scene.GetTerrainHeightAt(agentPosition.X, agentPosition.Y);
agentPosition += (move * speed);
float newFloor = scene.GetTerrainHeightAt(agentPosition.X, agentPosition.Y);
if (!flying && newFloor != oldFloor)
speed /= (1 + (SQRT_TWO * Math.Abs(newFloor - oldFloor)));
//HACK: distance from avatar center to the bottom of its feet
float distanceFromFloor = agent.Avatar.Prim.Scale.Z * .5f;
float lowerLimit = newFloor + distanceFromFloor;
//"bridge" physics
if (agent.Avatar.Prim.Velocity != Vector3.Zero)
{
//start ray at our feet
Vector3 rayStart = new Vector3(
agent.Avatar.Prim.Position.X,
agent.Avatar.Prim.Position.Y,
agent.Avatar.Prim.Position.Z - distanceFromFloor
);
//end ray at 0.01m below our feet
Vector3 rayEnd = new Vector3(
rayStart.X,
rayStart.Y,
rayStart.Z - 0.01f
);
scene.ForEachObject(delegate(SimulationObject obj)
{
//HACK: check nearby objects (what did you expect, octree?)
if (Vector3.Distance(rayStart, obj.Prim.Position) <= 15f)
{
Vector3 collision = scene.Physics.ObjectCollisionTest(rayStart, rayEnd, obj);
if (collision != rayEnd) //we collided!
{
//check if we are any higher than before
float height = collision.Z + distanceFromFloor;
if (height > lowerLimit) lowerLimit = height;
}
}
});
}
// Z acceleration resulting from gravity
float gravity = 0f;
float waterChestHeight = scene.WaterHeight - (agent.Avatar.Prim.Scale.Z * .33f);
if (flying)
{
agent.TickFall = 0;
agent.TickJump = 0;
//velocity falloff while flying
agent.Avatar.Prim.Velocity.X *= 0.66f;
agent.Avatar.Prim.Velocity.Y *= 0.66f;
agent.Avatar.Prim.Velocity.Z *= 0.33f;
if (agent.Avatar.Prim.Position.Z == lowerLimit)
agent.Avatar.Prim.Velocity.Z += INITIAL_HOVER_IMPULSE;
if (move.X != 0 || move.Y != 0)
{ //flying horizontally
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FLY))
animsChanged = true;
}
else if (move.Z > 0)
{ //flying straight up
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_UP))
animsChanged = true;
}
else if (move.Z < 0)
{ //flying straight down
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_DOWN))
animsChanged = true;
}
else
{ //hovering in the air
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER))
animsChanged = true;
}
}
else if (agent.Avatar.Prim.Position.Z > lowerLimit + FALL_FORGIVENESS || agent.Avatar.Prim.Position.Z <= waterChestHeight)
{ //falling, floating, or landing from a jump
if (agent.Avatar.Prim.Position.Z > scene.WaterHeight)
{ //above water
//override controls while drifting
move = Vector3.Zero;
//keep most of our horizontal inertia
agent.Avatar.Prim.Velocity.X *= 0.975f;
agent.Avatar.Prim.Velocity.Y *= 0.975f;
float fallElapsed = (float)(Environment.TickCount - agent.TickFall) / 1000f;
if (agent.TickFall == 0 || (fallElapsed > FALL_DELAY && agent.Avatar.Prim.Velocity.Z >= 0f))
{ //just started falling
agent.TickFall = Environment.TickCount;
}
else
{
gravity = GRAVITY * fallElapsed * seconds; //normal gravity
if (!jumping)
{ //falling
if (fallElapsed > FALL_DELAY)
{ //falling long enough to trigger the animation
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FALLDOWN))
animsChanged = true;
}
}
}
}
else if (agent.Avatar.Prim.Position.Z >= waterChestHeight)
{ //at the water line
gravity = 0f;
agent.Avatar.Prim.Velocity *= 0.5f;
agent.Avatar.Prim.Velocity.Z = 0f;
if (move.Z < 1) agent.Avatar.Prim.Position.Z = waterChestHeight;
if (move.Z > 0)
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_UP))
animsChanged = true;
}
else if (move.X != 0 || move.Y != 0)
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FLYSLOW))
animsChanged = true;
}
else
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER))
animsChanged = true;
}
}
else
{ //underwater
gravity = 0f; //buoyant
agent.Avatar.Prim.Velocity *= 0.5f * seconds;
agent.Avatar.Prim.Velocity.Z += 0.75f * seconds;
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FALLDOWN))
animsChanged = true;
}
}
else
{ //on the ground
agent.TickFall = 0;
//friction
agent.Avatar.Prim.Acceleration *= 0.2f;
agent.Avatar.Prim.Velocity *= 0.2f;
agent.Avatar.Prim.Position.Z = lowerLimit;
if (move.Z > 0)
{ //jumping
if (!jumping)
{ //begin prejump
move.Z = 0; //override Z control
if (scene.Avatars.SetDefaultAnimation(agent, Animations.PRE_JUMP))
animsChanged = true;
agent.TickJump = Environment.TickCount;
}
else if (Environment.TickCount - agent.TickJump > PREJUMP_DELAY * 1000)
{ //start actual jump
if (agent.TickJump == -1)
{
//already jumping! end current jump
agent.TickJump = 0;
return;
}
if (scene.Avatars.SetDefaultAnimation(agent, Animations.JUMP))
animsChanged = true;
agent.Avatar.Prim.Velocity.X += agent.Avatar.Prim.Acceleration.X * JUMP_IMPULSE_HORIZONTAL;
agent.Avatar.Prim.Velocity.Y += agent.Avatar.Prim.Acceleration.Y * JUMP_IMPULSE_HORIZONTAL;
agent.Avatar.Prim.Velocity.Z = JUMP_IMPULSE_VERTICAL * seconds;
agent.TickJump = -1; //flag that we are currently jumping
}
else move.Z = 0; //override Z control
}
else
{ //not jumping
agent.TickJump = 0;
if (move.X != 0 || move.Y != 0)
{ //not walking
if (move.Z < 0)
{ //crouchwalking
if (scene.Avatars.SetDefaultAnimation(agent, Animations.CROUCHWALK))
animsChanged = true;
}
else if (agent.Running)
{ //running
if (scene.Avatars.SetDefaultAnimation(agent, Animations.RUN))
animsChanged = true;
}
else
{ //walking
if (scene.Avatars.SetDefaultAnimation(agent, Animations.WALK))
animsChanged = true;
}
}
else
{ //walking
if (move.Z < 0)
{ //crouching
if (scene.Avatars.SetDefaultAnimation(agent, Animations.CROUCH))
animsChanged = true;
}
else
{ //standing
if (scene.Avatars.SetDefaultAnimation(agent, Animations.STAND))
animsChanged = true;
}
}
}
}
if (animsChanged)
scene.Avatars.SendAnimations(agent);
float maxVel = AVATAR_TERMINAL_VELOCITY * seconds;
// static acceleration when any control is held, otherwise none
if (moving)
{
agent.Avatar.Prim.Acceleration = move * speed;
if (agent.Avatar.Prim.Acceleration.Z < -maxVel)
agent.Avatar.Prim.Acceleration.Z = -maxVel;
else if (agent.Avatar.Prim.Acceleration.Z > maxVel)
agent.Avatar.Prim.Acceleration.Z = maxVel;
}
else agent.Avatar.Prim.Acceleration = Vector3.Zero;
agent.Avatar.Prim.Velocity += agent.Avatar.Prim.Acceleration - new Vector3(0f, 0f, gravity);
if (agent.Avatar.Prim.Velocity.Z < -maxVel)
agent.Avatar.Prim.Velocity.Z = -maxVel;
else if (agent.Avatar.Prim.Velocity.Z > maxVel)
agent.Avatar.Prim.Velocity.Z = maxVel;
agent.Avatar.Prim.Position += agent.Avatar.Prim.Velocity;
if (agent.Avatar.Prim.Position.X < 0) agent.Avatar.Prim.Position.X = 0f;
else if (agent.Avatar.Prim.Position.X > 255) agent.Avatar.Prim.Position.X = 255f;
if (agent.Avatar.Prim.Position.Y < 0) agent.Avatar.Prim.Position.Y = 0f;
else if (agent.Avatar.Prim.Position.Y > 255) agent.Avatar.Prim.Position.Y = 255f;
if (agent.Avatar.Prim.Position.Z < lowerLimit) agent.Avatar.Prim.Position.Z = lowerLimit;
}
);
}
void AgentRequestSitHandler(Packet packet, Agent agent)
{
AgentRequestSitPacket request = (AgentRequestSitPacket)packet;
SimulationObject obj;
if (scene.TryGetObject(request.TargetObject.TargetID, out obj))
{
agent.RequestedSitTarget = request.TargetObject.TargetID;
agent.RequestedSitOffset = request.TargetObject.Offset;
AvatarSitResponsePacket response = new AvatarSitResponsePacket();
response.SitObject.ID = request.TargetObject.TargetID;
response.SitTransform.AutoPilot = true;
response.SitTransform.CameraAtOffset = Vector3.Zero;
response.SitTransform.CameraEyeOffset = Vector3.Zero;
response.SitTransform.ForceMouselook = false;
response.SitTransform.SitPosition = request.TargetObject.Offset;
response.SitTransform.SitRotation = obj.SitRotation;
scene.UDP.SendPacket(agent.ID, response, PacketCategory.State);
}
else
{
//TODO: send error
}
}
void AgentSitHandler(Packet packet, Agent agent)
{
AgentSitPacket sit = (AgentSitPacket)packet;
if (agent.RequestedSitTarget != UUID.Zero)
{
SimulationObject obj;
SimulationObject avObj;
if (scene.TryGetObject(agent.RequestedSitTarget, out obj) && scene.TryGetObject(agent.ID, out avObj))
{
agent.Avatar.Prim.Flags &= ~PrimFlags.Physics;
agent.Avatar.Prim.ParentID = obj.Prim.LocalID;
agent.Avatar.Prim.Position = new Vector3(
obj.Prim.Scale.X * 0.5f,
obj.Prim.Scale.Z * 0.5f,
agent.Avatar.Prim.Scale.Z * 0.33f);
scene.ObjectAddOrUpdate(this, avObj, avObj.Prim.OwnerID, 0, PrimFlags.None,
UpdateFlags.PrimFlags | UpdateFlags.ParentID | UpdateFlags.Position);
scene.Avatars.SetDefaultAnimation(agent, Animations.SIT);
scene.Avatars.SendAnimations(agent);
}
else
{
//TODO: send error
}
agent.RequestedSitTarget = UUID.Zero;
agent.RequestedSitOffset = Vector3.Zero;
}
}
void AgentUpdateHandler(Packet packet, Agent agent)
{
AgentUpdatePacket update = (AgentUpdatePacket)packet;
SimulationObject obj;
if (scene.TryGetObject(agent.ID, out obj))
{
if (agent.Avatar.Prim.ParentID == 0)
agent.Avatar.Prim.Rotation = update.AgentData.BodyRotation;
agent.ControlFlags = (AgentManager.ControlFlags)update.AgentData.ControlFlags;
agent.State = (AgentState)update.AgentData.State;
agent.HideTitle = update.AgentData.Flags != 0;
// Check for standing up
SimulationObject parent;
if (scene.TryGetObject(agent.Avatar.Prim.ParentID, out parent) &&
agent.Avatar.Prim.ParentID > 0 &&
(agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) == AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP)
{
agent.Avatar.Prim.Position = parent.Prim.Position
+ Vector3.Transform(parent.SitPosition, Matrix4.CreateFromQuaternion(parent.SitRotation))
+ Vector3.UnitZ;
agent.Avatar.Prim.ParentID = 0;
scene.Avatars.SetDefaultAnimation(agent, Animations.STAND);
scene.Avatars.SendAnimations(agent);
agent.Avatar.Prim.Flags |= PrimFlags.Physics;
}
scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.Position | UpdateFlags.Rotation);
}
}
void SetAlwaysRunHandler(Packet packet, Agent agent)
{
SetAlwaysRunPacket run = (SetAlwaysRunPacket)packet;
agent.Running = run.AgentData.AlwaysRun;
}
}
}

View File

@@ -1,685 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Rendering;
using OpenMetaverse.Packets;
namespace Simian
{
public class ObjectManager : IExtension<ISceneProvider>
{
ISceneProvider scene;
public ObjectManager()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.ObjectAdd, ObjectAddHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectAttach, ObjectAttachHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectDuplicate, ObjectDuplicateHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectSelect, ObjectSelectHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectDeselect, ObjectDeselectHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectLink, ObjectLinkHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectDelink, ObjectDelinkHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectShape, ObjectShapeHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectFlagUpdate, ObjectFlagUpdateHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectExtraParams, ObjectExtraParamsHandler);
scene.UDP.RegisterPacketCallback(PacketType.ObjectImage, ObjectImageHandler);
scene.UDP.RegisterPacketCallback(PacketType.Undo, UndoHandler);
scene.UDP.RegisterPacketCallback(PacketType.Redo, RedoHandler);
scene.UDP.RegisterPacketCallback(PacketType.MultipleObjectUpdate, MultipleObjectUpdateHandler);
scene.UDP.RegisterPacketCallback(PacketType.RequestObjectPropertiesFamily, RequestObjectPropertiesFamilyHandler);
return true;
}
public void Stop()
{
}
void ObjectAddHandler(Packet packet, Agent agent)
{
ObjectAddPacket add = (ObjectAddPacket)packet;
Vector3 position = Vector3.Zero;
Vector3 scale = add.ObjectData.Scale;
PCode pcode = (PCode)add.ObjectData.PCode;
PrimFlags flags = (PrimFlags)add.ObjectData.AddFlags;
//bool bypassRaycast = (add.ObjectData.BypassRaycast == 1);
bool rayEndIsIntersection = (add.ObjectData.RayEndIsIntersection == 1);
#region Position Calculation
if (rayEndIsIntersection)
{
// HACK: Blindly trust where the client tells us to place
position = add.ObjectData.RayEnd;
}
else
{
if (add.ObjectData.RayTargetID != UUID.Zero)
{
SimulationObject obj;
if (scene.TryGetObject(add.ObjectData.RayTargetID, out obj))
{
// Test for a collision with the specified object
position = scene.Physics.ObjectCollisionTest(add.ObjectData.RayStart, add.ObjectData.RayEnd, obj);
}
}
if (position == Vector3.Zero)
{
// Test for a collision with the entire scene
position = FullSceneCollisionTest(add.ObjectData.RayStart, add.ObjectData.RayEnd);
}
}
// Position lies on the face of another surface, either terrain of an object.
// Back up along the ray so we are not colliding with the mesh.
// HACK: This is really cheesy and should be done by a collision system
Vector3 rayDir = Vector3.Normalize(add.ObjectData.RayEnd - add.ObjectData.RayStart);
position -= rayDir * scale;
#endregion Position Calculation
#region Foliage Handling
// Set all foliage to phantom
if (pcode == PCode.Grass || pcode == PCode.Tree || pcode == PCode.NewTree)
{
flags |= PrimFlags.Phantom;
if (pcode != PCode.Grass)
{
// Resize based on the foliage type
Tree tree = (Tree)add.ObjectData.State;
switch (tree)
{
case Tree.Cypress1:
case Tree.Cypress2:
scale = new Vector3(4f, 4f, 10f);
break;
default:
scale = new Vector3(4f, 4f, 4f);
break;
}
}
}
#endregion Foliage Handling
// Create an object
Primitive prim = new Primitive();
// TODO: Security check
prim.GroupID = add.AgentData.GroupID;
prim.ID = UUID.Random();
prim.MediaURL = String.Empty;
prim.OwnerID = agent.ID;
prim.Position = position;
prim.PrimData.Material = (Material)add.ObjectData.Material;
prim.PrimData.PathCurve = (PathCurve)add.ObjectData.PathCurve;
prim.PrimData.ProfileCurve = (ProfileCurve)add.ObjectData.ProfileCurve;
prim.PrimData.PathBegin = Primitive.UnpackBeginCut(add.ObjectData.PathBegin);
prim.PrimData.PathEnd = Primitive.UnpackEndCut(add.ObjectData.PathEnd);
prim.PrimData.PathScaleX = Primitive.UnpackPathScale(add.ObjectData.PathScaleX);
prim.PrimData.PathScaleY = Primitive.UnpackPathScale(add.ObjectData.PathScaleY);
prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)add.ObjectData.PathShearX);
prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)add.ObjectData.PathShearY);
prim.PrimData.PathTwist = Primitive.UnpackPathTwist(add.ObjectData.PathTwist);
prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist(add.ObjectData.PathTwistBegin);
prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist(add.ObjectData.PathRadiusOffset);
prim.PrimData.PathTaperX = Primitive.UnpackPathTaper(add.ObjectData.PathTaperX);
prim.PrimData.PathTaperY = Primitive.UnpackPathTaper(add.ObjectData.PathTaperY);
prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(add.ObjectData.PathRevolutions);
prim.PrimData.PathSkew = Primitive.UnpackPathTwist(add.ObjectData.PathSkew);
prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(add.ObjectData.ProfileBegin);
prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(add.ObjectData.ProfileEnd);
prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(add.ObjectData.ProfileHollow);
prim.PrimData.PCode = pcode;
prim.Properties = new Primitive.ObjectProperties();
prim.Properties.CreationDate = DateTime.Now;
prim.Properties.CreatorID = agent.ID;
prim.Properties.Description = String.Empty;
prim.Properties.GroupID = add.AgentData.GroupID;
prim.Properties.LastOwnerID = agent.ID;
prim.Properties.Name = "New Object";
prim.Properties.ObjectID = prim.ID;
prim.Properties.OwnerID = prim.OwnerID;
prim.Properties.Permissions = scene.Server.Permissions.GetDefaultPermissions();
prim.Properties.SalePrice = 10;
prim.RegionHandle = scene.RegionHandle;
prim.Rotation = add.ObjectData.Rotation;
prim.Scale = scale;
prim.TextColor = Color4.Black;
// Add this prim to the object database
SimulationObject simObj = new SimulationObject(prim, scene);
scene.ObjectAddOrUpdate(this, simObj, agent.ID, 0, flags, UpdateFlags.FullUpdate);
}
void ObjectAttachHandler(Packet packet, Agent agent)
{
ObjectAttachPacket attach = (ObjectAttachPacket)packet;
for (int i = 0; i < attach.ObjectData.Length; i++)
{
SimulationObject obj;
if (scene.TryGetObject(attach.ObjectData[i].ObjectLocalID, out obj))
{
obj.BeforeAttachmentRotation = attach.ObjectData[i].Rotation;
obj.Prim.ParentID = agent.Avatar.Prim.LocalID;
obj.Prim.Position = obj.AttachmentPosition;
obj.Prim.Rotation = obj.AttachmentRotation;
AttachmentPoint point = (AttachmentPoint)attach.AgentData.AttachmentPoint;
obj.Prim.PrimData.AttachmentPoint = (point == AttachmentPoint.Default ? obj.LastAttachmentPoint : point);
// Send an update out to everyone
scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, obj.Prim.Flags,
UpdateFlags.ParentID | UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.AttachmentPoint);
}
}
}
void ObjectDuplicateHandler(Packet packet, Agent agent)
{
ObjectDuplicatePacket duplicate = (ObjectDuplicatePacket)packet;
PrimFlags flags = (PrimFlags)duplicate.SharedData.DuplicateFlags;
Vector3 offset = duplicate.SharedData.Offset;
for (int i = 0; i < duplicate.ObjectData.Length; i++)
{
uint dupeID = duplicate.ObjectData[i].ObjectLocalID;
SimulationObject obj;
if (scene.TryGetObject(dupeID, out obj))
{
SimulationObject newObj = new SimulationObject(obj);
newObj.Prim.Position += offset;
newObj.Prim.ID = UUID.Zero;
newObj.Prim.LocalID = 0;
newObj.Prim.Properties.CreationDate = DateTime.Now;
scene.ObjectAddOrUpdate(this, newObj, agent.ID, 0, flags, UpdateFlags.FullUpdate);
}
else
{
Logger.Log("ObjectDuplicate sent for missing object " + dupeID,
Helpers.LogLevel.Warning);
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = dupeID;
scene.UDP.SendPacket(agent.ID, kill, PacketCategory.State);
}
}
}
void ObjectSelectHandler(Packet packet, Agent agent)
{
ObjectSelectPacket select = (ObjectSelectPacket)packet;
for (int i = 0; i < select.ObjectData.Length; i++)
{
ObjectPropertiesPacket properties = new ObjectPropertiesPacket();
properties.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[1];
properties.ObjectData[0] = new ObjectPropertiesPacket.ObjectDataBlock();
SimulationObject obj;
if (scene.TryGetObject(select.ObjectData[i].ObjectLocalID, out obj))
{
//Logger.DebugLog("Selecting object " + obj.Prim.LocalID);
properties.ObjectData[0].BaseMask = (uint)obj.Prim.Properties.Permissions.BaseMask;
properties.ObjectData[0].CreationDate = Utils.DateTimeToUnixTime(obj.Prim.Properties.CreationDate);
properties.ObjectData[0].CreatorID = obj.Prim.Properties.CreatorID;
properties.ObjectData[0].Description = Utils.StringToBytes(obj.Prim.Properties.Description);
properties.ObjectData[0].EveryoneMask = (uint)obj.Prim.Properties.Permissions.EveryoneMask;
properties.ObjectData[0].GroupID = obj.Prim.Properties.GroupID;
properties.ObjectData[0].GroupMask = (uint)obj.Prim.Properties.Permissions.GroupMask;
properties.ObjectData[0].LastOwnerID = obj.Prim.Properties.LastOwnerID;
properties.ObjectData[0].Name = Utils.StringToBytes(obj.Prim.Properties.Name);
properties.ObjectData[0].NextOwnerMask = (uint)obj.Prim.Properties.Permissions.NextOwnerMask;
properties.ObjectData[0].ObjectID = obj.Prim.ID;
properties.ObjectData[0].OwnerID = obj.Prim.Properties.OwnerID;
properties.ObjectData[0].OwnerMask = (uint)obj.Prim.Properties.Permissions.OwnerMask;
properties.ObjectData[0].OwnershipCost = obj.Prim.Properties.OwnershipCost;
properties.ObjectData[0].SalePrice = obj.Prim.Properties.SalePrice;
properties.ObjectData[0].SaleType = (byte)obj.Prim.Properties.SaleType;
properties.ObjectData[0].SitName = Utils.StringToBytes(obj.Prim.Properties.SitName);
properties.ObjectData[0].TextureID = Utils.EmptyBytes; // FIXME: What is this?
properties.ObjectData[0].TouchName = Utils.StringToBytes(obj.Prim.Properties.TouchName);
scene.UDP.SendPacket(agent.ID, properties, PacketCategory.Transaction);
}
else
{
Logger.Log("ObjectSelect sent for missing object " + select.ObjectData[i].ObjectLocalID,
Helpers.LogLevel.Warning);
properties.ObjectData[0].Description = Utils.EmptyBytes;
properties.ObjectData[0].Name = Utils.EmptyBytes;
properties.ObjectData[0].SitName = Utils.EmptyBytes;
properties.ObjectData[0].TextureID = Utils.EmptyBytes;
properties.ObjectData[0].TouchName = Utils.EmptyBytes;
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = select.ObjectData[i].ObjectLocalID;
scene.UDP.SendPacket(agent.ID, kill, PacketCategory.State);
}
}
}
void ObjectDeselectHandler(Packet packet, Agent agent)
{
ObjectDeselectPacket deselect = (ObjectDeselectPacket)packet;
for (int i = 0; i < deselect.ObjectData.Length; i++)
{
uint localID = deselect.ObjectData[i].ObjectLocalID;
SimulationObject obj;
if (scene.TryGetObject(localID, out obj))
{
//Logger.DebugLog("Deselecting object " + obj.Prim.LocalID);
}
}
// TODO: Do we need this at all?
}
void ObjectLinkHandler(Packet packet, Agent agent)
{
ObjectLinkPacket link = (ObjectLinkPacket)packet;
List<SimulationObject> linkSet = new List<SimulationObject>();
for (int i = 0; i < link.ObjectData.Length; i++)
{
SimulationObject obj;
if (!scene.TryGetObject(link.ObjectData[i].ObjectLocalID, out obj))
{
//TODO: Send an error message
return;
}
else if (obj.Prim.OwnerID != agent.ID)
{
//TODO: Do a full permissions check
return;
}
else
{
linkSet.Add(obj);
}
}
for (int i = 0; i < linkSet.Count; i++)
{
linkSet[i].LinkNumber = i + 1;
if (linkSet[i].Prim.ParentID > 0)
{
// Previously linked children
SimulationObject parent;
if (scene.TryGetObject(linkSet[i].Prim.ParentID, out parent))
{
// Re-add old root orientation
linkSet[i].Prim.Position = parent.Prim.Position + Vector3.Transform(linkSet[i].Prim.Position,
Matrix4.CreateFromQuaternion(parent.Prim.Rotation));
linkSet[i].Prim.Rotation *= parent.Prim.Rotation;
}
}
if (i > 0)
{
// Subtract root prim orientation
linkSet[i].Prim.Position = Vector3.Transform(linkSet[i].Prim.Position - linkSet[0].Prim.Position,
Matrix4.CreateFromQuaternion(Quaternion.Identity / linkSet[0].Prim.Rotation));
linkSet[i].Prim.Rotation /= linkSet[0].Prim.Rotation;
// Set parent ID
linkSet[i].Prim.ParentID = linkSet[0].Prim.LocalID;
}
else
{
// Root prim
linkSet[i].Prim.ParentID = 0;
}
scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags,
UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.ParentID);
}
}
void ObjectDelinkHandler(Packet packet, Agent agent)
{
ObjectDelinkPacket delink = (ObjectDelinkPacket)packet;
List<SimulationObject> linkSet = new List<SimulationObject>();
for (int i = 0; i < delink.ObjectData.Length; i++)
{
SimulationObject obj;
if (!scene.TryGetObject(delink.ObjectData[i].ObjectLocalID, out obj))
{
//TODO: Send an error message
return;
}
else if (obj.Prim.OwnerID != agent.ID)
{
//TODO: Do a full permissions check
return;
}
else
{
linkSet.Add(obj);
}
}
for (int i = 0; i < linkSet.Count; i++)
{
linkSet[i].Prim.ParentID = 0;
linkSet[i].LinkNumber = 0;
// Add root prim orientation to child prims
if (i > 0)
{
linkSet[i].Prim.Position = linkSet[0].Prim.Position + Vector3.Transform(linkSet[i].Prim.Position,
Matrix4.CreateFromQuaternion(linkSet[0].Prim.Rotation));
linkSet[i].Prim.Rotation *= linkSet[0].Prim.Rotation;
}
scene.ObjectAddOrUpdate(this, linkSet[i], agent.ID, 0, linkSet[i].Prim.Flags,
UpdateFlags.Position | UpdateFlags.Rotation | UpdateFlags.ParentID);
}
}
void ObjectShapeHandler(Packet packet, Agent agent)
{
ObjectShapePacket shape = (ObjectShapePacket)packet;
for (int i = 0; i < shape.ObjectData.Length; i++)
{
ObjectShapePacket.ObjectDataBlock block = shape.ObjectData[i];
SimulationObject obj;
if (scene.TryGetObject(block.ObjectLocalID, out obj))
{
Primitive.ConstructionData data = obj.Prim.PrimData;
data.PathBegin = Primitive.UnpackBeginCut(block.PathBegin);
data.PathCurve = (PathCurve)block.PathCurve;
data.PathEnd = Primitive.UnpackEndCut(block.PathEnd);
data.PathRadiusOffset = Primitive.UnpackPathTwist(block.PathRadiusOffset);
data.PathRevolutions = Primitive.UnpackPathRevolutions(block.PathRevolutions);
data.PathScaleX = Primitive.UnpackPathScale(block.PathScaleX);
data.PathScaleY = Primitive.UnpackPathScale(block.PathScaleY);
data.PathShearX = Primitive.UnpackPathShear((sbyte)block.PathShearX);
data.PathShearY = Primitive.UnpackPathShear((sbyte)block.PathShearY);
data.PathSkew = Primitive.UnpackPathTwist(block.PathSkew);
data.PathTaperX = Primitive.UnpackPathTaper(block.PathTaperX);
data.PathTaperY = Primitive.UnpackPathTaper(block.PathTaperY);
data.PathTwist = Primitive.UnpackPathTwist(block.PathTwist);
data.PathTwistBegin = Primitive.UnpackPathTwist(block.PathTwistBegin);
data.ProfileBegin = Primitive.UnpackBeginCut(block.ProfileBegin);
data.profileCurve = block.ProfileCurve;
data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd);
data.ProfileHollow = Primitive.UnpackProfileHollow(block.ProfileHollow);
obj.Prim.PrimData = data;
scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimData);
}
else
{
Logger.Log("Got an ObjectShape packet for unknown object " + block.ObjectLocalID,
Helpers.LogLevel.Warning);
}
}
}
void ObjectFlagUpdateHandler(Packet packet, Agent agent)
{
ObjectFlagUpdatePacket update = (ObjectFlagUpdatePacket)packet;
SimulationObject obj;
if (scene.TryGetObject(update.AgentData.ObjectLocalID, out obj))
{
PrimFlags flags = obj.Prim.Flags;
if (update.AgentData.CastsShadows)
flags |= PrimFlags.CastShadows;
else
flags &= ~PrimFlags.CastShadows;
if (update.AgentData.IsPhantom)
flags |= PrimFlags.Phantom;
else
flags &= ~PrimFlags.Phantom;
if (update.AgentData.IsTemporary)
flags |= PrimFlags.Temporary;
else
flags &= ~PrimFlags.Temporary;
if (update.AgentData.UsePhysics)
flags |= PrimFlags.Physics;
else
flags &= ~PrimFlags.Physics;
obj.Prim.Flags = flags;
scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.PrimFlags);
}
else
{
Logger.Log("Got an ObjectFlagUpdate packet for unknown object " + update.AgentData.ObjectLocalID,
Helpers.LogLevel.Warning);
}
}
void ObjectExtraParamsHandler(Packet packet, Agent agent)
{
ObjectExtraParamsPacket extra = (ObjectExtraParamsPacket)packet;
for (int i = 0; i < extra.ObjectData.Length; i++)
{
ObjectExtraParamsPacket.ObjectDataBlock block = extra.ObjectData[i];
SimulationObject obj;
if (scene.TryGetObject(block.ObjectLocalID, out obj))
{
ExtraParamType type = (ExtraParamType)block.ParamType;
if (block.ParamInUse)
{
switch (type)
{
case ExtraParamType.Flexible:
obj.Prim.Flexible = new Primitive.FlexibleData(block.ParamData, 0);
break;
case ExtraParamType.Light:
obj.Prim.Light = new Primitive.LightData(block.ParamData, 0);
break;
case ExtraParamType.Sculpt:
obj.Prim.Sculpt = new Primitive.SculptData(block.ParamData, 0);
break;
}
}
else
{
switch (type)
{
case ExtraParamType.Flexible:
obj.Prim.Flexible = null;
break;
case ExtraParamType.Light:
obj.Prim.Light = null;
break;
case ExtraParamType.Sculpt:
obj.Prim.Sculpt = null;
break;
}
}
scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.ExtraData);
}
}
}
void ObjectImageHandler(Packet packet, Agent agent)
{
ObjectImagePacket image = (ObjectImagePacket)packet;
for (int i = 0; i < image.ObjectData.Length; i++)
{
SimulationObject obj;
if (scene.TryGetObject(image.ObjectData[i].ObjectLocalID, out obj))
{
obj.Prim.MediaURL = Utils.BytesToString(image.ObjectData[i].MediaURL);
obj.Prim.Textures = new Primitive.TextureEntry(image.ObjectData[i].TextureEntry, 0, image.ObjectData[i].TextureEntry.Length);
scene.ObjectAddOrUpdate(this, obj, obj.Prim.OwnerID, 0, PrimFlags.None, UpdateFlags.MediaURL | UpdateFlags.Textures);
}
}
}
void UndoHandler(Packet packet, Agent agent)
{
UndoPacket undo = (UndoPacket)packet;
for (int i = 0; i < undo.ObjectData.Length; i++)
{
SimulationObject obj;
if (scene.TryGetObject(undo.ObjectData[i].ObjectID, out obj))
scene.ObjectUndo(this, obj);
}
}
void RedoHandler(Packet packet, Agent agent)
{
RedoPacket redo = (RedoPacket)packet;
for (int i = 0; i < redo.ObjectData.Length; i++)
{
SimulationObject obj;
if (scene.TryGetObject(redo.ObjectData[i].ObjectID, out obj))
scene.ObjectRedo(this, obj);
}
}
void MultipleObjectUpdateHandler(Packet packet, Agent agent)
{
MultipleObjectUpdatePacket update = (MultipleObjectUpdatePacket)packet;
for (int i = 0; i < update.ObjectData.Length; i++)
{
bool scaled = false;
MultipleObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[i];
SimulationObject obj;
if (scene.TryGetObject(block.ObjectLocalID, out obj))
{
UpdateType type = (UpdateType)block.Type;
//bool linked = ((type & UpdateType.Linked) != 0);
int pos = 0;
Vector3 position = obj.Prim.Position;
Quaternion rotation = obj.Prim.Rotation;
Vector3 scale = obj.Prim.Scale;
UpdateFlags updateFlags = UpdateFlags.None;
if ((type & UpdateType.Position) != 0)
{
updateFlags |= UpdateFlags.Position;
position = new Vector3(block.Data, pos);
pos += 12;
}
if ((type & UpdateType.Rotation) != 0)
{
updateFlags |= UpdateFlags.Rotation;
rotation = new Quaternion(block.Data, pos, true);
pos += 12;
}
if ((type & UpdateType.Scale) != 0)
{
updateFlags |= UpdateFlags.Scale;
scaled = true;
scale = new Vector3(block.Data, pos);
pos += 12;
// FIXME: Use this in linksets
//bool uniform = ((type & UpdateType.Uniform) != 0);
}
obj.Prim.Position = position;
obj.Prim.Rotation = rotation;
if (scaled) obj.Prim.Scale = scale;
scene.ObjectAddOrUpdate(this, obj, agent.ID, 0, PrimFlags.None, updateFlags);
}
else
{
// Ghosted prim, send a kill message to this agent
KillObjectPacket kill = new KillObjectPacket();
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
kill.ObjectData[0].ID = block.ObjectLocalID;
scene.UDP.SendPacket(agent.ID, kill, PacketCategory.State);
}
}
}
void RequestObjectPropertiesFamilyHandler(Packet packet, Agent agent)
{
RequestObjectPropertiesFamilyPacket request = (RequestObjectPropertiesFamilyPacket)packet;
ReportType type = (ReportType)request.ObjectData.RequestFlags;
SimulationObject obj;
if (scene.TryGetObject(request.ObjectData.ObjectID, out obj))
{
ObjectPropertiesFamilyPacket props = new ObjectPropertiesFamilyPacket();
props.ObjectData.BaseMask = (uint)obj.Prim.Properties.Permissions.BaseMask;
props.ObjectData.Category = (uint)obj.Prim.Properties.Category;
props.ObjectData.Description = Utils.StringToBytes(obj.Prim.Properties.Description);
props.ObjectData.EveryoneMask = (uint)obj.Prim.Properties.Permissions.EveryoneMask;
props.ObjectData.GroupID = obj.Prim.Properties.GroupID;
props.ObjectData.GroupMask = (uint)obj.Prim.Properties.Permissions.GroupMask;
props.ObjectData.LastOwnerID = obj.Prim.Properties.LastOwnerID;
props.ObjectData.Name = Utils.StringToBytes(obj.Prim.Properties.Name);
props.ObjectData.NextOwnerMask = (uint)obj.Prim.Properties.Permissions.NextOwnerMask;
props.ObjectData.ObjectID = obj.Prim.ID;
props.ObjectData.OwnerID = obj.Prim.Properties.OwnerID;
props.ObjectData.OwnerMask = (uint)obj.Prim.Properties.Permissions.OwnerMask;
props.ObjectData.OwnershipCost = obj.Prim.Properties.OwnershipCost;
props.ObjectData.RequestFlags = (uint)type;
props.ObjectData.SalePrice = obj.Prim.Properties.SalePrice;
props.ObjectData.SaleType = (byte)obj.Prim.Properties.SaleType;
scene.UDP.SendPacket(agent.ID, props, PacketCategory.Transaction);
}
else
{
Logger.Log("RequestObjectPropertiesFamily sent for unknown object " +
request.ObjectData.ObjectID.ToString(), Helpers.LogLevel.Warning);
}
}
Vector3 FullSceneCollisionTest(Vector3 rayStart, Vector3 rayEnd)
{
// HACK: For now
Logger.DebugLog("Full scene collision test was requested, ignoring");
return rayEnd;
}
}
}

View File

@@ -48,8 +48,6 @@ namespace Simian
// Add the default parcel to the list
parcels[parcel.LocalID] = parcel;
scene.UDP.RegisterPacketCallback(PacketType.ParcelPropertiesRequest, ParcelPropertiesRequestHandler);
scene.UDP.RegisterPacketCallback(PacketType.ParcelPropertiesUpdate, ParcelPropertiesUpdateHandler);
return true;
}
@@ -124,6 +122,21 @@ namespace Simian
}
}
public void UpdateParcel(Parcel parcel)
{
lock (parcels) parcels[parcel.LocalID] = parcel;
}
public int GetParcelID(int x, int y)
{
return parcelOverlay[y * 64 + x];
}
public bool TryGetParcel(int parcelID, out Parcel parcel)
{
return parcels.TryGetValue(parcelID, out parcel);
}
void UpdateParcelSize(ref Parcel parcel)
{
int minX = 64;
@@ -156,152 +169,5 @@ namespace Simian
parcel.AABBMax.Y = maxY;
parcel.Area = area;
}
void SendParcelProperties(int parcelID, int sequenceID, bool snapSelection, ParcelResult result,
Agent agent)
{
Parcel parcel;
if (parcels.TryGetValue(parcelID, out parcel))
{
ParcelPropertiesPacket properties = new ParcelPropertiesPacket();
properties.AgeVerificationBlock.RegionDenyAgeUnverified = false;
properties.ParcelData.AABBMax = parcel.AABBMax;
properties.ParcelData.AABBMin = parcel.AABBMin;
properties.ParcelData.Area = parcel.Area;
properties.ParcelData.AuctionID = parcel.AuctionID;
properties.ParcelData.AuthBuyerID = parcel.AuthBuyerID;
properties.ParcelData.Bitmap = parcel.Bitmap;
properties.ParcelData.Category = (byte)parcel.Category;
properties.ParcelData.ClaimDate = (int)Utils.DateTimeToUnixTime(parcel.ClaimDate);
properties.ParcelData.ClaimPrice = parcel.ClaimPrice;
properties.ParcelData.Desc = Utils.StringToBytes(parcel.Desc);
properties.ParcelData.GroupID = parcel.GroupID;
properties.ParcelData.GroupPrims = parcel.GroupPrims;
properties.ParcelData.IsGroupOwned = parcel.IsGroupOwned;
properties.ParcelData.LandingType = (byte)parcel.Landing;
properties.ParcelData.LocalID = parcel.LocalID;
properties.ParcelData.MaxPrims = parcel.MaxPrims;
properties.ParcelData.MediaAutoScale = parcel.Media.MediaAutoScale;
properties.ParcelData.MediaID = parcel.Media.MediaID;
properties.ParcelData.MediaURL = Utils.StringToBytes(parcel.Media.MediaURL);
properties.ParcelData.MusicURL = Utils.StringToBytes(parcel.MusicURL);
properties.ParcelData.Name = Utils.StringToBytes(parcel.Name);
properties.ParcelData.OtherCleanTime = parcel.OtherCleanTime;
properties.ParcelData.OtherCount = parcel.OtherCount;
properties.ParcelData.OtherPrims = parcel.OtherPrims;
properties.ParcelData.OwnerID = parcel.OwnerID;
properties.ParcelData.OwnerPrims = parcel.OwnerPrims;
properties.ParcelData.ParcelFlags = (uint)parcel.Flags;
properties.ParcelData.ParcelPrimBonus = parcel.ParcelPrimBonus;
properties.ParcelData.PassHours = parcel.PassHours;
properties.ParcelData.PassPrice = parcel.PassPrice;
properties.ParcelData.PublicCount = parcel.PublicCount;
properties.ParcelData.RegionDenyAnonymous = parcel.RegionDenyAnonymous;
properties.ParcelData.RegionDenyIdentified = false; // Deprecated
properties.ParcelData.RegionDenyTransacted = false; // Deprecated
properties.ParcelData.RegionPushOverride = parcel.RegionPushOverride;
properties.ParcelData.RentPrice = parcel.RentPrice;
properties.ParcelData.RequestResult = (int)result;
properties.ParcelData.SalePrice = parcel.SalePrice;
properties.ParcelData.SelectedPrims = 0; // TODO:
properties.ParcelData.SelfCount = parcel.SelfCount;
properties.ParcelData.SequenceID = sequenceID;
properties.ParcelData.SimWideMaxPrims = parcel.SimWideMaxPrims;
properties.ParcelData.SimWideTotalPrims = parcel.SimWideTotalPrims;
properties.ParcelData.SnapSelection = snapSelection;
properties.ParcelData.SnapshotID = parcel.SnapshotID;
properties.ParcelData.Status = (byte)parcel.Status;
properties.ParcelData.TotalPrims = parcel.TotalPrims;
properties.ParcelData.UserLocation = parcel.UserLocation;
properties.ParcelData.UserLookAt = parcel.UserLookAt;
// HACK: Make everyone think they are the owner of this parcel
properties.ParcelData.OwnerID = agent.ID;
scene.UDP.SendPacket(agent.ID, properties, PacketCategory.Transaction);
}
else
{
Logger.Log("SendParcelProperties() called for unknown parcel " + parcelID, Helpers.LogLevel.Warning);
}
}
void ParcelPropertiesRequestHandler(Packet packet, Agent agent)
{
ParcelPropertiesRequestPacket request = (ParcelPropertiesRequestPacket)packet;
// TODO: Replace with HashSet when we switch to .NET 3.5
List<int> parcels = new List<int>();
// Convert the boundaries to integers
int north = (int)Math.Round(request.ParcelData.North) / 4;
int east = (int)Math.Round(request.ParcelData.East) / 4;
int south = (int)Math.Round(request.ParcelData.South) / 4;
int west = (int)Math.Round(request.ParcelData.West) / 4;
// Find all of the parcels within the given boundaries
int xLen = east - west;
int yLen = north - south;
for (int x = 0; x < xLen; x++)
{
for (int y = 0; y < yLen; y++)
{
if (west + x < 64 && south + y < 64)
{
int currentParcelID = parcelOverlay[(south + y) * 64 + (west + x)];
if (!parcels.Contains(currentParcelID))
parcels.Add(currentParcelID);
}
}
}
ParcelResult result = ParcelResult.NoData;
if (parcels.Count == 1)
result = ParcelResult.Single;
else if (parcels.Count > 1)
result = ParcelResult.Multiple;
for (int i = 0; i < parcels.Count; i++)
SendParcelProperties(parcels[i], request.ParcelData.SequenceID, request.ParcelData.SnapSelection, result, agent);
}
void ParcelPropertiesUpdateHandler(Packet packet, Agent agent)
{
ParcelPropertiesUpdatePacket update = (ParcelPropertiesUpdatePacket)packet;
Parcel parcel;
if (parcels.TryGetValue(update.ParcelData.LocalID, out parcel))
{
parcel.AuthBuyerID = update.ParcelData.AuthBuyerID;
parcel.Category = (Parcel.ParcelCategory)update.ParcelData.Category;
parcel.Desc = Utils.BytesToString(update.ParcelData.Desc);
parcel.Flags = (Parcel.ParcelFlags)update.ParcelData.ParcelFlags;
parcel.GroupID = update.ParcelData.GroupID;
parcel.Landing = (Parcel.LandingType)update.ParcelData.LandingType;
parcel.Media.MediaAutoScale = update.ParcelData.MediaAutoScale;
parcel.Media.MediaID = update.ParcelData.MediaID;
parcel.Media.MediaURL = Utils.BytesToString(update.ParcelData.MediaURL);
parcel.MusicURL = Utils.BytesToString(update.ParcelData.MusicURL);
parcel.Name = Utils.BytesToString(update.ParcelData.Name);
parcel.PassHours = update.ParcelData.PassHours;
parcel.PassPrice = update.ParcelData.PassPrice;
parcel.SalePrice = update.ParcelData.SalePrice;
parcel.SnapshotID = update.ParcelData.SnapshotID;
parcel.UserLocation = update.ParcelData.UserLocation;
parcel.UserLookAt = update.ParcelData.UserLookAt;
lock (parcels)
parcels[parcel.LocalID] = parcel;
if (update.ParcelData.Flags != 0)
SendParcelProperties(parcel.LocalID, 0, false, ParcelResult.Single, agent);
}
else
{
Logger.Log("Got a ParcelPropertiesUpdate for an unknown parcel " + update.ParcelData.LocalID,
Helpers.LogLevel.Warning);
}
}
}
}

View File

@@ -10,8 +10,6 @@ namespace Simian
{
public class PeriscopeTransferManager
{
public const string UPLOAD_DIR = "uploadedAssets";
ISceneProvider scene;
GridClient client;
Dictionary<ulong, Asset> CurrentUploads = new Dictionary<ulong, Asset>();

View File

@@ -7,12 +7,25 @@ namespace Simian
{
public class PhysicsSimple : IExtension<ISceneProvider>, IPhysicsProvider
{
ISceneProvider scene;
// Run our own frames per second limiter on top of the limiting done by ISceneProvider
const int FRAMES_PER_SECOND = 10;
public float TimeDilation
{
get { return 1.0f; }
}
const float GRAVITY = 9.8f; //meters/sec
const float WALK_SPEED = 3f; //meters/sec
const float RUN_SPEED = 5f; //meters/sec
const float FLY_SPEED = 10f; //meters/sec
const float FALL_DELAY = 0.33f; //seconds before starting animation
const float FALL_FORGIVENESS = .25f; //fall buffer in meters
const float JUMP_IMPULSE_VERTICAL = 8.5f; //boost amount in meters/sec
const float JUMP_IMPULSE_HORIZONTAL = 10f; //boost amount in meters/sec
const float INITIAL_HOVER_IMPULSE = 2f; //boost amount in meters/sec
const float PREJUMP_DELAY = 0.25f; //seconds before actually jumping
const float AVATAR_TERMINAL_VELOCITY = 54f; //~120mph
const float SQRT_TWO = 1.41421356f;
ISceneProvider scene;
float elapsedSinceUpdate;
public PhysicsSimple()
{
@@ -21,6 +34,8 @@ namespace Simian
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.OnObjectAddOrUpdate += Scene_OnObjectAddOrUpdate;
return true;
}
@@ -28,6 +43,335 @@ namespace Simian
{
}
public void Update(float elapsedTime)
{
if (elapsedSinceUpdate >= 1f / (float)FRAMES_PER_SECOND)
{
elapsedTime = elapsedSinceUpdate;
elapsedSinceUpdate = 0f;
}
else
{
elapsedSinceUpdate += elapsedTime;
return;
}
scene.ForEachAgent(
delegate(Agent agent)
{
if ((agent.Avatar.Prim.Flags & PrimFlags.Physics) == 0)
return;
bool animsChanged = false;
// Create forward and left vectors from the current avatar rotation
Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(agent.Avatar.Prim.Rotation);
Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix);
Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix);
// Check control flags
bool heldForward = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
bool heldBack = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG;
bool heldLeft = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS;
bool heldRight = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG;
//bool heldTurnLeft = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT;
//bool heldTurnRight = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT;
bool heldUp = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS;
bool heldDown = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG;
bool flying = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY;
//bool mouselook = (agent.ControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) == AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK;
// direction in which the avatar is trying to move
Vector3 move = Vector3.Zero;
if (heldForward) { move.X += fwd.X; move.Y += fwd.Y; }
if (heldBack) { move.X -= fwd.X; move.Y -= fwd.Y; }
if (heldLeft) { move.X += left.X; move.Y += left.Y; }
if (heldRight) { move.X -= left.X; move.Y -= left.Y; }
if (heldUp) { move.Z += 1; }
if (heldDown) { move.Z -= 1; }
// is the avatar trying to move?
bool moving = move != Vector3.Zero;
bool jumping = agent.TickJump != 0;
// 2-dimensional speed multipler
float speed = elapsedTime * (flying ? FLY_SPEED : agent.Running && !jumping ? RUN_SPEED : WALK_SPEED);
if ((heldForward || heldBack) && (heldLeft || heldRight))
speed /= SQRT_TWO;
Vector3 agentPosition = agent.Avatar.GetSimulatorPosition();
float oldFloor = scene.GetTerrainHeightAt(agentPosition.X, agentPosition.Y);
agentPosition += (move * speed);
float newFloor = scene.GetTerrainHeightAt(agentPosition.X, agentPosition.Y);
if (!flying && newFloor != oldFloor)
speed /= (1 + (SQRT_TWO * Math.Abs(newFloor - oldFloor)));
//HACK: distance from avatar center to the bottom of its feet
float distanceFromFloor = agent.Avatar.Prim.Scale.Z * .5f;
float lowerLimit = newFloor + distanceFromFloor;
//"bridge" physics
if (agent.Avatar.Prim.Velocity != Vector3.Zero)
{
//start ray at our feet
Vector3 rayStart = new Vector3(
agent.Avatar.Prim.Position.X,
agent.Avatar.Prim.Position.Y,
agent.Avatar.Prim.Position.Z - distanceFromFloor
);
//end ray at 0.01m below our feet
Vector3 rayEnd = new Vector3(
rayStart.X,
rayStart.Y,
rayStart.Z - 0.01f
);
scene.ForEachObject(delegate(SimulationObject obj)
{
//HACK: check nearby objects (what did you expect, octree?)
if (Vector3.Distance(rayStart, obj.Prim.Position) <= 15f)
{
Vector3 collision = scene.Physics.ObjectCollisionTest(rayStart, rayEnd, obj);
if (collision != rayEnd) //we collided!
{
//check if we are any higher than before
float height = collision.Z + distanceFromFloor;
if (height > lowerLimit) lowerLimit = height;
}
}
});
}
// Z acceleration resulting from gravity
float gravity = 0f;
float waterChestHeight = scene.WaterHeight - (agent.Avatar.Prim.Scale.Z * .33f);
if (flying)
{
agent.TickFall = 0;
agent.TickJump = 0;
//velocity falloff while flying
agent.Avatar.Prim.Velocity.X *= 0.66f;
agent.Avatar.Prim.Velocity.Y *= 0.66f;
agent.Avatar.Prim.Velocity.Z *= 0.33f;
if (agent.Avatar.Prim.Position.Z == lowerLimit)
agent.Avatar.Prim.Velocity.Z += INITIAL_HOVER_IMPULSE;
if (move.X != 0 || move.Y != 0)
{ //flying horizontally
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FLY))
animsChanged = true;
}
else if (move.Z > 0)
{ //flying straight up
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_UP))
animsChanged = true;
}
else if (move.Z < 0)
{ //flying straight down
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_DOWN))
animsChanged = true;
}
else
{ //hovering in the air
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER))
animsChanged = true;
}
}
else if (agent.Avatar.Prim.Position.Z > lowerLimit + FALL_FORGIVENESS || agent.Avatar.Prim.Position.Z <= waterChestHeight)
{ //falling, floating, or landing from a jump
if (agent.Avatar.Prim.Position.Z > scene.WaterHeight)
{ //above water
//override controls while drifting
move = Vector3.Zero;
//keep most of our horizontal inertia
agent.Avatar.Prim.Velocity.X *= 0.975f;
agent.Avatar.Prim.Velocity.Y *= 0.975f;
float fallElapsed = (float)(Environment.TickCount - agent.TickFall) / 1000f;
if (agent.TickFall == 0 || (fallElapsed > FALL_DELAY && agent.Avatar.Prim.Velocity.Z >= 0f))
{ //just started falling
agent.TickFall = Environment.TickCount;
}
else
{
gravity = GRAVITY * fallElapsed * elapsedTime; //normal gravity
if (!jumping)
{ //falling
if (fallElapsed > FALL_DELAY)
{ //falling long enough to trigger the animation
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FALLDOWN))
animsChanged = true;
}
}
}
}
else if (agent.Avatar.Prim.Position.Z >= waterChestHeight)
{ //at the water line
gravity = 0f;
agent.Avatar.Prim.Velocity *= 0.5f;
agent.Avatar.Prim.Velocity.Z = 0f;
if (move.Z < 1) agent.Avatar.Prim.Position.Z = waterChestHeight;
if (move.Z > 0)
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER_UP))
animsChanged = true;
}
else if (move.X != 0 || move.Y != 0)
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FLYSLOW))
animsChanged = true;
}
else
{
if (scene.Avatars.SetDefaultAnimation(agent, Animations.HOVER))
animsChanged = true;
}
}
else
{ //underwater
gravity = 0f; //buoyant
agent.Avatar.Prim.Velocity *= 0.5f * elapsedTime;
agent.Avatar.Prim.Velocity.Z += 0.75f * elapsedTime;
if (scene.Avatars.SetDefaultAnimation(agent, Animations.FALLDOWN))
animsChanged = true;
}
}
else
{ //on the ground
agent.TickFall = 0;
//friction
agent.Avatar.Prim.Acceleration *= 0.2f;
agent.Avatar.Prim.Velocity *= 0.2f;
agent.Avatar.Prim.Position.Z = lowerLimit;
if (move.Z > 0)
{ //jumping
if (!jumping)
{ //begin prejump
move.Z = 0; //override Z control
if (scene.Avatars.SetDefaultAnimation(agent, Animations.PRE_JUMP))
animsChanged = true;
agent.TickJump = Environment.TickCount;
}
else if (Environment.TickCount - agent.TickJump > PREJUMP_DELAY * 1000)
{ //start actual jump
if (agent.TickJump == -1)
{
//already jumping! end current jump
agent.TickJump = 0;
return;
}
if (scene.Avatars.SetDefaultAnimation(agent, Animations.JUMP))
animsChanged = true;
agent.Avatar.Prim.Velocity.X += agent.Avatar.Prim.Acceleration.X * JUMP_IMPULSE_HORIZONTAL;
agent.Avatar.Prim.Velocity.Y += agent.Avatar.Prim.Acceleration.Y * JUMP_IMPULSE_HORIZONTAL;
agent.Avatar.Prim.Velocity.Z = JUMP_IMPULSE_VERTICAL * elapsedTime;
agent.TickJump = -1; //flag that we are currently jumping
}
else move.Z = 0; //override Z control
}
else
{ //not jumping
agent.TickJump = 0;
if (move.X != 0 || move.Y != 0)
{ //not walking
if (move.Z < 0)
{ //crouchwalking
if (scene.Avatars.SetDefaultAnimation(agent, Animations.CROUCHWALK))
animsChanged = true;
}
else if (agent.Running)
{ //running
if (scene.Avatars.SetDefaultAnimation(agent, Animations.RUN))
animsChanged = true;
}
else
{ //walking
if (scene.Avatars.SetDefaultAnimation(agent, Animations.WALK))
animsChanged = true;
}
}
else
{ //walking
if (move.Z < 0)
{ //crouching
if (scene.Avatars.SetDefaultAnimation(agent, Animations.CROUCH))
animsChanged = true;
}
else
{ //standing
if (scene.Avatars.SetDefaultAnimation(agent, Animations.STAND))
animsChanged = true;
}
}
}
}
if (animsChanged)
scene.Avatars.SendAnimations(agent);
float maxVel = AVATAR_TERMINAL_VELOCITY * elapsedTime;
// static acceleration when any control is held, otherwise none
if (moving)
{
agent.Avatar.Prim.Acceleration = move * speed;
if (agent.Avatar.Prim.Acceleration.Z < -maxVel)
agent.Avatar.Prim.Acceleration.Z = -maxVel;
else if (agent.Avatar.Prim.Acceleration.Z > maxVel)
agent.Avatar.Prim.Acceleration.Z = maxVel;
}
else agent.Avatar.Prim.Acceleration = Vector3.Zero;
agent.Avatar.Prim.Velocity += agent.Avatar.Prim.Acceleration - new Vector3(0f, 0f, gravity);
if (agent.Avatar.Prim.Velocity.Z < -maxVel)
agent.Avatar.Prim.Velocity.Z = -maxVel;
else if (agent.Avatar.Prim.Velocity.Z > maxVel)
agent.Avatar.Prim.Velocity.Z = maxVel;
agent.Avatar.Prim.Position += agent.Avatar.Prim.Velocity;
if (agent.Avatar.Prim.Position.X < 0) agent.Avatar.Prim.Position.X = 0f;
else if (agent.Avatar.Prim.Position.X > 255) agent.Avatar.Prim.Position.X = 255f;
if (agent.Avatar.Prim.Position.Y < 0) agent.Avatar.Prim.Position.Y = 0f;
else if (agent.Avatar.Prim.Position.Y > 255) agent.Avatar.Prim.Position.Y = 255f;
if (agent.Avatar.Prim.Position.Z < lowerLimit) agent.Avatar.Prim.Position.Z = lowerLimit;
}
);
}
public Vector3 ObjectCollisionTest(Vector3 rayStart, Vector3 rayEnd, SimulationObject obj)
{
Vector3 closestPoint = rayEnd;
@@ -80,6 +424,28 @@ namespace Simian
}
}
void Scene_OnObjectAddOrUpdate(object sender, SimulationObject obj, UUID ownerID, int scriptStartParam, PrimFlags creatorFlags, UpdateFlags update)
{
// Recompute meshes for
bool forceMeshing = false;
bool forceTransform = false;
if ((update & UpdateFlags.Scale) != 0 ||
(update & UpdateFlags.Position) != 0 ||
(update & UpdateFlags.Rotation) != 0)
{
forceTransform = true;
}
if ((update & UpdateFlags.PrimData) != 0)
{
forceMeshing = true;
}
// TODO: This doesn't update children prims when their parents move
obj.GetWorldMesh(DetailLevel.Low, forceMeshing, forceTransform);
}
/// <summary>
/// Adapted from http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
/// </summary>

File diff suppressed because it is too large Load Diff

View File

@@ -1,359 +0,0 @@
using System;
using System.Collections.Generic;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian
{
public class TransferManager : IExtension<ISceneProvider>
{
ISceneProvider scene;
Dictionary<ulong, Asset> CurrentUploads = new Dictionary<ulong, Asset>();
public TransferManager()
{
}
public bool Start(ISceneProvider scene)
{
this.scene = scene;
scene.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
scene.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
scene.UDP.RegisterPacketCallback(PacketType.AbortXfer, new PacketCallback(AbortXferHandler));
scene.UDP.RegisterPacketCallback(PacketType.TransferRequest, new PacketCallback(TransferRequestHandler));
return true;
}
public void Stop()
{
}
#region Xfer System
void AssetUploadRequestHandler(Packet packet, Agent agent)
{
AssetUploadRequestPacket request = (AssetUploadRequestPacket)packet;
UUID assetID = UUID.Combine(request.AssetBlock.TransactionID, agent.SecureSessionID);
// Check if the asset is small enough to fit in a single packet
if (request.AssetBlock.AssetData.Length != 0)
{
// Create a new asset from the completed upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, request.AssetBlock.AssetData);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Storing uploaded asset {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
// Store the asset
scene.Server.Assets.StoreAsset(asset);
// Send a success response
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = request.AssetBlock.Type;
complete.AssetBlock.UUID = assetID;
scene.UDP.SendPacket(agent.ID, complete, PacketCategory.Inventory);
}
else
{
// Create a new (empty) asset for the upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, null);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Starting upload for {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
RequestXferPacket xfer = new RequestXferPacket();
xfer.XferID.DeleteOnCompletion = request.AssetBlock.Tempfile;
xfer.XferID.FilePath = 0;
xfer.XferID.Filename = Utils.EmptyBytes;
xfer.XferID.ID = request.AssetBlock.TransactionID.GetULong();
xfer.XferID.UseBigPackets = false;
xfer.XferID.VFileID = asset.AssetID;
xfer.XferID.VFileType = request.AssetBlock.Type;
// Add this asset to the current upload list
lock (CurrentUploads)
CurrentUploads[xfer.XferID.ID] = asset;
scene.UDP.SendPacket(agent.ID, xfer, PacketCategory.Inventory);
}
}
void SendXferPacketHandler(Packet packet, Agent agent)
{
SendXferPacketPacket xfer = (SendXferPacketPacket)packet;
Asset asset;
if (CurrentUploads.TryGetValue(xfer.XferID.ID, out asset))
{
if (asset.AssetData == null)
{
if (xfer.XferID.Packet != 0)
{
Logger.Log(String.Format("Received Xfer packet {0} before the first packet!",
xfer.XferID.Packet), Helpers.LogLevel.Error);
return;
}
uint size = Utils.BytesToUInt(xfer.DataPacket.Data);
asset.AssetData = new byte[size];
Buffer.BlockCopy(xfer.DataPacket.Data, 4, asset.AssetData, 0, xfer.DataPacket.Data.Length - 4);
// Confirm the first upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
scene.UDP.SendPacket(agent.ID, confirm, PacketCategory.Asset);
}
else
{
Buffer.BlockCopy(xfer.DataPacket.Data, 0, asset.AssetData, (int)xfer.XferID.Packet * 1000,
xfer.DataPacket.Data.Length);
// Confirm this upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
scene.UDP.SendPacket(agent.ID, confirm, PacketCategory.Asset);
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
// Asset upload finished
Logger.DebugLog(String.Format("Completed Xfer upload of asset {0} ({1}", asset.AssetID, asset.AssetType));
lock (CurrentUploads)
CurrentUploads.Remove(xfer.XferID.ID);
scene.Server.Assets.StoreAsset(asset);
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = (sbyte)asset.AssetType;
complete.AssetBlock.UUID = asset.AssetID;
scene.UDP.SendPacket(agent.ID, complete, PacketCategory.Asset);
}
}
}
else
{
Logger.DebugLog("Received a SendXferPacket for an unknown upload");
}
}
void AbortXferHandler(Packet packet, Agent agent)
{
AbortXferPacket abort = (AbortXferPacket)packet;
lock (CurrentUploads)
{
if (CurrentUploads.ContainsKey(abort.XferID.ID))
{
Logger.DebugLog(String.Format("Aborting Xfer {0}, result: {1}", abort.XferID.ID,
(TransferError)abort.XferID.Result));
CurrentUploads.Remove(abort.XferID.ID);
}
else
{
Logger.DebugLog(String.Format("Received an AbortXfer for an unknown xfer {0}",
abort.XferID.ID));
}
}
}
#endregion Xfer System
#region Transfer System
void TransferRequestHandler(Packet packet, Agent agent)
{
TransferRequestPacket request = (TransferRequestPacket)packet;
ChannelType channel = (ChannelType)request.TransferInfo.ChannelType;
SourceType source = (SourceType)request.TransferInfo.SourceType;
if (channel == ChannelType.Asset)
{
// Construct the response packet
TransferInfoPacket response = new TransferInfoPacket();
response.TransferInfo = new TransferInfoPacket.TransferInfoBlock();
response.TransferInfo.TransferID = request.TransferInfo.TransferID;
if (source == SourceType.Asset)
{
// Parse the request
UUID assetID = new UUID(request.TransferInfo.Params, 0);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 16);
// Set the response channel type
response.TransferInfo.ChannelType = (int)ChannelType.Asset;
// Params
response.TransferInfo.Params = new byte[20];
Buffer.BlockCopy(assetID.GetBytes(), 0, response.TransferInfo.Params, 0, 16);
Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, response.TransferInfo.Params, 16, 4);
// Check if we have this asset
Asset asset;
if (scene.Server.Assets.TryGetAsset(assetID, out asset))
{
if (asset.AssetType == type)
{
Logger.DebugLog(String.Format("Transferring asset {0} ({1})", asset.AssetID, asset.AssetType));
// Asset found
response.TransferInfo.Size = asset.AssetData.Length;
response.TransferInfo.Status = (int)StatusCode.OK;
response.TransferInfo.TargetType = (int)TargetType.Unknown; // Doesn't seem to be used by the client
scene.UDP.SendPacket(agent.ID, response, PacketCategory.Asset);
// Transfer system does not wait for ACKs, just sends all of the
// packets for this transfer out
const int MAX_CHUNK_SIZE = Settings.MAX_PACKET_SIZE - 100;
int processedLength = 0;
int packetNum = 0;
while (processedLength < asset.AssetData.Length)
{
TransferPacketPacket transfer = new TransferPacketPacket();
transfer.TransferData.ChannelType = (int)ChannelType.Asset;
transfer.TransferData.TransferID = request.TransferInfo.TransferID;
transfer.TransferData.Packet = packetNum++;
int chunkSize = Math.Min(asset.AssetData.Length - processedLength, MAX_CHUNK_SIZE);
transfer.TransferData.Data = new byte[chunkSize];
Buffer.BlockCopy(asset.AssetData, processedLength, transfer.TransferData.Data, 0, chunkSize);
processedLength += chunkSize;
if (processedLength >= asset.AssetData.Length)
transfer.TransferData.Status = (int)StatusCode.Done;
else
transfer.TransferData.Status = (int)StatusCode.OK;
scene.UDP.SendPacket(agent.ID, transfer, PacketCategory.Asset);
}
}
else
{
Logger.Log(String.Format(
"Request for asset {0} with type {1} does not match actual asset type {2}",
assetID, type, asset.AssetType), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format("Request for missing asset {0} with type {1}",
assetID, type), Helpers.LogLevel.Warning);
// Asset not found
response.TransferInfo.Size = 0;
response.TransferInfo.Status = (int)StatusCode.UnknownSource;
response.TransferInfo.TargetType = (int)TargetType.Unknown;
scene.UDP.SendPacket(agent.ID, response, PacketCategory.Asset);
}
}
else if (source == SourceType.SimEstate)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
EstateAssetType type = (EstateAssetType)Utils.BytesToInt(request.TransferInfo.Params, 32);
Logger.Log("Please implement estate asset transfers", Helpers.LogLevel.Warning);
}
else if (source == SourceType.SimInventoryItem)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
UUID ownerID = new UUID(request.TransferInfo.Params, 32);
UUID taskID = new UUID(request.TransferInfo.Params, 48);
UUID itemID = new UUID(request.TransferInfo.Params, 64);
UUID assetID = new UUID(request.TransferInfo.Params, 80);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 96);
if (taskID != UUID.Zero)
{
// Task (prim) inventory request
Logger.Log("Please implement task inventory transfers", Helpers.LogLevel.Warning);
}
else
{
// Agent inventory request
Logger.Log("Please implement agent inventory transfer", Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
#endregion Transfer System
Asset CreateAsset(AssetType type, UUID assetID, byte[] data)
{
switch (type)
{
case AssetType.Bodypart:
return new AssetBodypart(assetID, data);
case AssetType.Clothing:
return new AssetClothing(assetID, data);
case AssetType.LSLBytecode:
return new AssetScriptBinary(assetID, data);
case AssetType.LSLText:
return new AssetScriptText(assetID, data);
case AssetType.Notecard:
return new AssetNotecard(assetID, data);
case AssetType.Texture:
return new AssetTexture(assetID, data);
case AssetType.Animation:
return new AssetAnimation(assetID, data);
case AssetType.CallingCard:
case AssetType.Folder:
case AssetType.Gesture:
case AssetType.ImageJPEG:
case AssetType.ImageTGA:
case AssetType.Landmark:
case AssetType.LostAndFoundFolder:
case AssetType.Object:
case AssetType.RootFolder:
case AssetType.Simstate:
case AssetType.SnapshotFolder:
case AssetType.Sound:
return new AssetSound(assetID, data);
case AssetType.SoundWAV:
case AssetType.TextureTGA:
case AssetType.TrashFolder:
case AssetType.Unknown:
default:
Logger.Log("Asset type " + type.ToString() + " not implemented!", Helpers.LogLevel.Warning);
return null;
}
}
}
}