* Updating libsecondlife.dll to the latest version with a working LayerData function
* Reformatting some source files * Adding a try/catch sanity check around a phoning home check to osgrid.org * Updating the MSVC project file * Converted LayerData generation to use the functions built in to libsecondlife * Removing unused BitPack.cs and TerrainDecoder.cs files * Added a basic terrain generator (hills algorithm)adam
parent
5ebd471544
commit
0b6f8a02a7
Binary file not shown.
249
src/Config.cs
249
src/Config.cs
|
@ -36,128 +36,139 @@ using OpenSim.world;
|
||||||
|
|
||||||
namespace OpenSim
|
namespace OpenSim
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class handles connection to the underlying database used for configuration of the region.
|
/// This class handles connection to the underlying database used for configuration of the region.
|
||||||
/// Region content is also stored by this class. The main entry point is InitConfig() which attempts to locate
|
/// Region content is also stored by this class. The main entry point is InitConfig() which attempts to locate
|
||||||
/// opensim.yap in the current working directory. If opensim.yap can not be found, default settings are loaded from
|
/// opensim.yap in the current working directory. If opensim.yap can not be found, default settings are loaded from
|
||||||
/// what is hardcoded here and then saved into opensim.yap for future startups.
|
/// what is hardcoded here and then saved into opensim.yap for future startups.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SimConfig
|
public class SimConfig
|
||||||
{
|
{
|
||||||
public string RegionName;
|
public string RegionName;
|
||||||
|
|
||||||
public uint RegionLocX;
|
|
||||||
public uint RegionLocY;
|
|
||||||
public ulong RegionHandle;
|
|
||||||
|
|
||||||
public int IPListenPort;
|
|
||||||
public string IPListenAddr;
|
|
||||||
|
|
||||||
public bool sandbox;
|
|
||||||
public string AssetURL="";
|
|
||||||
public string AssetSendKey="";
|
|
||||||
|
|
||||||
public string GridURL="";
|
|
||||||
public string GridSendKey="";
|
|
||||||
|
|
||||||
private IObjectContainer db;
|
public uint RegionLocX;
|
||||||
|
public uint RegionLocY;
|
||||||
public void LoadDefaults() {
|
public ulong RegionHandle;
|
||||||
string tempstring;
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings");
|
|
||||||
|
|
||||||
this.RegionName=OpenSim_Main.localcons.CmdPrompt("Name [OpenSim test]: ","OpenSim test");
|
|
||||||
this.RegionLocX=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location X [997]: ","997"));
|
|
||||||
this.RegionLocY=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location Y [996]: ","996"));
|
|
||||||
this.IPListenPort=Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("UDP port for client connections [9000]: ","9000"));
|
|
||||||
this.IPListenAddr=OpenSim_Main.localcons.CmdPrompt("IP Address to listen on for client connections [127.0.0.1]: ","127.0.0.1");
|
|
||||||
|
|
||||||
|
|
||||||
tempstring=OpenSim_Main.localcons.CmdPrompt("Run in sandbox or grid mode? [sandbox]: ","sandbox", "sandbox", "grid");
|
|
||||||
if(tempstring=="grid"){
|
|
||||||
this.sandbox = false;
|
|
||||||
} else if(tempstring=="sandbox"){
|
|
||||||
this.sandbox=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.sandbox) {
|
public int IPListenPort;
|
||||||
this.AssetURL=OpenSim_Main.localcons.CmdPrompt("Asset server URL: ");
|
public string IPListenAddr;
|
||||||
this.AssetSendKey=OpenSim_Main.localcons.CmdPrompt("Asset server key: ");
|
|
||||||
this.GridURL=OpenSim_Main.localcons.CmdPrompt("Grid server URL: ");
|
|
||||||
this.GridSendKey=OpenSim_Main.localcons.CmdPrompt("Grid server key: ");
|
|
||||||
}
|
|
||||||
this.RegionHandle = Helpers.UIntsToLong((RegionLocX*256), (RegionLocY*256));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InitConfig() {
|
public bool sandbox = true;
|
||||||
try {
|
public string AssetURL = String.Empty;
|
||||||
db = Db4oFactory.OpenFile("opensim.yap");
|
public string AssetSendKey = String.Empty;
|
||||||
IObjectSet result = db.Get(typeof(SimConfig));
|
|
||||||
if(result.Count==1) {
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading");
|
|
||||||
foreach (SimConfig cfg in result) {
|
|
||||||
this.sandbox = cfg.sandbox;
|
|
||||||
this.RegionName = cfg.RegionName;
|
|
||||||
this.RegionLocX = cfg.RegionLocX;
|
|
||||||
this.RegionLocY = cfg.RegionLocY;
|
|
||||||
this.RegionHandle = Helpers.UIntsToLong((RegionLocX*256), (RegionLocY*256));
|
|
||||||
this.IPListenPort = cfg.IPListenPort;
|
|
||||||
this.IPListenAddr = cfg.IPListenAddr;
|
|
||||||
this.AssetURL = cfg.AssetURL;
|
|
||||||
this.AssetSendKey = cfg.AssetSendKey;
|
|
||||||
this.GridURL = cfg.GridURL;
|
|
||||||
this.GridSendKey = cfg.GridSendKey;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults");
|
|
||||||
LoadDefaults();
|
|
||||||
OpenSim_Main.localcons.WriteLine("Writing out default settings to local database");
|
|
||||||
db.Set(this);
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
db.Close();
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Exception occured");
|
|
||||||
OpenSim_Main.localcons.WriteLine(e.ToString());
|
|
||||||
}
|
|
||||||
OpenSim_Main.localcons.WriteLine("Sim settings loaded:");
|
|
||||||
OpenSim_Main.localcons.WriteLine("Name: " + this.RegionName);
|
|
||||||
OpenSim_Main.localcons.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]");
|
|
||||||
OpenSim_Main.localcons.WriteLine("Region Handle: " + this.RegionHandle.ToString());
|
|
||||||
OpenSim_Main.localcons.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort);
|
|
||||||
OpenSim_Main.localcons.WriteLine("Sandbox Mode? " + this.sandbox.ToString());
|
|
||||||
OpenSim_Main.localcons.WriteLine("Asset URL: " + this.AssetURL);
|
|
||||||
OpenSim_Main.localcons.WriteLine("Asset key: " + this.AssetSendKey);
|
|
||||||
OpenSim_Main.localcons.WriteLine("Grid URL: " + this.GridURL);
|
|
||||||
OpenSim_Main.localcons.WriteLine("Grid key: " + this.GridSendKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public World LoadWorld() {
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Loading world....");
|
|
||||||
World blank = new World();
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Looking for a heightmap in local DB");
|
|
||||||
IObjectSet world_result = db.Get(new float[65536]);
|
|
||||||
if(world_result.Count>0) {
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Found a heightmap in local database, loading");
|
|
||||||
blank.LandMap=(float[])world_result.Next();
|
|
||||||
} else {
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - No heightmap found, generating new one");
|
|
||||||
for(int i =0; i < 65536; i++) {
|
|
||||||
blank.LandMap[i] = 21.4989f;
|
|
||||||
}
|
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Saving heightmap to local database");
|
|
||||||
db.Set(blank.LandMap);
|
|
||||||
db.Commit();
|
|
||||||
}
|
|
||||||
return blank;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadFromGrid() {
|
public string GridURL = String.Empty;
|
||||||
OpenSim_Main.localcons.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!");
|
public string GridSendKey = String.Empty;
|
||||||
// TODO: Make this crap work
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Shutdown() {
|
private IObjectContainer db;
|
||||||
db.Close();
|
|
||||||
}
|
public void LoadDefaults()
|
||||||
}
|
{
|
||||||
|
string tempstring;
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings");
|
||||||
|
|
||||||
|
this.RegionName = OpenSim_Main.localcons.CmdPrompt("Name [OpenSim test]: ", "OpenSim test");
|
||||||
|
this.RegionLocX = (uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location X [997]: ", "997"));
|
||||||
|
this.RegionLocY = (uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location Y [996]: ", "996"));
|
||||||
|
this.IPListenPort = Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("UDP port for client connections [9000]: ", "9000"));
|
||||||
|
this.IPListenAddr = OpenSim_Main.localcons.CmdPrompt("IP Address to listen on for client connections [127.0.0.1]: ", "127.0.0.1");
|
||||||
|
|
||||||
|
tempstring = OpenSim_Main.localcons.CmdPrompt("Run in sandbox or grid mode? [sandbox]: ", "sandbox", "sandbox", "grid");
|
||||||
|
this.sandbox = tempstring.Equals("sandbox");
|
||||||
|
|
||||||
|
if (!this.sandbox)
|
||||||
|
{
|
||||||
|
this.AssetURL = OpenSim_Main.localcons.CmdPrompt("Asset server URL: ");
|
||||||
|
this.AssetSendKey = OpenSim_Main.localcons.CmdPrompt("Asset server key: ");
|
||||||
|
this.GridURL = OpenSim_Main.localcons.CmdPrompt("Grid server URL: ");
|
||||||
|
this.GridSendKey = OpenSim_Main.localcons.CmdPrompt("Grid server key: ");
|
||||||
|
}
|
||||||
|
this.RegionHandle = Helpers.UIntsToLong((RegionLocX * 256), (RegionLocY * 256));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitConfig()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
db = Db4oFactory.OpenFile("opensim.yap");
|
||||||
|
IObjectSet result = db.Get(typeof(SimConfig));
|
||||||
|
if (result.Count == 1)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading");
|
||||||
|
foreach (SimConfig cfg in result)
|
||||||
|
{
|
||||||
|
this.sandbox = cfg.sandbox;
|
||||||
|
this.RegionName = cfg.RegionName;
|
||||||
|
this.RegionLocX = cfg.RegionLocX;
|
||||||
|
this.RegionLocY = cfg.RegionLocY;
|
||||||
|
this.RegionHandle = Helpers.UIntsToLong((RegionLocX * 256), (RegionLocY * 256));
|
||||||
|
this.IPListenPort = cfg.IPListenPort;
|
||||||
|
this.IPListenAddr = cfg.IPListenAddr;
|
||||||
|
this.AssetURL = cfg.AssetURL;
|
||||||
|
this.AssetSendKey = cfg.AssetSendKey;
|
||||||
|
this.GridURL = cfg.GridURL;
|
||||||
|
this.GridSendKey = cfg.GridSendKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults");
|
||||||
|
LoadDefaults();
|
||||||
|
OpenSim_Main.localcons.WriteLine("Writing out default settings to local database");
|
||||||
|
db.Set(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
db.Close();
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Exception occured");
|
||||||
|
OpenSim_Main.localcons.WriteLine(e.ToString());
|
||||||
|
}
|
||||||
|
OpenSim_Main.localcons.WriteLine("Sim settings loaded:");
|
||||||
|
OpenSim_Main.localcons.WriteLine("Name: " + this.RegionName);
|
||||||
|
OpenSim_Main.localcons.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]");
|
||||||
|
OpenSim_Main.localcons.WriteLine("Region Handle: " + this.RegionHandle.ToString());
|
||||||
|
OpenSim_Main.localcons.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort);
|
||||||
|
OpenSim_Main.localcons.WriteLine("Sandbox Mode? " + this.sandbox.ToString());
|
||||||
|
OpenSim_Main.localcons.WriteLine("Asset URL: " + this.AssetURL);
|
||||||
|
OpenSim_Main.localcons.WriteLine("Asset key: " + this.AssetSendKey);
|
||||||
|
OpenSim_Main.localcons.WriteLine("Grid URL: " + this.GridURL);
|
||||||
|
OpenSim_Main.localcons.WriteLine("Grid key: " + this.GridSendKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public World LoadWorld()
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Loading world....");
|
||||||
|
World blank = new World();
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Looking for a heightmap in local DB");
|
||||||
|
IObjectSet world_result = db.Get(new float[65536]);
|
||||||
|
if (world_result.Count > 0)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Found a heightmap in local database, loading");
|
||||||
|
blank.LandMap = (float[])world_result.Next();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - No heightmap found, generating new one");
|
||||||
|
HeightmapGenHills hills = new HeightmapGenHills();
|
||||||
|
blank.LandMap = hills.GenerateHeightmap(200, 4.0f, 80.0f, false);
|
||||||
|
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Saving heightmap to local database");
|
||||||
|
db.Set(blank.LandMap);
|
||||||
|
db.Commit();
|
||||||
|
}
|
||||||
|
return blank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadFromGrid()
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!");
|
||||||
|
// TODO: Make this crap work
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
db.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,425 +37,474 @@ using System.Timers;
|
||||||
|
|
||||||
namespace OpenSim
|
namespace OpenSim
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles new client connections
|
/// Handles new client connections
|
||||||
/// Constructor takes a single Packet and authenticates everything
|
/// Constructor takes a single Packet and authenticates everything
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OpenSimClient {
|
public class OpenSimClient
|
||||||
|
{
|
||||||
public LLUUID AgentID;
|
|
||||||
public LLUUID SessionID;
|
|
||||||
public uint CircuitCode;
|
|
||||||
public world.Avatar ClientAvatar;
|
|
||||||
private UseCircuitCodePacket cirpack;
|
|
||||||
private Thread ClientThread;
|
|
||||||
public EndPoint userEP;
|
|
||||||
private BlockingQueue<QueItem> PacketQueue;
|
|
||||||
private BlockingQueue<TransferRequestPacket> AssetRequests;
|
|
||||||
private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
|
|
||||||
private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
|
|
||||||
private System.Timers.Timer AckTimer;
|
|
||||||
private uint Sequence = 0;
|
|
||||||
private object SequenceLock = new object();
|
|
||||||
private const int MAX_APPENDED_ACKS = 10;
|
|
||||||
private const int RESEND_TIMEOUT = 4000;
|
|
||||||
private const int MAX_SEQUENCE = 0xFFFFFF;
|
|
||||||
private Queue<uint> Inbox;
|
|
||||||
|
|
||||||
public void ack_pack(Packet Pack) {
|
|
||||||
//libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
|
|
||||||
//ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
|
|
||||||
//ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
|
|
||||||
//ack_it.Packets[0].ID = Pack.Header.ID;
|
|
||||||
//ack_it.Header.Reliable = false;
|
|
||||||
|
|
||||||
//OutPacket(ack_it);
|
public LLUUID AgentID;
|
||||||
|
public LLUUID SessionID;
|
||||||
if (Pack.Header.Reliable) {
|
public uint CircuitCode;
|
||||||
lock (PendingAcks) {
|
public world.Avatar ClientAvatar;
|
||||||
uint sequence = (uint)Pack.Header.Sequence;
|
private UseCircuitCodePacket cirpack;
|
||||||
if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
|
private Thread ClientThread;
|
||||||
}
|
public EndPoint userEP;
|
||||||
}
|
private BlockingQueue<QueItem> PacketQueue;
|
||||||
}
|
private BlockingQueue<TransferRequestPacket> AssetRequests;
|
||||||
|
private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
|
||||||
public void AssetLoader() {
|
private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
|
||||||
if(OpenSim_Main.cfg.sandbox==false) {
|
private System.Timers.Timer AckTimer;
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread");
|
private uint Sequence = 0;
|
||||||
TransferRequestPacket reqPacket = AssetRequests.Dequeue();
|
private object SequenceLock = new object();
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it");
|
private const int MAX_APPENDED_ACKS = 10;
|
||||||
LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0);
|
private const int RESEND_TIMEOUT = 4000;
|
||||||
WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data");
|
private const int MAX_SEQUENCE = 0xFFFFFF;
|
||||||
WebResponse AssetResponse = AssetLoad.GetResponse();
|
//private Queue<uint> Inbox;
|
||||||
byte[] idata = new byte[(int)AssetResponse.ContentLength];
|
|
||||||
BinaryReader br = new BinaryReader(AssetResponse.GetResponseStream());
|
|
||||||
idata = br.ReadBytes((int)AssetResponse.ContentLength);
|
|
||||||
br.Close();
|
|
||||||
|
|
||||||
TransferInfoPacket Transfer = new TransferInfoPacket();
|
|
||||||
Transfer.TransferInfo.ChannelType = 2;
|
|
||||||
Transfer.TransferInfo.Status = 0;
|
|
||||||
Transfer.TransferInfo.TargetType = 0;
|
|
||||||
Transfer.TransferInfo.Params = reqPacket.TransferInfo.Params;
|
|
||||||
Transfer.TransferInfo.Size = (int)AssetResponse.ContentLength;
|
|
||||||
Transfer.TransferInfo.TransferID = reqPacket.TransferInfo.TransferID;
|
|
||||||
|
|
||||||
OutPacket(Transfer);
|
|
||||||
|
|
||||||
TransferPacketPacket TransferPacket = new TransferPacketPacket();
|
|
||||||
TransferPacket.TransferData.Packet = 0;
|
|
||||||
TransferPacket.TransferData.ChannelType = 2;
|
|
||||||
TransferPacket.TransferData.TransferID=reqPacket.TransferInfo.TransferID;
|
|
||||||
|
|
||||||
if(AssetResponse.ContentLength>1000) {
|
|
||||||
byte[] chunk = new byte[1000];
|
|
||||||
Array.Copy(idata,chunk,1000);
|
|
||||||
TransferPacket.TransferData.Data = chunk;
|
|
||||||
TransferPacket.TransferData.Status = 0;
|
|
||||||
OutPacket(TransferPacket);
|
|
||||||
|
|
||||||
TransferPacket = new TransferPacketPacket();
|
|
||||||
TransferPacket.TransferData.Packet = 1;
|
|
||||||
TransferPacket.TransferData.ChannelType = 2;
|
|
||||||
TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID;
|
|
||||||
byte[] chunk1 = new byte[(idata.Length-1000)];
|
|
||||||
Array.Copy(idata, 1000, chunk1, 0, chunk1.Length);
|
|
||||||
TransferPacket.TransferData.Data = chunk1;
|
|
||||||
TransferPacket.TransferData.Status = 1;
|
|
||||||
OutPacket(TransferPacket);
|
|
||||||
} else {
|
|
||||||
TransferPacket.TransferData.Status = 1;
|
|
||||||
TransferPacket.TransferData.Data = idata;
|
|
||||||
OutPacket(TransferPacket);
|
|
||||||
}
|
|
||||||
AssetResponse.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Logout() {
|
|
||||||
// TODO - kill any AssetLoaders
|
|
||||||
ClientThread.Abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ProcessInPacket(Packet Pack) {
|
|
||||||
ack_pack(Pack);
|
|
||||||
switch(Pack.Type) {
|
|
||||||
case PacketType.CompleteAgentMovement:
|
|
||||||
ClientAvatar.CompleteMovement(OpenSim_Main.local_world);
|
|
||||||
ClientAvatar.SendInitialPosition();
|
|
||||||
break;
|
|
||||||
case PacketType.RegionHandshakeReply:
|
|
||||||
OpenSim_Main.local_world.SendLayerData(this);
|
|
||||||
break;
|
|
||||||
case PacketType.AgentWearablesRequest:
|
|
||||||
ClientAvatar.SendInitialAppearance();
|
|
||||||
break;
|
|
||||||
case PacketType.TransferRequest:
|
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
|
|
||||||
// We put transfer requests into a big queue and then spawn a thread for each new one
|
|
||||||
TransferRequestPacket transfer = (TransferRequestPacket)Pack;
|
|
||||||
AssetRequests.Enqueue(transfer);
|
|
||||||
Thread AssetLoaderThread = new Thread(new ThreadStart(AssetLoader));
|
|
||||||
AssetLoaderThread.Start();
|
|
||||||
break;
|
|
||||||
case PacketType.LogoutRequest:
|
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
|
|
||||||
lock(OpenSim_Main.local_world.Entities) {
|
|
||||||
OpenSim_Main.local_world.Entities.Remove(this.AgentID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(OpenSim_Main.cfg.sandbox==false) {
|
|
||||||
WebRequest DeleteSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + this.AgentID.ToString() + this.CircuitCode.ToString() + "/delete");
|
|
||||||
WebResponse GridResponse = DeleteSession.GetResponse();
|
|
||||||
StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
|
|
||||||
String grTest = sr.ReadLine();
|
|
||||||
sr.Close();
|
|
||||||
GridResponse.Close();
|
|
||||||
OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest);
|
|
||||||
}
|
|
||||||
this.ClientThread.Abort();
|
|
||||||
break;
|
|
||||||
case PacketType.AgentUpdate:
|
|
||||||
ClientAvatar.HandleAgentUpdate((AgentUpdatePacket)Pack);
|
|
||||||
break;
|
|
||||||
case PacketType.ChatFromViewer:
|
|
||||||
ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
|
|
||||||
if(Helpers.FieldToString(inchatpack.ChatData.Message)=="") break;
|
|
||||||
|
|
||||||
System.Text.Encoding _enc = System.Text.Encoding.ASCII;
|
public void ack_pack(Packet Pack)
|
||||||
libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
|
{
|
||||||
reply.ChatData.Audible = 1;
|
//libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
|
||||||
reply.ChatData.Message = inchatpack.ChatData.Message;
|
//ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
|
||||||
reply.ChatData.ChatType = 1;
|
//ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
|
||||||
reply.ChatData.SourceType = 1;
|
//ack_it.Packets[0].ID = Pack.Header.ID;
|
||||||
reply.ChatData.Position = this.ClientAvatar.position;
|
//ack_it.Header.Reliable = false;
|
||||||
reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0");
|
|
||||||
reply.ChatData.OwnerID = this.AgentID;
|
//OutPacket(ack_it);
|
||||||
reply.ChatData.SourceID = this.AgentID;
|
|
||||||
|
if (Pack.Header.Reliable)
|
||||||
|
{
|
||||||
|
lock (PendingAcks)
|
||||||
|
{
|
||||||
|
uint sequence = (uint)Pack.Header.Sequence;
|
||||||
|
if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssetLoader()
|
||||||
|
{
|
||||||
|
if (OpenSim_Main.cfg.sandbox == false)
|
||||||
|
{
|
||||||
|
WebResponse AssetResponse;
|
||||||
|
byte[] idata;
|
||||||
|
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread");
|
||||||
|
TransferRequestPacket reqPacket = AssetRequests.Dequeue();
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it");
|
||||||
|
LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data");
|
||||||
|
AssetResponse = AssetLoad.GetResponse();
|
||||||
|
idata = new byte[(int)AssetResponse.ContentLength];
|
||||||
|
BinaryReader br = new BinaryReader(AssetResponse.GetResponseStream());
|
||||||
|
idata = br.ReadBytes((int)AssetResponse.ContentLength);
|
||||||
|
br.Close();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferInfoPacket Transfer = new TransferInfoPacket();
|
||||||
|
Transfer.TransferInfo.ChannelType = 2;
|
||||||
|
Transfer.TransferInfo.Status = 0;
|
||||||
|
Transfer.TransferInfo.TargetType = 0;
|
||||||
|
Transfer.TransferInfo.Params = reqPacket.TransferInfo.Params;
|
||||||
|
Transfer.TransferInfo.Size = (int)AssetResponse.ContentLength;
|
||||||
|
Transfer.TransferInfo.TransferID = reqPacket.TransferInfo.TransferID;
|
||||||
|
|
||||||
|
OutPacket(Transfer);
|
||||||
|
|
||||||
|
TransferPacketPacket TransferPacket = new TransferPacketPacket();
|
||||||
|
TransferPacket.TransferData.Packet = 0;
|
||||||
|
TransferPacket.TransferData.ChannelType = 2;
|
||||||
|
TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID;
|
||||||
|
|
||||||
|
if (AssetResponse.ContentLength > 1000)
|
||||||
|
{
|
||||||
|
byte[] chunk = new byte[1000];
|
||||||
|
Array.Copy(idata, chunk, 1000);
|
||||||
|
TransferPacket.TransferData.Data = chunk;
|
||||||
|
TransferPacket.TransferData.Status = 0;
|
||||||
|
OutPacket(TransferPacket);
|
||||||
|
|
||||||
|
TransferPacket = new TransferPacketPacket();
|
||||||
|
TransferPacket.TransferData.Packet = 1;
|
||||||
|
TransferPacket.TransferData.ChannelType = 2;
|
||||||
|
TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID;
|
||||||
|
byte[] chunk1 = new byte[(idata.Length - 1000)];
|
||||||
|
Array.Copy(idata, 1000, chunk1, 0, chunk1.Length);
|
||||||
|
TransferPacket.TransferData.Data = chunk1;
|
||||||
|
TransferPacket.TransferData.Status = 1;
|
||||||
|
OutPacket(TransferPacket);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TransferPacket.TransferData.Status = 1;
|
||||||
|
TransferPacket.TransferData.Data = idata;
|
||||||
|
OutPacket(TransferPacket);
|
||||||
|
}
|
||||||
|
AssetResponse.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Logout()
|
||||||
|
{
|
||||||
|
// TODO - kill any AssetLoaders
|
||||||
|
ClientThread.Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessInPacket(Packet Pack)
|
||||||
|
{
|
||||||
|
ack_pack(Pack);
|
||||||
|
switch (Pack.Type)
|
||||||
|
{
|
||||||
|
case PacketType.CompleteAgentMovement:
|
||||||
|
ClientAvatar.CompleteMovement(OpenSim_Main.local_world);
|
||||||
|
ClientAvatar.SendInitialPosition();
|
||||||
|
break;
|
||||||
|
case PacketType.RegionHandshakeReply:
|
||||||
|
OpenSim_Main.local_world.SendLayerData(this);
|
||||||
|
break;
|
||||||
|
case PacketType.AgentWearablesRequest:
|
||||||
|
ClientAvatar.SendInitialAppearance();
|
||||||
|
break;
|
||||||
|
case PacketType.TransferRequest:
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request");
|
||||||
|
// We put transfer requests into a big queue and then spawn a thread for each new one
|
||||||
|
TransferRequestPacket transfer = (TransferRequestPacket)Pack;
|
||||||
|
AssetRequests.Enqueue(transfer);
|
||||||
|
Thread AssetLoaderThread = new Thread(new ThreadStart(AssetLoader));
|
||||||
|
AssetLoaderThread.Start();
|
||||||
|
break;
|
||||||
|
case PacketType.LogoutRequest:
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request");
|
||||||
|
lock (OpenSim_Main.local_world.Entities)
|
||||||
|
{
|
||||||
|
OpenSim_Main.local_world.Entities.Remove(this.AgentID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OpenSim_Main.cfg.sandbox == false)
|
||||||
|
{
|
||||||
|
WebRequest DeleteSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + this.AgentID.ToString() + this.CircuitCode.ToString() + "/delete");
|
||||||
|
WebResponse GridResponse = DeleteSession.GetResponse();
|
||||||
|
StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
|
||||||
|
String grTest = sr.ReadLine();
|
||||||
|
sr.Close();
|
||||||
|
GridResponse.Close();
|
||||||
|
OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest);
|
||||||
|
}
|
||||||
|
this.ClientThread.Abort();
|
||||||
|
break;
|
||||||
|
case PacketType.AgentUpdate:
|
||||||
|
ClientAvatar.HandleAgentUpdate((AgentUpdatePacket)Pack);
|
||||||
|
break;
|
||||||
|
case PacketType.ChatFromViewer:
|
||||||
|
ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack;
|
||||||
|
if (Helpers.FieldToString(inchatpack.ChatData.Message) == "") break;
|
||||||
|
|
||||||
|
System.Text.Encoding _enc = System.Text.Encoding.ASCII;
|
||||||
|
libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket();
|
||||||
|
reply.ChatData.Audible = 1;
|
||||||
|
reply.ChatData.Message = inchatpack.ChatData.Message;
|
||||||
|
reply.ChatData.ChatType = 1;
|
||||||
|
reply.ChatData.SourceType = 1;
|
||||||
|
reply.ChatData.Position = this.ClientAvatar.position;
|
||||||
|
reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0");
|
||||||
|
reply.ChatData.OwnerID = this.AgentID;
|
||||||
|
reply.ChatData.SourceID = this.AgentID;
|
||||||
|
|
||||||
|
|
||||||
foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) {
|
|
||||||
client.OutPacket(reply);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResendUnacked()
|
foreach (OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values)
|
||||||
{
|
{
|
||||||
int now = Environment.TickCount;
|
client.OutPacket(reply);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock (NeedAck)
|
private void ResendUnacked()
|
||||||
{
|
{
|
||||||
foreach (Packet packet in NeedAck.Values)
|
int now = Environment.TickCount;
|
||||||
{
|
|
||||||
if (now - packet.TickCount > RESEND_TIMEOUT)
|
|
||||||
{
|
|
||||||
|
|
||||||
packet.Header.Resent = true;
|
lock (NeedAck)
|
||||||
OutPacket(packet);
|
{
|
||||||
}
|
foreach (Packet packet in NeedAck.Values)
|
||||||
}
|
{
|
||||||
}
|
if (now - packet.TickCount > RESEND_TIMEOUT)
|
||||||
}
|
{
|
||||||
|
|
||||||
private void SendAcks()
|
packet.Header.Resent = true;
|
||||||
{
|
OutPacket(packet);
|
||||||
lock (PendingAcks)
|
}
|
||||||
{
|
}
|
||||||
if (PendingAcks.Count > 0)
|
}
|
||||||
{
|
}
|
||||||
if (PendingAcks.Count > 250)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int i = 0;
|
private void SendAcks()
|
||||||
PacketAckPacket acks = new PacketAckPacket();
|
{
|
||||||
acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
|
lock (PendingAcks)
|
||||||
|
{
|
||||||
foreach (uint ack in PendingAcks.Values)
|
if (PendingAcks.Count > 0)
|
||||||
{
|
{
|
||||||
acks.Packets[i] = new PacketAckPacket.PacketsBlock();
|
if (PendingAcks.Count > 250)
|
||||||
acks.Packets[i].ID = ack;
|
{
|
||||||
i++;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
acks.Header.Reliable = false;
|
|
||||||
OutPacket(acks);
|
|
||||||
|
|
||||||
PendingAcks.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
|
|
||||||
{
|
|
||||||
SendAcks();
|
|
||||||
ResendUnacked();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ProcessOutPacket(Packet Pack) {
|
|
||||||
|
|
||||||
// Keep track of when this packet was sent out
|
|
||||||
Pack.TickCount = Environment.TickCount;
|
|
||||||
|
|
||||||
if (!Pack.Header.Resent)
|
|
||||||
{
|
|
||||||
// Set the sequence number
|
|
||||||
lock (SequenceLock)
|
|
||||||
{
|
|
||||||
if (Sequence >= MAX_SEQUENCE)
|
|
||||||
Sequence = 1;
|
|
||||||
else
|
|
||||||
Sequence++;
|
|
||||||
Pack.Header.Sequence = Sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Pack.Header.Reliable) //DIRTY HACK
|
|
||||||
{
|
|
||||||
lock (NeedAck)
|
|
||||||
{
|
|
||||||
if (!NeedAck.ContainsKey(Pack.Header.Sequence))
|
|
||||||
{
|
|
||||||
NeedAck.Add(Pack.Header.Sequence, Pack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Client.Log("Attempted to add a duplicate sequence number (" +
|
|
||||||
// packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
|
|
||||||
// packet.Type.ToString(), Helpers.LogLevel.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't append ACKs to resent packets, in case that's what was causing the
|
|
||||||
// delivery to fail
|
|
||||||
if (!Pack.Header.Resent)
|
|
||||||
{
|
|
||||||
// Append any ACKs that need to be sent out to this packet
|
|
||||||
lock (PendingAcks)
|
|
||||||
{
|
|
||||||
if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
|
|
||||||
Pack.Type != PacketType.PacketAck &&
|
|
||||||
Pack.Type != PacketType.LogoutRequest)
|
|
||||||
{
|
|
||||||
Pack.Header.AckList = new uint[PendingAcks.Count];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
foreach (uint ack in PendingAcks.Values)
|
|
||||||
{
|
|
||||||
Pack.Header.AckList[i] = ack;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingAcks.Clear();
|
|
||||||
Pack.Header.AppendedAcks = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
byte[] ZeroOutBuffer = new byte[4096];
|
|
||||||
byte[] sendbuffer;
|
|
||||||
sendbuffer = Pack.ToBytes();
|
|
||||||
|
|
||||||
try {
|
int i = 0;
|
||||||
if (Pack.Header.Zerocoded) {
|
PacketAckPacket acks = new PacketAckPacket();
|
||||||
int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
|
acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
|
||||||
OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None,userEP);
|
|
||||||
} else {
|
|
||||||
OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None,userEP);
|
|
||||||
}
|
|
||||||
} catch (Exception) {
|
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
|
|
||||||
ClientThread.Abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InPacket(Packet NewPack) {
|
foreach (uint ack in PendingAcks.Values)
|
||||||
// Handle appended ACKs
|
{
|
||||||
if (NewPack.Header.AppendedAcks)
|
acks.Packets[i] = new PacketAckPacket.PacketsBlock();
|
||||||
{
|
acks.Packets[i].ID = ack;
|
||||||
lock (NeedAck)
|
i++;
|
||||||
{
|
}
|
||||||
foreach (uint ack in NewPack.Header.AckList)
|
|
||||||
{
|
|
||||||
OpenSim_Main.localcons.WriteLine("Got appended ack: "+ack);
|
|
||||||
NeedAck.Remove(ack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle PacketAck packets
|
acks.Header.Reliable = false;
|
||||||
if (NewPack.Type == PacketType.PacketAck)
|
OutPacket(acks);
|
||||||
{
|
|
||||||
PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
|
|
||||||
|
|
||||||
lock (NeedAck)
|
PendingAcks.Clear();
|
||||||
{
|
}
|
||||||
foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
|
}
|
||||||
{
|
}
|
||||||
NeedAck.Remove(block.ID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if( ( NewPack.Type == PacketType.StartPingCheck ) ) {
|
|
||||||
//reply to pingcheck
|
|
||||||
libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
|
|
||||||
libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
|
|
||||||
endPing.PingID.PingID = startPing.PingID.PingID;
|
|
||||||
OutPacket(endPing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QueItem item = new QueItem();
|
|
||||||
item.Packet = NewPack;
|
|
||||||
item.Incoming = true;
|
|
||||||
this.PacketQueue.Enqueue(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OutPacket(Packet NewPack) {
|
private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
|
||||||
QueItem item = new QueItem();
|
{
|
||||||
item.Packet = NewPack;
|
SendAcks();
|
||||||
item.Incoming = false;
|
ResendUnacked();
|
||||||
this.PacketQueue.Enqueue(item);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) {
|
public void ProcessOutPacket(Packet Pack)
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
|
{
|
||||||
cirpack = initialcirpack;
|
|
||||||
userEP = remoteEP;
|
|
||||||
PacketQueue = new BlockingQueue<QueItem>();
|
|
||||||
AssetRequests = new BlockingQueue<TransferRequestPacket>();
|
|
||||||
AckTimer = new System.Timers.Timer(500);
|
|
||||||
AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
|
|
||||||
AckTimer.Start();
|
|
||||||
|
|
||||||
ClientThread = new Thread(new ThreadStart(AuthUser));
|
// Keep track of when this packet was sent out
|
||||||
ClientThread.IsBackground = true;
|
Pack.TickCount = Environment.TickCount;
|
||||||
ClientThread.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClientLoop() {
|
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
|
|
||||||
while(true) {
|
|
||||||
QueItem nextPacket = PacketQueue.Dequeue();
|
|
||||||
if(nextPacket.Incoming)
|
|
||||||
{
|
|
||||||
//is a incoming packet
|
|
||||||
ProcessInPacket(nextPacket.Packet);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//is a out going packet
|
|
||||||
ProcessOutPacket(nextPacket.Packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitNewClient() {
|
if (!Pack.Header.Resent)
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
|
{
|
||||||
OpenSim_Main.local_world.AddViewerAgent(this);
|
// Set the sequence number
|
||||||
world.Entity tempent=OpenSim_Main.local_world.Entities[this.AgentID];
|
lock (SequenceLock)
|
||||||
this.ClientAvatar=(world.Avatar)tempent;
|
{
|
||||||
}
|
if (Sequence >= MAX_SEQUENCE)
|
||||||
|
Sequence = 1;
|
||||||
private void AuthUser() {
|
else
|
||||||
if(OpenSim_Main.cfg.sandbox==false) {
|
Sequence++;
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid");
|
Pack.Header.Sequence = Sequence;
|
||||||
WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists");
|
}
|
||||||
OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL);
|
|
||||||
WebResponse GridResponse = CheckSession.GetResponse();
|
if (Pack.Header.Reliable) //DIRTY HACK
|
||||||
StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
|
{
|
||||||
String grTest = sr.ReadLine();
|
lock (NeedAck)
|
||||||
sr.Close();
|
{
|
||||||
GridResponse.Close();
|
if (!NeedAck.ContainsKey(Pack.Header.Sequence))
|
||||||
if(String.IsNullOrEmpty(grTest) || grTest.Equals("1")) { // YAY! Valid login
|
{
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
|
NeedAck.Add(Pack.Header.Sequence, Pack);
|
||||||
this.AgentID=cirpack.CircuitCode.ID;
|
}
|
||||||
this.SessionID=cirpack.CircuitCode.SessionID;
|
else
|
||||||
this.CircuitCode=cirpack.CircuitCode.Code;
|
{
|
||||||
InitNewClient();
|
// Client.Log("Attempted to add a duplicate sequence number (" +
|
||||||
ClientLoop();
|
// packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
|
||||||
} else { // Invalid
|
// packet.Type.ToString(), Helpers.LogLevel.Warning);
|
||||||
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
|
}
|
||||||
ClientThread.Abort();
|
}
|
||||||
}
|
|
||||||
} else {
|
// Don't append ACKs to resent packets, in case that's what was causing the
|
||||||
this.AgentID=cirpack.CircuitCode.ID;
|
// delivery to fail
|
||||||
this.SessionID=cirpack.CircuitCode.SessionID;
|
if (!Pack.Header.Resent)
|
||||||
this.CircuitCode=cirpack.CircuitCode.Code;
|
{
|
||||||
InitNewClient();
|
// Append any ACKs that need to be sent out to this packet
|
||||||
ClientLoop();
|
lock (PendingAcks)
|
||||||
}
|
{
|
||||||
}
|
if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
|
||||||
}
|
Pack.Type != PacketType.PacketAck &&
|
||||||
|
Pack.Type != PacketType.LogoutRequest)
|
||||||
|
{
|
||||||
|
Pack.Header.AckList = new uint[PendingAcks.Count];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
foreach (uint ack in PendingAcks.Values)
|
||||||
|
{
|
||||||
|
Pack.Header.AckList[i] = ack;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PendingAcks.Clear();
|
||||||
|
Pack.Header.AppendedAcks = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
byte[] ZeroOutBuffer = new byte[4096];
|
||||||
|
byte[] sendbuffer;
|
||||||
|
sendbuffer = Pack.ToBytes();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Pack.Header.Zerocoded)
|
||||||
|
{
|
||||||
|
int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
|
||||||
|
OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None, userEP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None, userEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
|
||||||
|
ClientThread.Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InPacket(Packet NewPack)
|
||||||
|
{
|
||||||
|
// Handle appended ACKs
|
||||||
|
if (NewPack.Header.AppendedAcks)
|
||||||
|
{
|
||||||
|
lock (NeedAck)
|
||||||
|
{
|
||||||
|
foreach (uint ack in NewPack.Header.AckList)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("Got appended ack: " + ack);
|
||||||
|
NeedAck.Remove(ack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle PacketAck packets
|
||||||
|
if (NewPack.Type == PacketType.PacketAck)
|
||||||
|
{
|
||||||
|
PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
|
||||||
|
|
||||||
|
lock (NeedAck)
|
||||||
|
{
|
||||||
|
foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
|
||||||
|
{
|
||||||
|
NeedAck.Remove(block.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((NewPack.Type == PacketType.StartPingCheck))
|
||||||
|
{
|
||||||
|
//reply to pingcheck
|
||||||
|
libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
|
||||||
|
libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
|
||||||
|
endPing.PingID.PingID = startPing.PingID.PingID;
|
||||||
|
OutPacket(endPing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QueItem item = new QueItem();
|
||||||
|
item.Packet = NewPack;
|
||||||
|
item.Incoming = true;
|
||||||
|
this.PacketQueue.Enqueue(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OutPacket(Packet NewPack)
|
||||||
|
{
|
||||||
|
QueItem item = new QueItem();
|
||||||
|
item.Packet = NewPack;
|
||||||
|
item.Incoming = false;
|
||||||
|
this.PacketQueue.Enqueue(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request");
|
||||||
|
cirpack = initialcirpack;
|
||||||
|
userEP = remoteEP;
|
||||||
|
PacketQueue = new BlockingQueue<QueItem>();
|
||||||
|
AssetRequests = new BlockingQueue<TransferRequestPacket>();
|
||||||
|
AckTimer = new System.Timers.Timer(500);
|
||||||
|
AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
|
||||||
|
AckTimer.Start();
|
||||||
|
|
||||||
|
ClientThread = new Thread(new ThreadStart(AuthUser));
|
||||||
|
ClientThread.IsBackground = true;
|
||||||
|
ClientThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientLoop()
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop");
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
QueItem nextPacket = PacketQueue.Dequeue();
|
||||||
|
if (nextPacket.Incoming)
|
||||||
|
{
|
||||||
|
//is a incoming packet
|
||||||
|
ProcessInPacket(nextPacket.Packet);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//is a out going packet
|
||||||
|
ProcessOutPacket(nextPacket.Packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitNewClient()
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
|
||||||
|
OpenSim_Main.local_world.AddViewerAgent(this);
|
||||||
|
world.Entity tempent = OpenSim_Main.local_world.Entities[this.AgentID];
|
||||||
|
this.ClientAvatar = (world.Avatar)tempent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AuthUser()
|
||||||
|
{
|
||||||
|
if (OpenSim_Main.cfg.sandbox == false)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid");
|
||||||
|
WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists");
|
||||||
|
OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL);
|
||||||
|
WebResponse GridResponse = CheckSession.GetResponse();
|
||||||
|
StreamReader sr = new StreamReader(GridResponse.GetResponseStream());
|
||||||
|
String grTest = sr.ReadLine();
|
||||||
|
sr.Close();
|
||||||
|
GridResponse.Close();
|
||||||
|
if (String.IsNullOrEmpty(grTest) || grTest.Equals("1"))
|
||||||
|
{ // YAY! Valid login
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
|
||||||
|
this.AgentID = cirpack.CircuitCode.ID;
|
||||||
|
this.SessionID = cirpack.CircuitCode.SessionID;
|
||||||
|
this.CircuitCode = cirpack.CircuitCode.Code;
|
||||||
|
InitNewClient();
|
||||||
|
ClientLoop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // Invalid
|
||||||
|
OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
|
||||||
|
ClientThread.Abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.AgentID = cirpack.CircuitCode.ID;
|
||||||
|
this.SessionID = cirpack.CircuitCode.SessionID;
|
||||||
|
this.CircuitCode = cirpack.CircuitCode.Code;
|
||||||
|
InitNewClient();
|
||||||
|
ClientLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,19 +46,19 @@
|
||||||
<Compile Include="Config.cs" />
|
<Compile Include="Config.cs" />
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="OpenSimClient.cs" />
|
<Compile Include="OpenSimClient.cs" />
|
||||||
<Compile Include="types\BitPack.cs" />
|
<Compile Include="ServerConsole.cs" />
|
||||||
<Compile Include="types\Mesh.cs" />
|
<Compile Include="types\Mesh.cs" />
|
||||||
<Compile Include="types\Triangle.cs" />
|
<Compile Include="types\Triangle.cs" />
|
||||||
<Compile Include="Util.cs" />
|
<Compile Include="Util.cs" />
|
||||||
<Compile Include="VersionInfo.cs" />
|
<Compile Include="VersionInfo.cs" />
|
||||||
<Compile Include="world\Avatar.cs" />
|
<Compile Include="world\Avatar.cs" />
|
||||||
<Compile Include="world\Entity.cs" />
|
<Compile Include="world\Entity.cs" />
|
||||||
|
<Compile Include="world\HeightmapGenHills.cs" />
|
||||||
<Compile Include="world\PhysicsEngine.cs" />
|
<Compile Include="world\PhysicsEngine.cs" />
|
||||||
<Compile Include="world\Primitive.cs" />
|
<Compile Include="world\Primitive.cs" />
|
||||||
<Compile Include="world\ScriptEngine.cs" />
|
<Compile Include="world\ScriptEngine.cs" />
|
||||||
<Compile Include="world\scripting\IScript.cs" />
|
<Compile Include="world\scripting\IScript.cs" />
|
||||||
<Compile Include="world\SurfacePatch.cs" />
|
<Compile Include="world\SurfacePatch.cs" />
|
||||||
<Compile Include="world\TerrainDecoder.cs" />
|
|
||||||
<Compile Include="world\World.cs" />
|
<Compile Include="world\World.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) OpenSim project, http://osgrid.org/
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the <organization> nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace OpenSim
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public class VersionInfo
|
||||||
|
{
|
||||||
|
public static string Version = "0.0.1-unofficial";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,138 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace OpenSim.types
|
|
||||||
{
|
|
||||||
/* New Method
|
|
||||||
*
|
|
||||||
* 1. Get all the individual bytes and their bitlength, put them in a dictionary
|
|
||||||
* 2. Mash together when wanted.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
public class Bits {
|
|
||||||
public byte[] data;
|
|
||||||
public int len;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class InverseBitPack
|
|
||||||
{
|
|
||||||
private List<Bits> bits;
|
|
||||||
|
|
||||||
public InverseBitPack()
|
|
||||||
{
|
|
||||||
bits = new List<Bits>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BitPack
|
|
||||||
{
|
|
||||||
private const int MAX_BITS = 8;
|
|
||||||
|
|
||||||
private byte[] Data;
|
|
||||||
private int bytePos;
|
|
||||||
private int bitPos;
|
|
||||||
|
|
||||||
public BitPack(byte[] data, int pos) // For libsl compatibility
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
bytePos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitPack() // Encoding version
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadData(byte[] data, int pos) {
|
|
||||||
Data = data;
|
|
||||||
bytePos = pos;
|
|
||||||
bitPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PackBitsArray(byte[] bits, int bitLen)
|
|
||||||
{
|
|
||||||
int offset = bitPos % MAX_BITS;
|
|
||||||
int i;
|
|
||||||
byte temp1;
|
|
||||||
byte temp2;
|
|
||||||
|
|
||||||
for (i = 0; i < bits.Length; i++)
|
|
||||||
{
|
|
||||||
int Byte = bits[i];
|
|
||||||
Byte <<= offset;
|
|
||||||
temp1 = (byte)(Byte & 0xFF);
|
|
||||||
temp2 = (byte)((Byte >> 8) & 0xFF);
|
|
||||||
|
|
||||||
Data[Data.Length - 1] |= temp1;
|
|
||||||
// Data
|
|
||||||
|
|
||||||
bitPos += bitLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float UnpackFloat()
|
|
||||||
{
|
|
||||||
byte[] output = UnpackBitsArray(32);
|
|
||||||
|
|
||||||
if (!BitConverter.IsLittleEndian) Array.Reverse(output);
|
|
||||||
return BitConverter.ToSingle(output, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int UnpackBits(int totalCount)
|
|
||||||
{
|
|
||||||
byte[] output = UnpackBitsArray(totalCount);
|
|
||||||
|
|
||||||
if (!BitConverter.IsLittleEndian) Array.Reverse(output);
|
|
||||||
return BitConverter.ToInt32(output, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] UnpackBitsArray(int totalCount)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
byte[] output = new byte[4];
|
|
||||||
int curBytePos = 0;
|
|
||||||
int curBitPos = 0;
|
|
||||||
|
|
||||||
while (totalCount > 0)
|
|
||||||
{
|
|
||||||
if (totalCount > MAX_BITS)
|
|
||||||
{
|
|
||||||
count = MAX_BITS;
|
|
||||||
totalCount -= MAX_BITS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = totalCount;
|
|
||||||
totalCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
// Shift the previous bits
|
|
||||||
output[curBytePos] <<= 1;
|
|
||||||
|
|
||||||
// Grab one bit
|
|
||||||
if ((Data[bytePos] & (0x80 >> bitPos++)) != 0)
|
|
||||||
++output[curBytePos];
|
|
||||||
|
|
||||||
--count;
|
|
||||||
++curBitPos;
|
|
||||||
|
|
||||||
if (bitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
bitPos = 0;
|
|
||||||
++bytePos;
|
|
||||||
}
|
|
||||||
if (curBitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
curBitPos = 0;
|
|
||||||
++curBytePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -226,8 +226,8 @@ namespace OpenSim.world
|
||||||
handshake.RegionInfo.TerrainStartHeight10 = 10;
|
handshake.RegionInfo.TerrainStartHeight10 = 10;
|
||||||
handshake.RegionInfo.TerrainStartHeight11 = 10;
|
handshake.RegionInfo.TerrainStartHeight11 = 10;
|
||||||
handshake.RegionInfo.SimAccess = 13;
|
handshake.RegionInfo.SimAccess = 13;
|
||||||
handshake.RegionInfo.WaterHeight = 5;
|
handshake.RegionInfo.WaterHeight = 20.0f;
|
||||||
handshake.RegionInfo.RegionFlags = 72458694;
|
handshake.RegionInfo.RegionFlags = 72458694; // TODO: WTF sirs? Use an enum!
|
||||||
handshake.RegionInfo.SimName = _enc.GetBytes(OpenSim_Main.cfg.RegionName + "\0");
|
handshake.RegionInfo.SimName = _enc.GetBytes(OpenSim_Main.cfg.RegionName + "\0");
|
||||||
handshake.RegionInfo.SimOwner = new LLUUID("00000000-0000-0000-0000-000000000000");
|
handshake.RegionInfo.SimOwner = new LLUUID("00000000-0000-0000-0000-000000000000");
|
||||||
handshake.RegionInfo.TerrainBase0 = new LLUUID("b8d3965a-ad78-bf43-699b-bff8eca6c975");
|
handshake.RegionInfo.TerrainBase0 = new LLUUID("b8d3965a-ad78-bf43-699b-bff8eca6c975");
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace libsecondlife
|
||||||
|
{
|
||||||
|
public class HeightmapGenHills
|
||||||
|
{
|
||||||
|
private Random Rand = new Random();
|
||||||
|
private int NumHills;
|
||||||
|
private float HillMin;
|
||||||
|
private float HillMax;
|
||||||
|
private bool Island;
|
||||||
|
private float[] heightmap;
|
||||||
|
|
||||||
|
public float[] GenerateHeightmap(int numHills, float hillMin, float hillMax, bool island)
|
||||||
|
{
|
||||||
|
NumHills = numHills;
|
||||||
|
HillMin = hillMin;
|
||||||
|
HillMax = hillMax;
|
||||||
|
Island = island;
|
||||||
|
|
||||||
|
heightmap = new float[256 * 256];
|
||||||
|
|
||||||
|
for (int i = 0; i < numHills; i++)
|
||||||
|
{
|
||||||
|
AddHill();
|
||||||
|
}
|
||||||
|
|
||||||
|
Normalize();
|
||||||
|
|
||||||
|
return heightmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddHill()
|
||||||
|
{
|
||||||
|
float x, y;
|
||||||
|
float radius = RandomRange(HillMin, HillMax);
|
||||||
|
|
||||||
|
if (Island)
|
||||||
|
{
|
||||||
|
// Which direction from the center of the map the hill is placed
|
||||||
|
float theta = RandomRange(0, 6.28f);
|
||||||
|
|
||||||
|
// How far from the center of the map to place the hill. The radius
|
||||||
|
// is subtracted from the range to prevent any part of the hill from
|
||||||
|
// reaching the edge of the map
|
||||||
|
float distance = RandomRange(radius / 2.0f, 128.0f - radius);
|
||||||
|
|
||||||
|
x = 128.0f + (float)Math.Cos(theta) * distance;
|
||||||
|
y = 128.0f + (float)Math.Sin(theta) * distance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = RandomRange(-radius, 256.0f + radius);
|
||||||
|
y = RandomRange(-radius, 256.0f + radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
float radiusSq = radius * radius;
|
||||||
|
float distSq;
|
||||||
|
float height;
|
||||||
|
|
||||||
|
int xMin = (int)(x - radius) - 1;
|
||||||
|
int xMax = (int)(x + radius) + 1;
|
||||||
|
if (xMin < 0) xMin = 0;
|
||||||
|
if (xMax > 255) xMax = 255;
|
||||||
|
|
||||||
|
int yMin = (int)(y - radius) - 1;
|
||||||
|
int yMax = (int)(y + radius) + 1;
|
||||||
|
if (yMin < 0) yMin = 0;
|
||||||
|
if (yMax > 255) yMax = 255;
|
||||||
|
|
||||||
|
// Loop through each affected cell and determine the height at that point
|
||||||
|
for (int v = yMin; v <= yMax; ++v)
|
||||||
|
{
|
||||||
|
float fv = (float)v;
|
||||||
|
|
||||||
|
for (int h = xMin; h <= xMax; ++h)
|
||||||
|
{
|
||||||
|
float fh = (float)h;
|
||||||
|
|
||||||
|
// Determine how far from the center of this hill this point is
|
||||||
|
distSq = (x - fh) * (x - fh) + (y - fv) * (y - fv);
|
||||||
|
height = radiusSq - distSq;
|
||||||
|
|
||||||
|
// Don't add negative hill values
|
||||||
|
if (height > 0.0f) heightmap[h + v * 256] += height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Normalize()
|
||||||
|
{
|
||||||
|
float min = heightmap[0];
|
||||||
|
float max = heightmap[0];
|
||||||
|
|
||||||
|
for (int x = 0; x < 256; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < 256; y++)
|
||||||
|
{
|
||||||
|
if (heightmap[x + y * 256] < min) min = heightmap[x + y * 256];
|
||||||
|
if (heightmap[x + y * 256] > max) max = heightmap[x + y * 256];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid a rare divide by zero
|
||||||
|
if (min != max)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 256; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < 256; y++)
|
||||||
|
{
|
||||||
|
heightmap[x + y * 256] = ((heightmap[x + y * 256] - min) / (max - min)) * (HillMax - HillMin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float RandomRange(float min, float max)
|
||||||
|
{
|
||||||
|
return (float)Rand.NextDouble() * (max - min) + min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,683 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) OpenSim project, http://sim.opensecondlife.org/
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* * Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* * Neither the name of the <organization> nor the
|
|
||||||
* names of its contributors may be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
//using libsecondlife;
|
|
||||||
using libsecondlife.Packets;
|
|
||||||
|
|
||||||
namespace OpenSim
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Description of TerrainDecoder.
|
|
||||||
/// </summary>
|
|
||||||
public class TerrainDecode
|
|
||||||
{
|
|
||||||
|
|
||||||
public enum LayerType : byte
|
|
||||||
{
|
|
||||||
Land = 0x4C,
|
|
||||||
Water = 0x57,
|
|
||||||
Wind = 0x37,
|
|
||||||
Cloud = 0x38
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct GroupHeader
|
|
||||||
{
|
|
||||||
public int Stride;
|
|
||||||
public int PatchSize;
|
|
||||||
public LayerType Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct PatchHeader
|
|
||||||
{
|
|
||||||
public float DCOffset;
|
|
||||||
public int Range;
|
|
||||||
public int QuantWBits;
|
|
||||||
public int PatchIDs;
|
|
||||||
public uint WordBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Patch
|
|
||||||
{
|
|
||||||
public float[] Heightmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="simulator"></param>
|
|
||||||
/// <param name="x"></param>
|
|
||||||
/// <param name="y"></param>
|
|
||||||
/// <param name="width"></param>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
// public delegate void LandPatchCallback(Simulator simulator, int x, int y, int width, float[] data);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
//public event LandPatchCallback OnLandPatch;
|
|
||||||
|
|
||||||
private Random RandomClass = new Random();
|
|
||||||
|
|
||||||
private const byte END_OF_PATCHES = 97;
|
|
||||||
private const int PATCHES_PER_EDGE = 16;
|
|
||||||
private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
|
|
||||||
|
|
||||||
//private SecondLife Client;
|
|
||||||
private Dictionary<ulong, Patch[]> SimPatches = new Dictionary<ulong, Patch[]>();
|
|
||||||
private float[] DequantizeTable16 = new float[16 * 16];
|
|
||||||
private float[] DequantizeTable32 = new float[32 * 32];
|
|
||||||
private float[] ICosineTable16 = new float[16 * 16];
|
|
||||||
private float[] ICosineTable32 = new float[32 * 32];
|
|
||||||
private int[] DeCopyMatrix16 = new int[16 * 16];
|
|
||||||
private int[] DeCopyMatrix32 = new int[32 * 32];
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="client"></param>
|
|
||||||
public TerrainDecode()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Initialize the decompression tables
|
|
||||||
BuildDequantizeTable16();
|
|
||||||
BuildDequantizeTable32();
|
|
||||||
SetupICosines16();
|
|
||||||
SetupICosines32();
|
|
||||||
BuildDecopyMatrix16();
|
|
||||||
BuildDecopyMatrix32();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void BuildDequantizeTable16()
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 16; j++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
DequantizeTable16[j * 16 + i] = 1.0f + 2.0f * (float)(i + j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildDequantizeTable32()
|
|
||||||
{
|
|
||||||
for (int j = 0; j < 32; j++)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 32; i++)
|
|
||||||
{
|
|
||||||
DequantizeTable32[j * 32 + i] = 1.0f + 2.0f * (float)(i + j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupICosines16()
|
|
||||||
{
|
|
||||||
const float hposz = (float)Math.PI * 0.5f / 16.0f;
|
|
||||||
|
|
||||||
for (int u = 0; u < 16; u++)
|
|
||||||
{
|
|
||||||
for (int n = 0; n < 16; n++)
|
|
||||||
{
|
|
||||||
ICosineTable16[u * 16 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetupICosines32()
|
|
||||||
{
|
|
||||||
const float hposz = (float)Math.PI * 0.5f / 32.0f;
|
|
||||||
|
|
||||||
for (int u = 0; u < 32; u++)
|
|
||||||
{
|
|
||||||
for (int n = 0; n < 32; n++)
|
|
||||||
{
|
|
||||||
ICosineTable32[u * 32 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildDecopyMatrix16()
|
|
||||||
{
|
|
||||||
bool diag = false;
|
|
||||||
bool right = true;
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while (i < 16 && j < 16)
|
|
||||||
{
|
|
||||||
DeCopyMatrix16[j * 16 + i] = count++;
|
|
||||||
|
|
||||||
if (!diag)
|
|
||||||
{
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
if (i < 16 - 1) i++;
|
|
||||||
else j++;
|
|
||||||
|
|
||||||
right = false;
|
|
||||||
diag = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (j < 16 - 1) j++;
|
|
||||||
else i++;
|
|
||||||
|
|
||||||
right = true;
|
|
||||||
diag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
j--;
|
|
||||||
if (i == 16 - 1 || j == 0) diag = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
j++;
|
|
||||||
if (j == 16 - 1 || i == 0) diag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BuildDecopyMatrix32()
|
|
||||||
{
|
|
||||||
bool diag = false;
|
|
||||||
bool right = true;
|
|
||||||
int i = 0;
|
|
||||||
int j = 0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
while (i < 32 && j < 32)
|
|
||||||
{
|
|
||||||
DeCopyMatrix32[j * 32 + i] = count++;
|
|
||||||
|
|
||||||
if (!diag)
|
|
||||||
{
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
if (i < 32 - 1) i++;
|
|
||||||
else j++;
|
|
||||||
|
|
||||||
right = false;
|
|
||||||
diag = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (j < 32 - 1) j++;
|
|
||||||
else i++;
|
|
||||||
|
|
||||||
right = true;
|
|
||||||
diag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
j--;
|
|
||||||
if (i == 32 - 1 || j == 0) diag = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i--;
|
|
||||||
j++;
|
|
||||||
if (j == 32 - 1 || i == 0) diag = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EncodePatchHeader(BitPacker bitpack, PatchHeader header)
|
|
||||||
{
|
|
||||||
bitpack.PackBits(header.QuantWBits,8);
|
|
||||||
|
|
||||||
if (header.QuantWBits == END_OF_PATCHES)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bitpack.PackFloat(header.DCOffset);
|
|
||||||
bitpack.PackBits(header.Range,16);
|
|
||||||
bitpack.PackBits(header.PatchIDs,10);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DCTLine16(float[] In, float[] Out, int line)
|
|
||||||
{
|
|
||||||
int N =16;
|
|
||||||
int lineSize = line * 16;
|
|
||||||
|
|
||||||
for(int k = 0; k < N;k++)
|
|
||||||
{
|
|
||||||
float sum = 0.0f;
|
|
||||||
for(int n = 0; n < N; n++)
|
|
||||||
{
|
|
||||||
float num = (float)(Math.PI*k*(2.0f*n+1)/(2*N));
|
|
||||||
float cosine = (float)Math.Cos(num);
|
|
||||||
float product = In[lineSize +n] * cosine;
|
|
||||||
sum += product;
|
|
||||||
}
|
|
||||||
|
|
||||||
float alpha;
|
|
||||||
if(k == 0)
|
|
||||||
{
|
|
||||||
alpha = (float)(1.0f/Math.Sqrt(2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alpha = 1;
|
|
||||||
}
|
|
||||||
Out[lineSize + k] =(float)( sum * alpha );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void DCTColumn16(float[] In, float[] Out, int Column)
|
|
||||||
{
|
|
||||||
int N =16;
|
|
||||||
int uSize;
|
|
||||||
|
|
||||||
for(int k = 0; k < N; k++){
|
|
||||||
float sum = 0.0f;
|
|
||||||
for(int n = 0; n < N; n++)
|
|
||||||
{
|
|
||||||
uSize = n * 16;
|
|
||||||
float num = (float)(Math.PI*k*(2.0f*n+1)/(2*N));
|
|
||||||
float cosine = (float)Math.Cos(num);
|
|
||||||
float product = In[uSize + Column] * cosine;
|
|
||||||
sum += product;
|
|
||||||
}
|
|
||||||
|
|
||||||
float alpha;
|
|
||||||
if(k == 0)
|
|
||||||
{
|
|
||||||
alpha = (float)(1.0f/Math.Sqrt(2));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alpha = 1;
|
|
||||||
}
|
|
||||||
Out[16 * k + Column] = (float)( sum * alpha * (2.0f /N));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EncodePatch(int[] patches, BitPacker bitpack, int size)
|
|
||||||
{
|
|
||||||
int lastnum =0;
|
|
||||||
for(int n = 0; n < size * size; n++)
|
|
||||||
{
|
|
||||||
if(patches[n]!=0)
|
|
||||||
lastnum=n;
|
|
||||||
}
|
|
||||||
for (int n = 0; n < lastnum+1; n++)
|
|
||||||
{
|
|
||||||
if(patches[n] != 0)
|
|
||||||
{
|
|
||||||
bitpack.PackBits(1,1); //value or EOB
|
|
||||||
bitpack.PackBits(1,1); //value
|
|
||||||
if(patches[n] > 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
bitpack.PackBits(0,1); // positive
|
|
||||||
bitpack.PackBits(patches[n],13);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bitpack.PackBits(1,1); // negative
|
|
||||||
|
|
||||||
int temp = patches[n] * -1;
|
|
||||||
bitpack.PackBits(temp,13);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bitpack.PackBits(0,1); // no value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bitpack.PackBits(1,1); //value or EOB
|
|
||||||
bitpack.PackBits(0,1); // EOB
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] CompressPatch(float[] patches)
|
|
||||||
{
|
|
||||||
int size = 16;
|
|
||||||
float[] block = new float[size * size];
|
|
||||||
int[] output = new int[size * size];
|
|
||||||
int prequant = (139 >> 4) + 2;
|
|
||||||
int quantize = 1 << prequant;
|
|
||||||
float ooq = 1.0f / (float)quantize;
|
|
||||||
float mult = ooq * (float)1;
|
|
||||||
float addval = mult * (float)(1 << (prequant - 1)) + 20.4989f;
|
|
||||||
|
|
||||||
if (size == 16)
|
|
||||||
{
|
|
||||||
for (int n = 0; n < 16 * 16; n++)
|
|
||||||
{
|
|
||||||
block[n] = (float)((patches[n] - addval)/ mult);
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] ftemp = new float[32 * 32];
|
|
||||||
|
|
||||||
for (int o = 0; o < 16; o++)
|
|
||||||
this.DCTColumn16(block, ftemp, o);
|
|
||||||
for (int o = 0; o < 16; o++)
|
|
||||||
this.DCTLine16(ftemp, block, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = 0; j < block.Length; j++)
|
|
||||||
{
|
|
||||||
output[DeCopyMatrix16[j]] = (int)(block[j] / DequantizeTable16[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Packet CreateLayerPacket(float[] heightmap, int minX, int minY, int maxX, int maxY)
|
|
||||||
{
|
|
||||||
//int minX = 0, maxX = 2, minY = 0, maxY = 1; //these should be passed to this function
|
|
||||||
LayerDataPacket layer = new LayerDataPacket();
|
|
||||||
byte[] Encoded = new byte[2048];
|
|
||||||
layer.LayerID.Type = 76;
|
|
||||||
GroupHeader header = new GroupHeader();
|
|
||||||
header.Stride = 264;
|
|
||||||
header.PatchSize = 16;
|
|
||||||
header.Type = LayerType.Land;
|
|
||||||
BitPacker newpack = new BitPacker(Encoded,0);
|
|
||||||
newpack.PackBits(header.Stride,16);
|
|
||||||
newpack.PackBits(header.PatchSize,8);
|
|
||||||
newpack.PackBits((int)header.Type,8);
|
|
||||||
|
|
||||||
|
|
||||||
float[] height;
|
|
||||||
for(int y = minY; y< maxY; y++)
|
|
||||||
{
|
|
||||||
for(int x = minX ; x < maxX ; x++)
|
|
||||||
{
|
|
||||||
height = new float[256];
|
|
||||||
Array.Copy(heightmap, (4096 *y) +(x *256), height, 0, 256);
|
|
||||||
|
|
||||||
this.CreatePatch(height, newpack, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchHeader headers = new PatchHeader();
|
|
||||||
headers.QuantWBits = END_OF_PATCHES;
|
|
||||||
this.EncodePatchHeader(newpack, headers);
|
|
||||||
|
|
||||||
int lastused=0;
|
|
||||||
for(int i = 0; i < 2048 ; i++)
|
|
||||||
{
|
|
||||||
if(Encoded[i] !=0)
|
|
||||||
lastused = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = new byte[lastused+1];
|
|
||||||
Array.Copy(Encoded, data, lastused+1);
|
|
||||||
layer.LayerData.Data =data;
|
|
||||||
|
|
||||||
return(layer);
|
|
||||||
}
|
|
||||||
public void CreatePatch(float[] heightmap, BitPacker newpack, int x, int y)
|
|
||||||
{
|
|
||||||
PatchHeader header = new PatchHeader();
|
|
||||||
header.DCOffset = 20.4989f;
|
|
||||||
header.QuantWBits = 139;
|
|
||||||
header.Range = 1;
|
|
||||||
header.PatchIDs = (y & 0x1F);
|
|
||||||
header.PatchIDs += x <<5 ;
|
|
||||||
|
|
||||||
this.EncodePatchHeader(newpack, header);
|
|
||||||
|
|
||||||
int[] newpatch = this.CompressPatch(heightmap);
|
|
||||||
this.EncodePatch(newpatch, newpack, 16);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//***************************************************
|
|
||||||
public class BitPacker
|
|
||||||
{
|
|
||||||
private const int MAX_BITS = 8;
|
|
||||||
|
|
||||||
private byte[] Data;
|
|
||||||
public int bytePos;
|
|
||||||
public int bitPos;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default constructor, initialize the bit packer / bit unpacker
|
|
||||||
/// with a byte array and starting position
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Byte array to pack bits in to or unpack from</param>
|
|
||||||
/// <param name="pos">Starting position in the byte array</param>
|
|
||||||
public BitPacker(byte[] data, int pos)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
bytePos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pack a floating point value in to the data
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Floating point value to pack</param>
|
|
||||||
public void PackFloat(float data)
|
|
||||||
{
|
|
||||||
byte[] input = BitConverter.GetBytes(data);
|
|
||||||
PackBitArray(input, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pack part or all of an integer in to the data
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Integer containing the data to pack</param>
|
|
||||||
/// <param name="totalCount">Number of bits of the integer to pack</param>
|
|
||||||
public void PackBits(int data, int totalCount)
|
|
||||||
{
|
|
||||||
byte[] input = BitConverter.GetBytes(data);
|
|
||||||
PackBitArray(input, totalCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unpacking a floating point value from the data
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Unpacked floating point value</returns>
|
|
||||||
public float UnpackFloat()
|
|
||||||
{
|
|
||||||
byte[] output = UnpackBitsArray(32);
|
|
||||||
|
|
||||||
if (!BitConverter.IsLittleEndian) Array.Reverse(output);
|
|
||||||
return BitConverter.ToSingle(output, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unpack a variable number of bits from the data in to integer format
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="totalCount">Number of bits to unpack</param>
|
|
||||||
/// <returns>An integer containing the unpacked bits</returns>
|
|
||||||
/// <remarks>This function is only useful up to 32 bits</remarks>
|
|
||||||
public int UnpackBits(int totalCount)
|
|
||||||
{
|
|
||||||
byte[] output = UnpackBitsArray(totalCount);
|
|
||||||
|
|
||||||
if (!BitConverter.IsLittleEndian) Array.Reverse(output);
|
|
||||||
return BitConverter.ToInt32(output, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PackBitArray(byte[] data, int totalCount)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
int curBytePos = 0;
|
|
||||||
int curBitPos = 0;
|
|
||||||
|
|
||||||
while (totalCount > 0)
|
|
||||||
{
|
|
||||||
if (totalCount > (MAX_BITS ))
|
|
||||||
{
|
|
||||||
count = MAX_BITS ;
|
|
||||||
totalCount -= MAX_BITS ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = totalCount;
|
|
||||||
totalCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
switch(count)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if ((data[curBytePos] & (0x01)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if ((data[curBytePos] & (0x02)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ((data[curBytePos] & (0x04)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if ((data[curBytePos] & (0x08)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if ((data[curBytePos] & (0x10)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
if ((data[curBytePos] & (0x20)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
if ((data[curBytePos] & (0x40)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
if ((data[curBytePos] & (0x80)) != 0)
|
|
||||||
{
|
|
||||||
Data[bytePos] |= (byte)(0x80 >> bitPos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitPos++;
|
|
||||||
--count;
|
|
||||||
++curBitPos;
|
|
||||||
|
|
||||||
if (bitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
bitPos = 0;
|
|
||||||
++bytePos;
|
|
||||||
}
|
|
||||||
if (curBitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
curBitPos = 0;
|
|
||||||
++curBytePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private byte[] UnpackBitsArray(int totalCount)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
byte[] output = new byte[4];
|
|
||||||
int curBytePos = 0;
|
|
||||||
int curBitPos = 0;
|
|
||||||
|
|
||||||
while (totalCount > 0)
|
|
||||||
{
|
|
||||||
if (totalCount > MAX_BITS)
|
|
||||||
{
|
|
||||||
count = MAX_BITS;
|
|
||||||
totalCount -= MAX_BITS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = totalCount;
|
|
||||||
totalCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (count > 0)
|
|
||||||
{
|
|
||||||
// Shift the previous bits
|
|
||||||
output[curBytePos] <<= 1;
|
|
||||||
|
|
||||||
// Grab one bit
|
|
||||||
if ((Data[bytePos] & (0x80 >> bitPos++)) != 0)
|
|
||||||
++output[curBytePos];
|
|
||||||
|
|
||||||
--count;
|
|
||||||
++curBitPos;
|
|
||||||
|
|
||||||
if (bitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
bitPos = 0;
|
|
||||||
++bytePos;
|
|
||||||
}
|
|
||||||
if (curBitPos >= MAX_BITS)
|
|
||||||
{
|
|
||||||
curBitPos = 0;
|
|
||||||
++curBytePos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using libsecondlife;
|
|
||||||
using libsecondlife.Packets;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using libsecondlife;
|
||||||
|
using libsecondlife.Packets;
|
||||||
|
|
||||||
namespace OpenSim.world
|
namespace OpenSim.world
|
||||||
{
|
{
|
||||||
|
@ -12,77 +12,98 @@ namespace OpenSim.world
|
||||||
public Dictionary<libsecondlife.LLUUID, Entity> Entities;
|
public Dictionary<libsecondlife.LLUUID, Entity> Entities;
|
||||||
public float[] LandMap;
|
public float[] LandMap;
|
||||||
public ScriptEngine Scripts;
|
public ScriptEngine Scripts;
|
||||||
public TerrainDecode terrainengine = new TerrainDecode();
|
public uint _localNumber = 0;
|
||||||
public uint _localNumber=0;
|
public PhysicsEngine physics;
|
||||||
public PhysicsEngine physics;
|
|
||||||
|
private libsecondlife.TerrainManager TerrainManager;
|
||||||
private Random Rand = new Random();
|
private Random Rand = new Random();
|
||||||
|
|
||||||
public World()
|
public World()
|
||||||
{
|
{
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs - creating new entitities instance");
|
OpenSim_Main.localcons.WriteLine("World.cs - creating new entitities instance");
|
||||||
Entities = new Dictionary<libsecondlife.LLUUID, Entity>();
|
Entities = new Dictionary<libsecondlife.LLUUID, Entity>();
|
||||||
|
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs - creating LandMap");
|
OpenSim_Main.localcons.WriteLine("World.cs - creating LandMap");
|
||||||
terrainengine = new TerrainDecode();
|
TerrainManager = new TerrainManager(new SecondLife());
|
||||||
LandMap = new float[65536];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitLoop() {
|
public void InitLoop()
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs:StartLoop() - Initialising physics");
|
{
|
||||||
this.physics = new PhysicsEngine();
|
OpenSim_Main.localcons.WriteLine("World.cs:StartLoop() - Initialising physics");
|
||||||
physics.Startup();
|
this.physics = new PhysicsEngine();
|
||||||
}
|
physics.Startup();
|
||||||
|
}
|
||||||
public void DoStuff() {
|
|
||||||
lock(this) {
|
|
||||||
physics.DoStuff(this);
|
|
||||||
this.Update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update() {
|
public void DoStuff()
|
||||||
foreach (libsecondlife.LLUUID UUID in Entities.Keys)
|
{
|
||||||
|
lock (this)
|
||||||
{
|
{
|
||||||
if(Entities[UUID].needupdate) {
|
physics.DoStuff(this);
|
||||||
Entities[UUID].update();
|
this.Update();
|
||||||
|
|
||||||
if(Entities[UUID] is Avatar) {
|
|
||||||
Avatar avatar=(Avatar)Entities[UUID];
|
|
||||||
if((avatar.oldpos!=avatar.position) || (avatar.oldvel!=avatar.velocity) || avatar.walking) {
|
|
||||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = Entities[UUID].CreateTerseBlock();
|
|
||||||
foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) {
|
|
||||||
ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket();
|
|
||||||
terse.RegionData.RegionHandle = OpenSim_Main.cfg.RegionHandle; // FIXME
|
|
||||||
terse.RegionData.TimeDilation = 0;
|
|
||||||
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
|
|
||||||
terse.ObjectData[0] = terseBlock;
|
|
||||||
client.OutPacket(terse);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendLayerData(OpenSimClient RemoteClient) {
|
public void Update()
|
||||||
for(int x=0; x<16; x=x+4) for(int y=0; y<16; y++){
|
{
|
||||||
Packet layerpack=this.terrainengine.CreateLayerPacket(LandMap, x,y,x+4,y+1);
|
foreach (libsecondlife.LLUUID UUID in Entities.Keys)
|
||||||
RemoteClient.OutPacket(layerpack);
|
{
|
||||||
}
|
if (Entities[UUID].needupdate)
|
||||||
}
|
{
|
||||||
|
Entities[UUID].update();
|
||||||
|
|
||||||
public void AddViewerAgent(OpenSimClient AgentClient) {
|
if (Entities[UUID] is Avatar)
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent");
|
{
|
||||||
Avatar NewAvatar = new Avatar(AgentClient);
|
Avatar avatar = (Avatar)Entities[UUID];
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world");
|
if ((avatar.oldpos != avatar.position) || (avatar.oldvel != avatar.velocity) || avatar.walking)
|
||||||
this.Entities.Add(AgentClient.AgentID, NewAvatar);
|
{
|
||||||
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake ");
|
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = Entities[UUID].CreateTerseBlock();
|
||||||
NewAvatar.SendRegionHandshake(this);
|
foreach (OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values)
|
||||||
this.Update(); // will work for now, but needs to be optimised so we don't update everything in the sim for each new user
|
{
|
||||||
}
|
ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket();
|
||||||
|
terse.RegionData.RegionHandle = OpenSim_Main.cfg.RegionHandle; // FIXME
|
||||||
|
terse.RegionData.TimeDilation = 0;
|
||||||
|
terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
|
||||||
|
terse.ObjectData[0] = terseBlock;
|
||||||
|
client.OutPacket(terse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool Backup() {
|
public void SendLayerData(OpenSimClient RemoteClient)
|
||||||
|
{
|
||||||
|
int[] patches = new int[4];
|
||||||
|
|
||||||
|
for (int y = 0; y < 16; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < 16; x = x + 4)
|
||||||
|
{
|
||||||
|
patches[0] = x + 0 + y * 16;
|
||||||
|
patches[1] = x + 1 + y * 16;
|
||||||
|
patches[2] = x + 2 + y * 16;
|
||||||
|
patches[3] = x + 3 + y * 16;
|
||||||
|
|
||||||
|
Packet layerpack = TerrainManager.CreateLandPacket(LandMap, patches);
|
||||||
|
RemoteClient.OutPacket(layerpack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddViewerAgent(OpenSimClient AgentClient)
|
||||||
|
{
|
||||||
|
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent");
|
||||||
|
Avatar NewAvatar = new Avatar(AgentClient);
|
||||||
|
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world");
|
||||||
|
this.Entities.Add(AgentClient.AgentID, NewAvatar);
|
||||||
|
OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake ");
|
||||||
|
NewAvatar.SendRegionHandshake(this);
|
||||||
|
this.Update(); // will work for now, but needs to be optimised so we don't update everything in the sim for each new user
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Backup()
|
||||||
|
{
|
||||||
/* TODO: Save the current world entities state. */
|
/* TODO: Save the current world entities state. */
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue