diff --git a/libsecondlife/MainAvatarStatus.cs b/libsecondlife/MainAvatarStatus.cs
index b9125b32..8d7c2e55 100644
--- a/libsecondlife/MainAvatarStatus.cs
+++ b/libsecondlife/MainAvatarStatus.cs
@@ -339,6 +339,27 @@ namespace libsecondlife
UpdateTimer.Enabled = Client.Settings.SEND_AGENT_UPDATES;
}
+ ///
+ /// Send an AgentUpdate with the camera set at the current agent
+ /// position and pointing towards the heading specified
+ ///
+ /// Camera rotation in radians
+ /// Whether to send the AgentUpdate reliable
+ /// or not
+ public void UpdateFromHeading(double heading, bool reliable)
+ {
+ Client.Self.Status.Camera.CameraCenter = Client.Self.Position;
+ Client.Self.Status.Camera.CameraAtAxis.X = (float)Math.Cos(heading);
+ Client.Self.Status.Camera.CameraAtAxis.Y = (float)Math.Sin(heading);
+ Client.Self.Status.Camera.CameraLeftAxis.X = (float)-Math.Sin(heading);
+ Client.Self.Status.Camera.CameraLeftAxis.Y = (float)Math.Cos(heading);
+ Client.Self.Status.Camera.BodyRotation.Z = (float)Math.Sin(heading / 2.0d);
+ Client.Self.Status.Camera.BodyRotation.W = (float)Math.Cos(heading / 2.0d);
+ Client.Self.Status.Camera.HeadRotation = Client.Self.Status.Camera.BodyRotation;
+
+ Client.Self.Status.SendUpdate(reliable);
+ }
+
///
/// Send new AgentUpdate packet to update our current camera
/// position and rotation
diff --git a/libsecondlife/TerrainManager.cs b/libsecondlife/TerrainManager.cs
index ce9817b9..1f6d930e 100644
--- a/libsecondlife/TerrainManager.cs
+++ b/libsecondlife/TerrainManager.cs
@@ -135,7 +135,7 @@ namespace libsecondlife
/// True if the lookup was successful, otherwise false
public bool TerrainHeightAtPoint(ulong regionHandle, int x, int y, out float height)
{
- if (x > 0 && x < 256 && y > 0 && y < 256)
+ if (x >= 0 && x < 256 && y >= 0 && y < 256)
{
lock (SimPatches)
{
diff --git a/libsecondlife/examples/Heightmap/frmHeightmap.cs b/libsecondlife/examples/Heightmap/frmHeightmap.cs
index 44561866..55d96cb0 100644
--- a/libsecondlife/examples/Heightmap/frmHeightmap.cs
+++ b/libsecondlife/examples/Heightmap/frmHeightmap.cs
@@ -15,13 +15,10 @@ namespace Heightmap
{
private SecondLife Client = new SecondLife();
private PictureBox[,] Boxes = new PictureBox[16, 16];
- private System.Timers.Timer UpdateTimer = new System.Timers.Timer(500);
+ private System.Timers.Timer UpdateTimer = new System.Timers.Timer(1000);
private string FirstName, LastName, Password;
- LLVector3 center = new LLVector3(128, 128, 40);
- LLVector3 up = new LLVector3(0, 0, 0.9999f);
- LLVector3 forward = new LLVector3(0, 0.9999f, 0);
- LLVector3 left = new LLVector3(0.9999f, 0, 0);
+ double heading = -Math.PI;
public frmHeightmap(string firstName, string lastName, string password)
{
@@ -107,16 +104,11 @@ namespace Heightmap
void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
- forward.Y += 0.2f;
- left.X += 0.2f;
-
- if (forward.Y >= 1.0f) forward.Y = 0.0f;
- if (left.X >= 1.0f) left.X = 0.0f;
-
// Spin our camera in circles at the center of the sim to load all the terrain
- Client.Self.UpdateCamera(MainAvatar.ControlFlags.NONE, center, forward, left, up,
- LLQuaternion.Identity, LLQuaternion.Identity, 384.0f, MainAvatar.AgentFlags.None,
- MainAvatar.AgentState.None, false);
+ heading += 0.5d;
+ if (heading > Math.PI) heading = -Math.PI;
+
+ Client.Self.Status.UpdateFromHeading(heading, false);
}
void Terrain_OnLandPatch(Simulator simulator, int x, int y, int width, float[] data)
diff --git a/libsecondlife/examples/TestClient/ClientManager.cs b/libsecondlife/examples/TestClient/ClientManager.cs
index 528dba59..be27372d 100644
--- a/libsecondlife/examples/TestClient/ClientManager.cs
+++ b/libsecondlife/examples/TestClient/ClientManager.cs
@@ -84,10 +84,16 @@ namespace libsecondlife.TestClient
TestClient client = new TestClient(this);
+ // Optimize the throttle
+ client.Throttle.Wind = 0;
+ client.Throttle.Cloud = 0;
+ client.Throttle.Land = 1000000;
+ client.Throttle.Task = 1000000;
+
client.SimPrims = SimPrims;
client.Master = account.Master;
- if (this.startpos.sim != null)
+ if (!String.IsNullOrEmpty(this.startpos.sim))
{
if (this.startpos.x == 0 || this.startpos.y == 0 || this.startpos.z == 0)
{
diff --git a/libsecondlife/examples/TestClient/Commands/ParcelInfoCommand.cs b/libsecondlife/examples/TestClient/Commands/ParcelInfoCommand.cs
index 81ea339a..3221c609 100644
--- a/libsecondlife/examples/TestClient/Commands/ParcelInfoCommand.cs
+++ b/libsecondlife/examples/TestClient/Commands/ParcelInfoCommand.cs
@@ -8,7 +8,7 @@ namespace libsecondlife.TestClient
{
public class ParcelInfoCommand : Command
{
- private ParcelDownloader Parcels;
+ private ParcelDownloader ParcelDownloader;
private ManualResetEvent ParcelsDownloaded = new ManualResetEvent(false);
private int ParcelCount = 0;
@@ -17,14 +17,14 @@ namespace libsecondlife.TestClient
Name = "parcelinfo";
Description = "Prints out info about all the parcels in this simulator";
- Parcels = new ParcelDownloader(testClient);
- Parcels.OnParcelsDownloaded += new ParcelDownloader.ParcelsDownloadedCallback(Parcels_OnParcelsDownloaded);
+ ParcelDownloader = new ParcelDownloader(testClient);
+ ParcelDownloader.OnParcelsDownloaded += new ParcelDownloader.ParcelsDownloadedCallback(Parcels_OnParcelsDownloaded);
testClient.Network.OnDisconnected += new NetworkManager.DisconnectedCallback(Network_OnDisconnected);
}
public override string Execute(string[] args, LLUUID fromAgentID)
{
- Parcels.DownloadSimParcels(Client.Network.CurrentSim);
+ ParcelDownloader.DownloadSimParcels(Client.Network.CurrentSim);
ParcelsDownloaded.Reset();
ParcelsDownloaded.WaitOne(20000, false);
@@ -39,8 +39,10 @@ namespace libsecondlife.TestClient
{
foreach (KeyValuePair parcel in Parcels)
{
- Console.WriteLine("Parcels[{0}]: Name: \"{1}\", Description: \"{2}\" ACL Count: {3}", parcel.Key,
- parcel.Value.Name, parcel.Value.Desc, parcel.Value.AccessList.Count);
+ WaterType type = ParcelDownloader.GetWaterType(map, parcel.Value.LocalID);
+
+ Console.WriteLine("Parcels[{0}]: Name: \"{1}\", Description: \"{2}\" ACL Count: {3}, Location: {4}",
+ parcel.Key, parcel.Value.Name, parcel.Value.Desc, parcel.Value.AccessList.Count, type.ToString());
}
ParcelCount = Parcels.Count;
diff --git a/libsecondlife/examples/TestClient/Commands/RegionInfoCommand.cs b/libsecondlife/examples/TestClient/Commands/RegionInfoCommand.cs
new file mode 100644
index 00000000..750175fb
--- /dev/null
+++ b/libsecondlife/examples/TestClient/Commands/RegionInfoCommand.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Text;
+using libsecondlife;
+
+namespace libsecondlife.TestClient
+{
+ public class RegionInfoCommand : Command
+ {
+ public RegionInfoCommand(TestClient testClient)
+ {
+ Name = "regioninfo";
+ Description = "Prints out info about all the current region";
+ }
+
+ public override string Execute(string[] args, LLUUID fromAgentID)
+ {
+ StringBuilder output = new StringBuilder();
+ output.AppendLine(Client.Network.CurrentSim.ToString());
+ output.Append("Access: ");
+ output.AppendLine(Client.Network.CurrentSim.Access.ToString());
+ output.Append("Flags: ");
+ output.AppendLine(Client.Network.CurrentSim.Flags.ToString());
+ output.Append("TerrainBase0: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainBase0.ToStringHyphenated());
+ output.Append("TerrainBase1: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainBase1.ToStringHyphenated());
+ output.Append("TerrainBase2: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainBase2.ToStringHyphenated());
+ output.Append("TerrainBase3: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainBase3.ToStringHyphenated());
+ output.Append("TerrainDetail0: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainDetail0.ToStringHyphenated());
+ output.Append("TerrainDetail1: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainDetail1.ToStringHyphenated());
+ output.Append("TerrainDetail2: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainDetail2.ToStringHyphenated());
+ output.Append("TerrainDetail3: ");
+ output.AppendLine(Client.Network.CurrentSim.TerrainDetail3.ToStringHyphenated());
+ output.Append("Water Height: ");
+ output.AppendLine(Client.Network.CurrentSim.WaterHeight.ToString());
+
+ return output.ToString();
+ }
+ }
+}
diff --git a/libsecondlife/examples/TestClient/TestClient.csproj b/libsecondlife/examples/TestClient/TestClient.csproj
index c9870c71..a6153fec 100644
--- a/libsecondlife/examples/TestClient/TestClient.csproj
+++ b/libsecondlife/examples/TestClient/TestClient.csproj
@@ -71,6 +71,7 @@
Code
+
Code
diff --git a/libsecondlife/libsecondlife.Utilities/Utilities.cs b/libsecondlife/libsecondlife.Utilities/Utilities.cs
index c84c9332..d1b59bee 100644
--- a/libsecondlife/libsecondlife.Utilities/Utilities.cs
+++ b/libsecondlife/libsecondlife.Utilities/Utilities.cs
@@ -7,6 +7,21 @@ using libsecondlife.Packets;
namespace libsecondlife.Utilities
{
+ ///
+ ///
+ ///
+ public enum WaterType
+ {
+ ///
+ Unknown,
+ ///
+ Dry,
+ ///
+ Waterfront,
+ ///
+ Underwater
+ }
+
public static class Realism
{
public readonly static LLUUID TypingAnimation = new LLUUID("c541c47f-e0c0-058b-ad1a-d6ae3a4584d9");
@@ -91,14 +106,14 @@ namespace libsecondlife.Utilities
CheckTimer.Elapsed += new System.Timers.ElapsedEventHandler(CheckTimer_Elapsed);
}
- public static bool PersistentLogin(SecondLife client, string firstName, string lastName, string password,
- string userAgent, string author)
+ public static bool PersistentLogin(SecondLife client, string firstName, string lastName, string password,
+ string userAgent, string start, string author)
{
int unknownLogins = 0;
Start:
- if (client.Network.Login(firstName, lastName, password, userAgent, author))
+ if (client.Network.Login(firstName, lastName, password, userAgent, start, author))
{
client.Log("Logged in to " + client.Network.CurrentSim, Helpers.LogLevel.Info);
return true;
@@ -535,10 +550,8 @@ namespace libsecondlife.Utilities
/// Dictionary of 64x64 arrays of parcels which have been successfully downloaded
/// for each simulator (and their LocalID's, 0 = Null)
private Dictionary ParcelMarked = new Dictionary();
- ///
private Dictionary> Parcels = new Dictionary>();
-
- private ArrayList active_sims;
+ private List active_sims = new List();
///
/// Default constructor
@@ -549,8 +562,6 @@ namespace libsecondlife.Utilities
Client = client;
Client.Parcels.OnParcelProperties += new ParcelManager.ParcelPropertiesCallback(Parcels_OnParcelProperties);
Client.Parcels.OnAccessListReply += new ParcelManager.ParcelAccessListReplyCallback(Parcels_OnParcelAccessList);
-
- active_sims = new ArrayList();
}
public void DownloadSimParcels(Simulator simulator)
@@ -578,12 +589,104 @@ namespace libsecondlife.Utilities
Client.Parcels.PropertiesRequest(simulator, 0.0f, 0.0f, 0.0f, 0.0f, 0, false);
}
- private void Parcels_OnParcelAccessList(Simulator simulator, int sequenceID, int localID, uint flags,
- List accessEntries) {
- Parcels[simulator][localID].AccessList = accessEntries;
- }
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public WaterType GetWaterType(int[,] map, int localid)
+ {
+ if (!Client.Settings.STORE_LAND_PATCHES)
+ {
+ Client.Log("GetWaterType() will not work without Settings.STORE_LAND_PATCHES set to true",
+ Helpers.LogLevel.Error);
+ return WaterType.Unknown;
+ }
- private void Parcels_OnParcelProperties(Parcel parcel, ParcelManager.ParcelResult result, int sequenceID,
+ bool underwater = false;
+ bool abovewater = false;
+
+ for (int y = 0; y < 64; y++)
+ {
+ for (int x = 0; x < 64; x++)
+ {
+ if (map[y, x] == localid)
+ {
+ for (int y1 = 0; y1 < 4; y1++)
+ {
+ for (int x1 = 0; x1 < 4; x1++)
+ {
+ float height;
+ int tries = 0;
+
+ CheckHeight:
+ tries++;
+
+ if (Client.Terrain.TerrainHeightAtPoint(Client.Network.CurrentSim.Handle,
+ x * 4 + x1, y * 4 + y1, out height))
+ {
+ if (height < Client.Network.CurrentSim.WaterHeight)
+ {
+ underwater = true;
+ }
+ else
+ {
+ abovewater = true;
+ }
+ }
+ else if (tries > 4)
+ {
+ Console.WriteLine("Too many tries on this terrain block, skipping");
+ continue;
+ }
+ else
+ {
+ Console.WriteLine("Terrain height is null at {0},{1} retrying",
+ x * 4 + x1, y * 4 + y1);
+
+ // Terrain at this point hasn't been downloaded, move the camera to this spot
+ // and try again
+ Client.Self.Status.Camera.CameraCenter.X = (float)(x * 4 + x1);
+ Client.Self.Status.Camera.CameraCenter.Y = (float)(y * 4 + y1);
+ Client.Self.Status.Camera.CameraCenter.Z = Client.Self.Position.Z;
+ Client.Self.Status.SendUpdate(true);
+
+ Thread.Sleep(1000);
+ goto CheckHeight;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (underwater && abovewater)
+ {
+ return WaterType.Waterfront;
+ }
+ else if (abovewater)
+ {
+ return WaterType.Dry;
+ }
+ else if (underwater)
+ {
+ return WaterType.Underwater;
+ }
+ else
+ {
+ Client.Log("Error decoding terrain for parcel " + localid, Helpers.LogLevel.Error);
+ return WaterType.Unknown;
+ }
+ }
+
+ private void Parcels_OnParcelAccessList(Simulator simulator, int sequenceID, int localID, uint flags,
+ List accessEntries)
+ {
+ Parcels[simulator][localID].AccessList = accessEntries;
+ }
+
+ private void Parcels_OnParcelProperties(Parcel parcel, ParcelManager.ParcelResult result, int sequenceID,
bool snapSelection)
{
// Check if this is for a simulator we're concerned with
@@ -592,7 +695,7 @@ namespace libsecondlife.Utilities
// Warn about parcel property request errors and bail out
if (result == ParcelManager.ParcelResult.NoData)
{
- Client.Log("ParcelDownloader received a NoData response, sequenceID " + sequenceID,
+ Client.Log("ParcelDownloader received a NoData response, sequenceID " + sequenceID,
Helpers.LogLevel.Warning);
return;
}
@@ -600,46 +703,55 @@ namespace libsecondlife.Utilities
// Warn about unexpected data and bail out
if (!ParcelMarked.ContainsKey(parcel.Simulator))
{
- Client.Log("ParcelDownloader received unexpected parcel data for " + parcel.Simulator,
- Helpers.LogLevel.Info);
+ Client.Log("ParcelDownloader received unexpected parcel data for " + parcel.Simulator,
+ Helpers.LogLevel.Warning);
return;
}
- Client.Parcels.AccessListRequest(parcel.Simulator, parcel.LocalID, ParcelManager.AccessList.Ban, 0);
-
int x, y, index, bit;
int[,] markers = ParcelMarked[parcel.Simulator];
- Dictionary simParcels = Parcels[parcel.Simulator];
// Add this parcel to the dictionary of LocalID -> Parcel mappings
- lock (simParcels)
- if (!simParcels.ContainsKey(parcel.LocalID))
- simParcels[parcel.LocalID] = parcel;
+ lock (Parcels[parcel.Simulator])
+ if (!Parcels[parcel.Simulator].ContainsKey(parcel.LocalID))
+ Parcels[parcel.Simulator][parcel.LocalID] = parcel;
+
+ // Request the access list for this parcel
+ Client.Parcels.AccessListRequest(parcel.Simulator, parcel.LocalID,
+ ParcelManager.AccessList.Both, 0);
// Mark this area as downloaded
for (y = 0; y < 64; y++)
+ {
for (x = 0; x < 64; x++)
+ {
if (markers[y, x] == 0)
{
index = (y * 64) + x;
bit = index % 8;
index >>= 3;
- if ((parcel.Bitmap[index] & (1 << bit)) != 0)
- markers[y, x] = parcel.LocalID;
+ if ((parcel.Bitmap[index] & (1 << bit)) != 0)
+ markers[y, x] = parcel.LocalID;
}
+ }
+ }
// Request parcel information for the next missing area
for (y = 0; y < 64; y++)
+ {
for (x = 0; x < 64; x++)
+ {
if (markers[y, x] == 0)
{
Client.Parcels.PropertiesRequest(parcel.Simulator,
- (y+1) * 4.0f, (x+1) * 4.0f,
- y * 4.0f, x * 4.0f, 0, false);
+ (y + 1) * 4.0f, (x + 1) * 4.0f,
+ y * 4.0f, x * 4.0f, 0, false);
return;
}
+ }
+ }
// If we get here, there are no more zeroes in the markers map
lock (active_sims)
@@ -649,11 +761,10 @@ namespace libsecondlife.Utilities
if (OnParcelsDownloaded != null)
{
// This map is complete, fire callback
- try { OnParcelsDownloaded(parcel.Simulator, simParcels, markers); }
+ try { OnParcelsDownloaded(parcel.Simulator, Parcels[parcel.Simulator], markers); }
catch (Exception e) { Client.Log(e.ToString(), Helpers.LogLevel.Error); }
}
}
}
}
}
-