diff options
Diffstat (limited to '')
-rw-r--r-- | src/Config.cs | 259 | ||||
-rw-r--r-- | src/OpenSimClient.cs | 889 | ||||
-rw-r--r-- | src/Second-server.csproj | 4 | ||||
-rw-r--r-- | src/VersionInfo.cs | 37 | ||||
-rw-r--r-- | src/types/BitPack.cs | 138 | ||||
-rw-r--r-- | src/world/Avatar.cs | 4 | ||||
-rw-r--r-- | src/world/HeightmapGenHills.cs | 122 | ||||
-rw-r--r-- | src/world/TerrainDecoder.cs | 683 | ||||
-rw-r--r-- | src/world/World.cs | 137 |
9 files changed, 846 insertions, 1427 deletions
diff --git a/src/Config.cs b/src/Config.cs index 90753ef..9bb9296 100644 --- a/src/Config.cs +++ b/src/Config.cs | |||
@@ -36,128 +36,139 @@ using OpenSim.world; | |||
36 | 36 | ||
37 | namespace OpenSim | 37 | namespace OpenSim |
38 | { | 38 | { |
39 | /// <summary> | 39 | /// <summary> |
40 | /// This class handles connection to the underlying database used for configuration of the region. | 40 | /// This class handles connection to the underlying database used for configuration of the region. |
41 | /// Region content is also stored by this class. The main entry point is InitConfig() which attempts to locate | 41 | /// Region content is also stored by this class. The main entry point is InitConfig() which attempts to locate |
42 | /// opensim.yap in the current working directory. If opensim.yap can not be found, default settings are loaded from | 42 | /// opensim.yap in the current working directory. If opensim.yap can not be found, default settings are loaded from |
43 | /// what is hardcoded here and then saved into opensim.yap for future startups. | 43 | /// what is hardcoded here and then saved into opensim.yap for future startups. |
44 | /// </summary> | 44 | /// </summary> |
45 | public class SimConfig | 45 | public class SimConfig |
46 | { | 46 | { |
47 | public string RegionName; | 47 | public string RegionName; |
48 | 48 | ||
49 | public uint RegionLocX; | 49 | public uint RegionLocX; |
50 | public uint RegionLocY; | 50 | public uint RegionLocY; |
51 | public ulong RegionHandle; | 51 | public ulong RegionHandle; |
52 | 52 | ||
53 | public int IPListenPort; | 53 | public int IPListenPort; |
54 | public string IPListenAddr; | 54 | public string IPListenAddr; |
55 | 55 | ||
56 | public bool sandbox; | 56 | public bool sandbox = true; |
57 | public string AssetURL=""; | 57 | public string AssetURL = String.Empty; |
58 | public string AssetSendKey=""; | 58 | public string AssetSendKey = String.Empty; |
59 | 59 | ||
60 | public string GridURL=""; | 60 | public string GridURL = String.Empty; |
61 | public string GridSendKey=""; | 61 | public string GridSendKey = String.Empty; |
62 | 62 | ||
63 | private IObjectContainer db; | 63 | private IObjectContainer db; |
64 | 64 | ||
65 | public void LoadDefaults() { | 65 | public void LoadDefaults() |
66 | string tempstring; | 66 | { |
67 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings"); | 67 | string tempstring; |
68 | 68 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadDefaults() - Please press enter to retain default or enter new settings"); | |
69 | this.RegionName=OpenSim_Main.localcons.CmdPrompt("Name [OpenSim test]: ","OpenSim test"); | 69 | |
70 | this.RegionLocX=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location X [997]: ","997")); | 70 | this.RegionName = OpenSim_Main.localcons.CmdPrompt("Name [OpenSim test]: ", "OpenSim test"); |
71 | this.RegionLocY=(uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location Y [996]: ","996")); | 71 | this.RegionLocX = (uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location X [997]: ", "997")); |
72 | this.IPListenPort=Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("UDP port for client connections [9000]: ","9000")); | 72 | this.RegionLocY = (uint)Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("Grid Location Y [996]: ", "996")); |
73 | this.IPListenAddr=OpenSim_Main.localcons.CmdPrompt("IP Address to listen on for client connections [127.0.0.1]: ","127.0.0.1"); | 73 | this.IPListenPort = Convert.ToInt32(OpenSim_Main.localcons.CmdPrompt("UDP port for client connections [9000]: ", "9000")); |
74 | 74 | this.IPListenAddr = OpenSim_Main.localcons.CmdPrompt("IP Address to listen on for client connections [127.0.0.1]: ", "127.0.0.1"); | |
75 | 75 | ||
76 | tempstring=OpenSim_Main.localcons.CmdPrompt("Run in sandbox or grid mode? [sandbox]: ","sandbox", "sandbox", "grid"); | 76 | tempstring = OpenSim_Main.localcons.CmdPrompt("Run in sandbox or grid mode? [sandbox]: ", "sandbox", "sandbox", "grid"); |
77 | if(tempstring=="grid"){ | 77 | this.sandbox = tempstring.Equals("sandbox"); |
78 | this.sandbox = false; | 78 | |
79 | } else if(tempstring=="sandbox"){ | 79 | if (!this.sandbox) |
80 | this.sandbox=true; | 80 | { |
81 | } | 81 | this.AssetURL = OpenSim_Main.localcons.CmdPrompt("Asset server URL: "); |
82 | 82 | this.AssetSendKey = OpenSim_Main.localcons.CmdPrompt("Asset server key: "); | |
83 | if(!this.sandbox) { | 83 | this.GridURL = OpenSim_Main.localcons.CmdPrompt("Grid server URL: "); |
84 | this.AssetURL=OpenSim_Main.localcons.CmdPrompt("Asset server URL: "); | 84 | this.GridSendKey = OpenSim_Main.localcons.CmdPrompt("Grid server key: "); |
85 | this.AssetSendKey=OpenSim_Main.localcons.CmdPrompt("Asset server key: "); | 85 | } |
86 | this.GridURL=OpenSim_Main.localcons.CmdPrompt("Grid server URL: "); | 86 | this.RegionHandle = Helpers.UIntsToLong((RegionLocX * 256), (RegionLocY * 256)); |
87 | this.GridSendKey=OpenSim_Main.localcons.CmdPrompt("Grid server key: "); | 87 | } |
88 | } | 88 | |
89 | this.RegionHandle = Helpers.UIntsToLong((RegionLocX*256), (RegionLocY*256)); | 89 | public void InitConfig() |
90 | } | 90 | { |
91 | 91 | try | |
92 | public void InitConfig() { | 92 | { |
93 | try { | 93 | db = Db4oFactory.OpenFile("opensim.yap"); |
94 | db = Db4oFactory.OpenFile("opensim.yap"); | 94 | IObjectSet result = db.Get(typeof(SimConfig)); |
95 | IObjectSet result = db.Get(typeof(SimConfig)); | 95 | if (result.Count == 1) |
96 | if(result.Count==1) { | 96 | { |
97 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading"); | 97 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Found a SimConfig object in the local database, loading"); |
98 | foreach (SimConfig cfg in result) { | 98 | foreach (SimConfig cfg in result) |
99 | this.sandbox = cfg.sandbox; | 99 | { |
100 | this.RegionName = cfg.RegionName; | 100 | this.sandbox = cfg.sandbox; |
101 | this.RegionLocX = cfg.RegionLocX; | 101 | this.RegionName = cfg.RegionName; |
102 | this.RegionLocY = cfg.RegionLocY; | 102 | this.RegionLocX = cfg.RegionLocX; |
103 | this.RegionHandle = Helpers.UIntsToLong((RegionLocX*256), (RegionLocY*256)); | 103 | this.RegionLocY = cfg.RegionLocY; |
104 | this.IPListenPort = cfg.IPListenPort; | 104 | this.RegionHandle = Helpers.UIntsToLong((RegionLocX * 256), (RegionLocY * 256)); |
105 | this.IPListenAddr = cfg.IPListenAddr; | 105 | this.IPListenPort = cfg.IPListenPort; |
106 | this.AssetURL = cfg.AssetURL; | 106 | this.IPListenAddr = cfg.IPListenAddr; |
107 | this.AssetSendKey = cfg.AssetSendKey; | 107 | this.AssetURL = cfg.AssetURL; |
108 | this.GridURL = cfg.GridURL; | 108 | this.AssetSendKey = cfg.AssetSendKey; |
109 | this.GridSendKey = cfg.GridSendKey; | 109 | this.GridURL = cfg.GridURL; |
110 | } | 110 | this.GridSendKey = cfg.GridSendKey; |
111 | } else { | 111 | } |
112 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults"); | 112 | } |
113 | LoadDefaults(); | 113 | else |
114 | OpenSim_Main.localcons.WriteLine("Writing out default settings to local database"); | 114 | { |
115 | db.Set(this); | 115 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Could not find object in database, loading precompiled defaults"); |
116 | } | 116 | LoadDefaults(); |
117 | } catch(Exception e) { | 117 | OpenSim_Main.localcons.WriteLine("Writing out default settings to local database"); |
118 | db.Close(); | 118 | db.Set(this); |
119 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Exception occured"); | 119 | } |
120 | OpenSim_Main.localcons.WriteLine(e.ToString()); | 120 | } |
121 | } | 121 | catch (Exception e) |
122 | OpenSim_Main.localcons.WriteLine("Sim settings loaded:"); | 122 | { |
123 | OpenSim_Main.localcons.WriteLine("Name: " + this.RegionName); | 123 | db.Close(); |
124 | OpenSim_Main.localcons.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]"); | 124 | OpenSim_Main.localcons.WriteLine("Config.cs:InitConfig() - Exception occured"); |
125 | OpenSim_Main.localcons.WriteLine("Region Handle: " + this.RegionHandle.ToString()); | 125 | OpenSim_Main.localcons.WriteLine(e.ToString()); |
126 | OpenSim_Main.localcons.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort); | 126 | } |
127 | OpenSim_Main.localcons.WriteLine("Sandbox Mode? " + this.sandbox.ToString()); | 127 | OpenSim_Main.localcons.WriteLine("Sim settings loaded:"); |
128 | OpenSim_Main.localcons.WriteLine("Asset URL: " + this.AssetURL); | 128 | OpenSim_Main.localcons.WriteLine("Name: " + this.RegionName); |
129 | OpenSim_Main.localcons.WriteLine("Asset key: " + this.AssetSendKey); | 129 | OpenSim_Main.localcons.WriteLine("Region Location: [" + this.RegionLocX.ToString() + "," + this.RegionLocY + "]"); |
130 | OpenSim_Main.localcons.WriteLine("Grid URL: " + this.GridURL); | 130 | OpenSim_Main.localcons.WriteLine("Region Handle: " + this.RegionHandle.ToString()); |
131 | OpenSim_Main.localcons.WriteLine("Grid key: " + this.GridSendKey); | 131 | OpenSim_Main.localcons.WriteLine("Listening on IP: " + this.IPListenAddr + ":" + this.IPListenPort); |
132 | } | 132 | OpenSim_Main.localcons.WriteLine("Sandbox Mode? " + this.sandbox.ToString()); |
133 | 133 | OpenSim_Main.localcons.WriteLine("Asset URL: " + this.AssetURL); | |
134 | public World LoadWorld() { | 134 | OpenSim_Main.localcons.WriteLine("Asset key: " + this.AssetSendKey); |
135 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Loading world...."); | 135 | OpenSim_Main.localcons.WriteLine("Grid URL: " + this.GridURL); |
136 | World blank = new World(); | 136 | OpenSim_Main.localcons.WriteLine("Grid key: " + this.GridSendKey); |
137 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Looking for a heightmap in local DB"); | 137 | } |
138 | IObjectSet world_result = db.Get(new float[65536]); | 138 | |
139 | if(world_result.Count>0) { | 139 | public World LoadWorld() |
140 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Found a heightmap in local database, loading"); | 140 | { |
141 | blank.LandMap=(float[])world_result.Next(); | 141 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Loading world...."); |
142 | } else { | 142 | World blank = new World(); |
143 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - No heightmap found, generating new one"); | 143 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Looking for a heightmap in local DB"); |
144 | for(int i =0; i < 65536; i++) { | 144 | IObjectSet world_result = db.Get(new float[65536]); |
145 | blank.LandMap[i] = 21.4989f; | 145 | if (world_result.Count > 0) |
146 | } | 146 | { |
147 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Saving heightmap to local database"); | 147 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Found a heightmap in local database, loading"); |
148 | db.Set(blank.LandMap); | 148 | blank.LandMap = (float[])world_result.Next(); |
149 | db.Commit(); | 149 | } |
150 | } | 150 | else |
151 | return blank; | 151 | { |
152 | } | 152 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - No heightmap found, generating new one"); |
153 | 153 | HeightmapGenHills hills = new HeightmapGenHills(); | |
154 | public void LoadFromGrid() { | 154 | blank.LandMap = hills.GenerateHeightmap(200, 4.0f, 80.0f, false); |
155 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!"); | 155 | |
156 | // TODO: Make this crap work | 156 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadWorld() - Saving heightmap to local database"); |
157 | } | 157 | db.Set(blank.LandMap); |
158 | 158 | db.Commit(); | |
159 | public void Shutdown() { | 159 | } |
160 | db.Close(); | 160 | return blank; |
161 | } | 161 | } |
162 | } | 162 | |
163 | public void LoadFromGrid() | ||
164 | { | ||
165 | OpenSim_Main.localcons.WriteLine("Config.cs:LoadFromGrid() - dummy function, DOING ABSOLUTELY NOTHING AT ALL!!!"); | ||
166 | // TODO: Make this crap work | ||
167 | } | ||
168 | |||
169 | public void Shutdown() | ||
170 | { | ||
171 | db.Close(); | ||
172 | } | ||
173 | } | ||
163 | } | 174 | } |
diff --git a/src/OpenSimClient.cs b/src/OpenSimClient.cs index 655ebfe..497df00 100644 --- a/src/OpenSimClient.cs +++ b/src/OpenSimClient.cs | |||
@@ -37,425 +37,474 @@ using System.Timers; | |||
37 | 37 | ||
38 | namespace OpenSim | 38 | namespace OpenSim |
39 | { | 39 | { |
40 | /// <summary> | 40 | /// <summary> |
41 | /// Handles new client connections | 41 | /// Handles new client connections |
42 | /// Constructor takes a single Packet and authenticates everything | 42 | /// Constructor takes a single Packet and authenticates everything |
43 | /// </summary> | 43 | /// </summary> |
44 | public class OpenSimClient { | 44 | public class OpenSimClient |
45 | 45 | { | |
46 | public LLUUID AgentID; | 46 | |
47 | public LLUUID SessionID; | 47 | public LLUUID AgentID; |
48 | public uint CircuitCode; | 48 | public LLUUID SessionID; |
49 | public world.Avatar ClientAvatar; | 49 | public uint CircuitCode; |
50 | private UseCircuitCodePacket cirpack; | 50 | public world.Avatar ClientAvatar; |
51 | private Thread ClientThread; | 51 | private UseCircuitCodePacket cirpack; |
52 | public EndPoint userEP; | 52 | private Thread ClientThread; |
53 | private BlockingQueue<QueItem> PacketQueue; | 53 | public EndPoint userEP; |
54 | private BlockingQueue<TransferRequestPacket> AssetRequests; | 54 | private BlockingQueue<QueItem> PacketQueue; |
55 | private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | 55 | private BlockingQueue<TransferRequestPacket> AssetRequests; |
56 | private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | 56 | private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); |
57 | private System.Timers.Timer AckTimer; | 57 | private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); |
58 | private uint Sequence = 0; | 58 | private System.Timers.Timer AckTimer; |
59 | private object SequenceLock = new object(); | 59 | private uint Sequence = 0; |
60 | private const int MAX_APPENDED_ACKS = 10; | 60 | private object SequenceLock = new object(); |
61 | private const int RESEND_TIMEOUT = 4000; | 61 | private const int MAX_APPENDED_ACKS = 10; |
62 | private const int MAX_SEQUENCE = 0xFFFFFF; | 62 | private const int RESEND_TIMEOUT = 4000; |
63 | private Queue<uint> Inbox; | 63 | private const int MAX_SEQUENCE = 0xFFFFFF; |
64 | 64 | //private Queue<uint> Inbox; | |
65 | public void ack_pack(Packet Pack) { | 65 | |
66 | //libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket(); | 66 | public void ack_pack(Packet Pack) |
67 | //ack_it.Packets = new PacketAckPacket.PacketsBlock[1]; | 67 | { |
68 | //ack_it.Packets[0] = new PacketAckPacket.PacketsBlock(); | 68 | //libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket(); |
69 | //ack_it.Packets[0].ID = Pack.Header.ID; | 69 | //ack_it.Packets = new PacketAckPacket.PacketsBlock[1]; |
70 | //ack_it.Header.Reliable = false; | 70 | //ack_it.Packets[0] = new PacketAckPacket.PacketsBlock(); |
71 | 71 | //ack_it.Packets[0].ID = Pack.Header.ID; | |
72 | //OutPacket(ack_it); | 72 | //ack_it.Header.Reliable = false; |
73 | 73 | ||
74 | if (Pack.Header.Reliable) { | 74 | //OutPacket(ack_it); |
75 | lock (PendingAcks) { | 75 | |
76 | uint sequence = (uint)Pack.Header.Sequence; | 76 | if (Pack.Header.Reliable) |
77 | if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; } | 77 | { |
78 | } | 78 | lock (PendingAcks) |
79 | } | 79 | { |
80 | } | 80 | uint sequence = (uint)Pack.Header.Sequence; |
81 | 81 | if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; } | |
82 | public void AssetLoader() { | 82 | } |
83 | if(OpenSim_Main.cfg.sandbox==false) { | 83 | } |
84 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread"); | 84 | } |
85 | TransferRequestPacket reqPacket = AssetRequests.Dequeue(); | 85 | |
86 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it"); | 86 | public void AssetLoader() |
87 | LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0); | 87 | { |
88 | WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data"); | 88 | if (OpenSim_Main.cfg.sandbox == false) |
89 | WebResponse AssetResponse = AssetLoad.GetResponse(); | 89 | { |
90 | byte[] idata = new byte[(int)AssetResponse.ContentLength]; | 90 | WebResponse AssetResponse; |
91 | BinaryReader br = new BinaryReader(AssetResponse.GetResponseStream()); | 91 | byte[] idata; |
92 | idata = br.ReadBytes((int)AssetResponse.ContentLength); | 92 | |
93 | br.Close(); | 93 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Starting new thread"); |
94 | 94 | TransferRequestPacket reqPacket = AssetRequests.Dequeue(); | |
95 | TransferInfoPacket Transfer = new TransferInfoPacket(); | 95 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AssetLoader() - Got a request, processing it"); |
96 | Transfer.TransferInfo.ChannelType = 2; | 96 | LLUUID AssetID = new LLUUID(reqPacket.TransferInfo.Params, 0); |
97 | Transfer.TransferInfo.Status = 0; | 97 | |
98 | Transfer.TransferInfo.TargetType = 0; | 98 | try |
99 | Transfer.TransferInfo.Params = reqPacket.TransferInfo.Params; | 99 | { |
100 | Transfer.TransferInfo.Size = (int)AssetResponse.ContentLength; | 100 | WebRequest AssetLoad = WebRequest.Create(OpenSim_Main.cfg.AssetURL + "getasset/" + OpenSim_Main.cfg.AssetSendKey + "/" + AssetID + "/data"); |
101 | Transfer.TransferInfo.TransferID = reqPacket.TransferInfo.TransferID; | 101 | AssetResponse = AssetLoad.GetResponse(); |
102 | 102 | idata = new byte[(int)AssetResponse.ContentLength]; | |
103 | OutPacket(Transfer); | 103 | BinaryReader br = new BinaryReader(AssetResponse.GetResponseStream()); |
104 | 104 | idata = br.ReadBytes((int)AssetResponse.ContentLength); | |
105 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); | 105 | br.Close(); |
106 | TransferPacket.TransferData.Packet = 0; | 106 | } |
107 | TransferPacket.TransferData.ChannelType = 2; | 107 | catch (Exception e) |
108 | TransferPacket.TransferData.TransferID=reqPacket.TransferInfo.TransferID; | 108 | { |
109 | 109 | Console.WriteLine(e.ToString()); | |
110 | if(AssetResponse.ContentLength>1000) { | 110 | return; |
111 | byte[] chunk = new byte[1000]; | 111 | } |
112 | Array.Copy(idata,chunk,1000); | 112 | |
113 | TransferPacket.TransferData.Data = chunk; | 113 | TransferInfoPacket Transfer = new TransferInfoPacket(); |
114 | TransferPacket.TransferData.Status = 0; | 114 | Transfer.TransferInfo.ChannelType = 2; |
115 | OutPacket(TransferPacket); | 115 | Transfer.TransferInfo.Status = 0; |
116 | 116 | Transfer.TransferInfo.TargetType = 0; | |
117 | TransferPacket = new TransferPacketPacket(); | 117 | Transfer.TransferInfo.Params = reqPacket.TransferInfo.Params; |
118 | TransferPacket.TransferData.Packet = 1; | 118 | Transfer.TransferInfo.Size = (int)AssetResponse.ContentLength; |
119 | TransferPacket.TransferData.ChannelType = 2; | 119 | Transfer.TransferInfo.TransferID = reqPacket.TransferInfo.TransferID; |
120 | TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID; | 120 | |
121 | byte[] chunk1 = new byte[(idata.Length-1000)]; | 121 | OutPacket(Transfer); |
122 | Array.Copy(idata, 1000, chunk1, 0, chunk1.Length); | 122 | |
123 | TransferPacket.TransferData.Data = chunk1; | 123 | TransferPacketPacket TransferPacket = new TransferPacketPacket(); |
124 | TransferPacket.TransferData.Status = 1; | 124 | TransferPacket.TransferData.Packet = 0; |
125 | OutPacket(TransferPacket); | 125 | TransferPacket.TransferData.ChannelType = 2; |
126 | } else { | 126 | TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID; |
127 | TransferPacket.TransferData.Status = 1; | 127 | |
128 | TransferPacket.TransferData.Data = idata; | 128 | if (AssetResponse.ContentLength > 1000) |
129 | OutPacket(TransferPacket); | 129 | { |
130 | } | 130 | byte[] chunk = new byte[1000]; |
131 | AssetResponse.Close(); | 131 | Array.Copy(idata, chunk, 1000); |
132 | } | 132 | TransferPacket.TransferData.Data = chunk; |
133 | } | 133 | TransferPacket.TransferData.Status = 0; |
134 | 134 | OutPacket(TransferPacket); | |
135 | public void Logout() { | 135 | |
136 | // TODO - kill any AssetLoaders | 136 | TransferPacket = new TransferPacketPacket(); |
137 | ClientThread.Abort(); | 137 | TransferPacket.TransferData.Packet = 1; |
138 | } | 138 | TransferPacket.TransferData.ChannelType = 2; |
139 | 139 | TransferPacket.TransferData.TransferID = reqPacket.TransferInfo.TransferID; | |
140 | public void ProcessInPacket(Packet Pack) { | 140 | byte[] chunk1 = new byte[(idata.Length - 1000)]; |
141 | ack_pack(Pack); | 141 | Array.Copy(idata, 1000, chunk1, 0, chunk1.Length); |
142 | switch(Pack.Type) { | 142 | TransferPacket.TransferData.Data = chunk1; |
143 | case PacketType.CompleteAgentMovement: | 143 | TransferPacket.TransferData.Status = 1; |
144 | ClientAvatar.CompleteMovement(OpenSim_Main.local_world); | 144 | OutPacket(TransferPacket); |
145 | ClientAvatar.SendInitialPosition(); | 145 | } |
146 | break; | 146 | else |
147 | case PacketType.RegionHandshakeReply: | 147 | { |
148 | OpenSim_Main.local_world.SendLayerData(this); | 148 | TransferPacket.TransferData.Status = 1; |
149 | break; | 149 | TransferPacket.TransferData.Data = idata; |
150 | case PacketType.AgentWearablesRequest: | 150 | OutPacket(TransferPacket); |
151 | ClientAvatar.SendInitialAppearance(); | 151 | } |
152 | break; | 152 | AssetResponse.Close(); |
153 | case PacketType.TransferRequest: | 153 | } |
154 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request"); | 154 | } |
155 | // We put transfer requests into a big queue and then spawn a thread for each new one | 155 | |
156 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; | 156 | public void Logout() |
157 | AssetRequests.Enqueue(transfer); | 157 | { |
158 | Thread AssetLoaderThread = new Thread(new ThreadStart(AssetLoader)); | 158 | // TODO - kill any AssetLoaders |
159 | AssetLoaderThread.Start(); | 159 | ClientThread.Abort(); |
160 | break; | 160 | } |
161 | case PacketType.LogoutRequest: | 161 | |
162 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request"); | 162 | public void ProcessInPacket(Packet Pack) |
163 | lock(OpenSim_Main.local_world.Entities) { | 163 | { |
164 | OpenSim_Main.local_world.Entities.Remove(this.AgentID); | 164 | ack_pack(Pack); |
165 | } | 165 | switch (Pack.Type) |
166 | 166 | { | |
167 | if(OpenSim_Main.cfg.sandbox==false) { | 167 | case PacketType.CompleteAgentMovement: |
168 | WebRequest DeleteSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + this.AgentID.ToString() + this.CircuitCode.ToString() + "/delete"); | 168 | ClientAvatar.CompleteMovement(OpenSim_Main.local_world); |
169 | WebResponse GridResponse = DeleteSession.GetResponse(); | 169 | ClientAvatar.SendInitialPosition(); |
170 | StreamReader sr = new StreamReader(GridResponse.GetResponseStream()); | 170 | break; |
171 | String grTest = sr.ReadLine(); | 171 | case PacketType.RegionHandshakeReply: |
172 | sr.Close(); | 172 | OpenSim_Main.local_world.SendLayerData(this); |
173 | GridResponse.Close(); | 173 | break; |
174 | OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest); | 174 | case PacketType.AgentWearablesRequest: |
175 | } | 175 | ClientAvatar.SendInitialAppearance(); |
176 | this.ClientThread.Abort(); | 176 | break; |
177 | break; | 177 | case PacketType.TransferRequest: |
178 | case PacketType.AgentUpdate: | 178 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got transfer request"); |
179 | ClientAvatar.HandleAgentUpdate((AgentUpdatePacket)Pack); | 179 | // We put transfer requests into a big queue and then spawn a thread for each new one |
180 | break; | 180 | TransferRequestPacket transfer = (TransferRequestPacket)Pack; |
181 | case PacketType.ChatFromViewer: | 181 | AssetRequests.Enqueue(transfer); |
182 | ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack; | 182 | Thread AssetLoaderThread = new Thread(new ThreadStart(AssetLoader)); |
183 | if(Helpers.FieldToString(inchatpack.ChatData.Message)=="") break; | 183 | AssetLoaderThread.Start(); |
184 | 184 | break; | |
185 | System.Text.Encoding _enc = System.Text.Encoding.ASCII; | 185 | case PacketType.LogoutRequest: |
186 | libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket(); | 186 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessInPacket() - Got a logout request"); |
187 | reply.ChatData.Audible = 1; | 187 | lock (OpenSim_Main.local_world.Entities) |
188 | reply.ChatData.Message = inchatpack.ChatData.Message; | 188 | { |
189 | reply.ChatData.ChatType = 1; | 189 | OpenSim_Main.local_world.Entities.Remove(this.AgentID); |
190 | reply.ChatData.SourceType = 1; | 190 | } |
191 | reply.ChatData.Position = this.ClientAvatar.position; | 191 | |
192 | reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0"); | 192 | if (OpenSim_Main.cfg.sandbox == false) |
193 | reply.ChatData.OwnerID = this.AgentID; | 193 | { |
194 | reply.ChatData.SourceID = this.AgentID; | 194 | WebRequest DeleteSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + this.AgentID.ToString() + this.CircuitCode.ToString() + "/delete"); |
195 | 195 | WebResponse GridResponse = DeleteSession.GetResponse(); | |
196 | 196 | StreamReader sr = new StreamReader(GridResponse.GetResponseStream()); | |
197 | 197 | String grTest = sr.ReadLine(); | |
198 | foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) { | 198 | sr.Close(); |
199 | client.OutPacket(reply); | 199 | GridResponse.Close(); |
200 | } | 200 | OpenSim_Main.localcons.WriteLine("DEBUG: " + grTest); |
201 | break; | 201 | } |
202 | } | 202 | this.ClientThread.Abort(); |
203 | } | 203 | break; |
204 | 204 | case PacketType.AgentUpdate: | |
205 | private void ResendUnacked() | 205 | ClientAvatar.HandleAgentUpdate((AgentUpdatePacket)Pack); |
206 | { | 206 | break; |
207 | int now = Environment.TickCount; | 207 | case PacketType.ChatFromViewer: |
208 | 208 | ChatFromViewerPacket inchatpack = (ChatFromViewerPacket)Pack; | |
209 | lock (NeedAck) | 209 | if (Helpers.FieldToString(inchatpack.ChatData.Message) == "") break; |
210 | { | 210 | |
211 | foreach (Packet packet in NeedAck.Values) | 211 | System.Text.Encoding _enc = System.Text.Encoding.ASCII; |
212 | { | 212 | libsecondlife.Packets.ChatFromSimulatorPacket reply = new ChatFromSimulatorPacket(); |
213 | if (now - packet.TickCount > RESEND_TIMEOUT) | 213 | reply.ChatData.Audible = 1; |
214 | { | 214 | reply.ChatData.Message = inchatpack.ChatData.Message; |
215 | 215 | reply.ChatData.ChatType = 1; | |
216 | packet.Header.Resent = true; | 216 | reply.ChatData.SourceType = 1; |
217 | OutPacket(packet); | 217 | reply.ChatData.Position = this.ClientAvatar.position; |
218 | } | 218 | reply.ChatData.FromName = _enc.GetBytes(this.ClientAvatar.firstname + " " + this.ClientAvatar.lastname + "\0"); |
219 | } | 219 | reply.ChatData.OwnerID = this.AgentID; |
220 | } | 220 | reply.ChatData.SourceID = this.AgentID; |
221 | } | 221 | |
222 | 222 | ||
223 | private void SendAcks() | 223 | |
224 | { | 224 | foreach (OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) |
225 | lock (PendingAcks) | 225 | { |
226 | { | 226 | client.OutPacket(reply); |
227 | if (PendingAcks.Count > 0) | 227 | } |
228 | { | 228 | break; |
229 | if (PendingAcks.Count > 250) | 229 | } |
230 | { | 230 | } |
231 | return; | 231 | |
232 | } | 232 | private void ResendUnacked() |
233 | 233 | { | |
234 | 234 | int now = Environment.TickCount; | |
235 | 235 | ||
236 | int i = 0; | 236 | lock (NeedAck) |
237 | PacketAckPacket acks = new PacketAckPacket(); | 237 | { |
238 | acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count]; | 238 | foreach (Packet packet in NeedAck.Values) |
239 | 239 | { | |
240 | foreach (uint ack in PendingAcks.Values) | 240 | if (now - packet.TickCount > RESEND_TIMEOUT) |
241 | { | 241 | { |
242 | acks.Packets[i] = new PacketAckPacket.PacketsBlock(); | 242 | |
243 | acks.Packets[i].ID = ack; | 243 | packet.Header.Resent = true; |
244 | i++; | 244 | OutPacket(packet); |
245 | } | 245 | } |
246 | 246 | } | |
247 | acks.Header.Reliable = false; | 247 | } |
248 | OutPacket(acks); | 248 | } |
249 | 249 | ||
250 | PendingAcks.Clear(); | 250 | private void SendAcks() |
251 | } | 251 | { |
252 | } | 252 | lock (PendingAcks) |
253 | } | 253 | { |
254 | 254 | if (PendingAcks.Count > 0) | |
255 | private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) | 255 | { |
256 | { | 256 | if (PendingAcks.Count > 250) |
257 | SendAcks(); | 257 | { |
258 | ResendUnacked(); | 258 | return; |
259 | } | 259 | } |
260 | 260 | ||
261 | public void ProcessOutPacket(Packet Pack) { | 261 | |
262 | 262 | ||
263 | // Keep track of when this packet was sent out | 263 | int i = 0; |
264 | Pack.TickCount = Environment.TickCount; | 264 | PacketAckPacket acks = new PacketAckPacket(); |
265 | 265 | acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count]; | |
266 | if (!Pack.Header.Resent) | 266 | |
267 | { | 267 | foreach (uint ack in PendingAcks.Values) |
268 | // Set the sequence number | 268 | { |
269 | lock (SequenceLock) | 269 | acks.Packets[i] = new PacketAckPacket.PacketsBlock(); |
270 | { | 270 | acks.Packets[i].ID = ack; |
271 | if (Sequence >= MAX_SEQUENCE) | 271 | i++; |
272 | Sequence = 1; | 272 | } |
273 | else | 273 | |
274 | Sequence++; | 274 | acks.Header.Reliable = false; |
275 | Pack.Header.Sequence = Sequence; | 275 | OutPacket(acks); |
276 | } | 276 | |
277 | 277 | PendingAcks.Clear(); | |
278 | if (Pack.Header.Reliable) //DIRTY HACK | 278 | } |
279 | { | 279 | } |
280 | lock (NeedAck) | 280 | } |
281 | { | 281 | |
282 | if (!NeedAck.ContainsKey(Pack.Header.Sequence)) | 282 | private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea) |
283 | { | 283 | { |
284 | NeedAck.Add(Pack.Header.Sequence, Pack); | 284 | SendAcks(); |
285 | } | 285 | ResendUnacked(); |
286 | else | 286 | } |
287 | { | 287 | |
288 | // Client.Log("Attempted to add a duplicate sequence number (" + | 288 | public void ProcessOutPacket(Packet Pack) |
289 | // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + | 289 | { |
290 | // packet.Type.ToString(), Helpers.LogLevel.Warning); | 290 | |
291 | } | 291 | // Keep track of when this packet was sent out |
292 | } | 292 | Pack.TickCount = Environment.TickCount; |
293 | 293 | ||
294 | // Don't append ACKs to resent packets, in case that's what was causing the | 294 | if (!Pack.Header.Resent) |
295 | // delivery to fail | 295 | { |
296 | if (!Pack.Header.Resent) | 296 | // Set the sequence number |
297 | { | 297 | lock (SequenceLock) |
298 | // Append any ACKs that need to be sent out to this packet | 298 | { |
299 | lock (PendingAcks) | 299 | if (Sequence >= MAX_SEQUENCE) |
300 | { | 300 | Sequence = 1; |
301 | if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS && | 301 | else |
302 | Pack.Type != PacketType.PacketAck && | 302 | Sequence++; |
303 | Pack.Type != PacketType.LogoutRequest) | 303 | Pack.Header.Sequence = Sequence; |
304 | { | 304 | } |
305 | Pack.Header.AckList = new uint[PendingAcks.Count]; | 305 | |
306 | int i = 0; | 306 | if (Pack.Header.Reliable) //DIRTY HACK |
307 | 307 | { | |
308 | foreach (uint ack in PendingAcks.Values) | 308 | lock (NeedAck) |
309 | { | 309 | { |
310 | Pack.Header.AckList[i] = ack; | 310 | if (!NeedAck.ContainsKey(Pack.Header.Sequence)) |
311 | i++; | 311 | { |
312 | } | 312 | NeedAck.Add(Pack.Header.Sequence, Pack); |
313 | 313 | } | |
314 | PendingAcks.Clear(); | 314 | else |
315 | Pack.Header.AppendedAcks = true; | 315 | { |
316 | } | 316 | // Client.Log("Attempted to add a duplicate sequence number (" + |
317 | } | 317 | // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " + |
318 | } | 318 | // packet.Type.ToString(), Helpers.LogLevel.Warning); |
319 | } | 319 | } |
320 | } | 320 | } |
321 | 321 | ||
322 | 322 | // Don't append ACKs to resent packets, in case that's what was causing the | |
323 | byte[] ZeroOutBuffer = new byte[4096]; | 323 | // delivery to fail |
324 | byte[] sendbuffer; | 324 | if (!Pack.Header.Resent) |
325 | sendbuffer = Pack.ToBytes(); | 325 | { |
326 | 326 | // Append any ACKs that need to be sent out to this packet | |
327 | try { | 327 | lock (PendingAcks) |
328 | if (Pack.Header.Zerocoded) { | 328 | { |
329 | int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer); | 329 | if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS && |
330 | OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None,userEP); | 330 | Pack.Type != PacketType.PacketAck && |
331 | } else { | 331 | Pack.Type != PacketType.LogoutRequest) |
332 | OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None,userEP); | 332 | { |
333 | } | 333 | Pack.Header.AckList = new uint[PendingAcks.Count]; |
334 | } catch (Exception) { | 334 | int i = 0; |
335 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread"); | 335 | |
336 | ClientThread.Abort(); | 336 | foreach (uint ack in PendingAcks.Values) |
337 | } | 337 | { |
338 | 338 | Pack.Header.AckList[i] = ack; | |
339 | } | 339 | i++; |
340 | 340 | } | |
341 | public void InPacket(Packet NewPack) { | 341 | |
342 | // Handle appended ACKs | 342 | PendingAcks.Clear(); |
343 | if (NewPack.Header.AppendedAcks) | 343 | Pack.Header.AppendedAcks = true; |
344 | { | 344 | } |
345 | lock (NeedAck) | 345 | } |
346 | { | 346 | } |
347 | foreach (uint ack in NewPack.Header.AckList) | 347 | } |
348 | { | 348 | } |
349 | OpenSim_Main.localcons.WriteLine("Got appended ack: "+ack); | 349 | |
350 | NeedAck.Remove(ack); | 350 | |
351 | } | 351 | byte[] ZeroOutBuffer = new byte[4096]; |
352 | } | 352 | byte[] sendbuffer; |
353 | } | 353 | sendbuffer = Pack.ToBytes(); |
354 | 354 | ||
355 | // Handle PacketAck packets | 355 | try |
356 | if (NewPack.Type == PacketType.PacketAck) | 356 | { |
357 | { | 357 | if (Pack.Header.Zerocoded) |
358 | PacketAckPacket ackPacket = (PacketAckPacket)NewPack; | 358 | { |
359 | 359 | int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer); | |
360 | lock (NeedAck) | 360 | OpenSim_Main.Server.SendTo(ZeroOutBuffer, packetsize, SocketFlags.None, userEP); |
361 | { | 361 | } |
362 | foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) | 362 | else |
363 | { | 363 | { |
364 | NeedAck.Remove(block.ID); | 364 | OpenSim_Main.Server.SendTo(sendbuffer, sendbuffer.Length, SocketFlags.None, userEP); |
365 | } | 365 | } |
366 | } | 366 | } |
367 | } else if( ( NewPack.Type == PacketType.StartPingCheck ) ) { | 367 | catch (Exception) |
368 | //reply to pingcheck | 368 | { |
369 | libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack; | 369 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread"); |
370 | libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket(); | 370 | ClientThread.Abort(); |
371 | endPing.PingID.PingID = startPing.PingID.PingID; | 371 | } |
372 | OutPacket(endPing); | 372 | |
373 | } | 373 | } |
374 | else | 374 | |
375 | { | 375 | public void InPacket(Packet NewPack) |
376 | QueItem item = new QueItem(); | 376 | { |
377 | item.Packet = NewPack; | 377 | // Handle appended ACKs |
378 | item.Incoming = true; | 378 | if (NewPack.Header.AppendedAcks) |
379 | this.PacketQueue.Enqueue(item); | 379 | { |
380 | } | 380 | lock (NeedAck) |
381 | 381 | { | |
382 | } | 382 | foreach (uint ack in NewPack.Header.AckList) |
383 | 383 | { | |
384 | public void OutPacket(Packet NewPack) { | 384 | OpenSim_Main.localcons.WriteLine("Got appended ack: " + ack); |
385 | QueItem item = new QueItem(); | 385 | NeedAck.Remove(ack); |
386 | item.Packet = NewPack; | 386 | } |
387 | item.Incoming = false; | 387 | } |
388 | this.PacketQueue.Enqueue(item); | 388 | } |
389 | } | 389 | |
390 | 390 | // Handle PacketAck packets | |
391 | public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) { | 391 | if (NewPack.Type == PacketType.PacketAck) |
392 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request"); | 392 | { |
393 | cirpack = initialcirpack; | 393 | PacketAckPacket ackPacket = (PacketAckPacket)NewPack; |
394 | userEP = remoteEP; | 394 | |
395 | PacketQueue = new BlockingQueue<QueItem>(); | 395 | lock (NeedAck) |
396 | AssetRequests = new BlockingQueue<TransferRequestPacket>(); | 396 | { |
397 | AckTimer = new System.Timers.Timer(500); | 397 | foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets) |
398 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); | 398 | { |
399 | AckTimer.Start(); | 399 | NeedAck.Remove(block.ID); |
400 | 400 | } | |
401 | ClientThread = new Thread(new ThreadStart(AuthUser)); | 401 | } |
402 | ClientThread.IsBackground = true; | 402 | } |
403 | ClientThread.Start(); | 403 | else if ((NewPack.Type == PacketType.StartPingCheck)) |
404 | } | 404 | { |
405 | 405 | //reply to pingcheck | |
406 | private void ClientLoop() { | 406 | libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack; |
407 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop"); | 407 | libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket(); |
408 | while(true) { | 408 | endPing.PingID.PingID = startPing.PingID.PingID; |
409 | QueItem nextPacket = PacketQueue.Dequeue(); | 409 | OutPacket(endPing); |
410 | if(nextPacket.Incoming) | 410 | } |
411 | { | 411 | else |
412 | //is a incoming packet | 412 | { |
413 | ProcessInPacket(nextPacket.Packet); | 413 | QueItem item = new QueItem(); |
414 | } | 414 | item.Packet = NewPack; |
415 | else | 415 | item.Incoming = true; |
416 | { | 416 | this.PacketQueue.Enqueue(item); |
417 | //is a out going packet | 417 | } |
418 | ProcessOutPacket(nextPacket.Packet); | 418 | |
419 | } | 419 | } |
420 | } | 420 | |
421 | } | 421 | public void OutPacket(Packet NewPack) |
422 | 422 | { | |
423 | private void InitNewClient() { | 423 | QueItem item = new QueItem(); |
424 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world"); | 424 | item.Packet = NewPack; |
425 | OpenSim_Main.local_world.AddViewerAgent(this); | 425 | item.Incoming = false; |
426 | world.Entity tempent=OpenSim_Main.local_world.Entities[this.AgentID]; | 426 | this.PacketQueue.Enqueue(item); |
427 | this.ClientAvatar=(world.Avatar)tempent; | 427 | } |
428 | } | 428 | |
429 | 429 | public OpenSimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack) | |
430 | private void AuthUser() { | 430 | { |
431 | if(OpenSim_Main.cfg.sandbox==false) { | 431 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs - Started up new client thread to handle incoming request"); |
432 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid"); | 432 | cirpack = initialcirpack; |
433 | WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists"); | 433 | userEP = remoteEP; |
434 | OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL); | 434 | PacketQueue = new BlockingQueue<QueItem>(); |
435 | WebResponse GridResponse = CheckSession.GetResponse(); | 435 | AssetRequests = new BlockingQueue<TransferRequestPacket>(); |
436 | StreamReader sr = new StreamReader(GridResponse.GetResponseStream()); | 436 | AckTimer = new System.Timers.Timer(500); |
437 | String grTest = sr.ReadLine(); | 437 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); |
438 | sr.Close(); | 438 | AckTimer.Start(); |
439 | GridResponse.Close(); | 439 | |
440 | if(String.IsNullOrEmpty(grTest) || grTest.Equals("1")) { // YAY! Valid login | 440 | ClientThread = new Thread(new ThreadStart(AuthUser)); |
441 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString()); | 441 | ClientThread.IsBackground = true; |
442 | this.AgentID=cirpack.CircuitCode.ID; | 442 | ClientThread.Start(); |
443 | this.SessionID=cirpack.CircuitCode.SessionID; | 443 | } |
444 | this.CircuitCode=cirpack.CircuitCode.Code; | 444 | |
445 | InitNewClient(); | 445 | private void ClientLoop() |
446 | ClientLoop(); | 446 | { |
447 | } else { // Invalid | 447 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:ClientLoop() - Entered loop"); |
448 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString()); | 448 | while (true) |
449 | ClientThread.Abort(); | 449 | { |
450 | } | 450 | QueItem nextPacket = PacketQueue.Dequeue(); |
451 | } else { | 451 | if (nextPacket.Incoming) |
452 | this.AgentID=cirpack.CircuitCode.ID; | 452 | { |
453 | this.SessionID=cirpack.CircuitCode.SessionID; | 453 | //is a incoming packet |
454 | this.CircuitCode=cirpack.CircuitCode.Code; | 454 | ProcessInPacket(nextPacket.Packet); |
455 | InitNewClient(); | 455 | } |
456 | ClientLoop(); | 456 | else |
457 | } | 457 | { |
458 | } | 458 | //is a out going packet |
459 | } | 459 | ProcessOutPacket(nextPacket.Packet); |
460 | } | ||
461 | } | ||
462 | } | ||
463 | |||
464 | private void InitNewClient() | ||
465 | { | ||
466 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:InitNewClient() - Adding viewer agent to world"); | ||
467 | OpenSim_Main.local_world.AddViewerAgent(this); | ||
468 | world.Entity tempent = OpenSim_Main.local_world.Entities[this.AgentID]; | ||
469 | this.ClientAvatar = (world.Avatar)tempent; | ||
470 | } | ||
471 | |||
472 | private void AuthUser() | ||
473 | { | ||
474 | if (OpenSim_Main.cfg.sandbox == false) | ||
475 | { | ||
476 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Authenticating new user request with grid"); | ||
477 | WebRequest CheckSession = WebRequest.Create(OpenSim_Main.cfg.GridURL + "/usersessions/" + OpenSim_Main.cfg.GridSendKey + "/" + cirpack.CircuitCode.ID.ToString() + "/" + cirpack.CircuitCode.Code.ToString() + "/exists"); | ||
478 | OpenSim_Main.localcons.WriteLine(OpenSim_Main.cfg.GridURL); | ||
479 | WebResponse GridResponse = CheckSession.GetResponse(); | ||
480 | StreamReader sr = new StreamReader(GridResponse.GetResponseStream()); | ||
481 | String grTest = sr.ReadLine(); | ||
482 | sr.Close(); | ||
483 | GridResponse.Close(); | ||
484 | if (String.IsNullOrEmpty(grTest) || grTest.Equals("1")) | ||
485 | { // YAY! Valid login | ||
486 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString()); | ||
487 | this.AgentID = cirpack.CircuitCode.ID; | ||
488 | this.SessionID = cirpack.CircuitCode.SessionID; | ||
489 | this.CircuitCode = cirpack.CircuitCode.Code; | ||
490 | InitNewClient(); | ||
491 | ClientLoop(); | ||
492 | } | ||
493 | else | ||
494 | { // Invalid | ||
495 | OpenSim_Main.localcons.WriteLine("OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString()); | ||
496 | ClientThread.Abort(); | ||
497 | } | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | this.AgentID = cirpack.CircuitCode.ID; | ||
502 | this.SessionID = cirpack.CircuitCode.SessionID; | ||
503 | this.CircuitCode = cirpack.CircuitCode.Code; | ||
504 | InitNewClient(); | ||
505 | ClientLoop(); | ||
506 | } | ||
507 | } | ||
508 | } | ||
460 | 509 | ||
461 | } | 510 | } |
diff --git a/src/Second-server.csproj b/src/Second-server.csproj index 304f666..8d55e06 100644 --- a/src/Second-server.csproj +++ b/src/Second-server.csproj | |||
@@ -46,19 +46,19 @@ | |||
46 | <Compile Include="Config.cs" /> | 46 | <Compile Include="Config.cs" /> |
47 | <Compile Include="Main.cs" /> | 47 | <Compile Include="Main.cs" /> |
48 | <Compile Include="OpenSimClient.cs" /> | 48 | <Compile Include="OpenSimClient.cs" /> |
49 | <Compile Include="types\BitPack.cs" /> | 49 | <Compile Include="ServerConsole.cs" /> |
50 | <Compile Include="types\Mesh.cs" /> | 50 | <Compile Include="types\Mesh.cs" /> |
51 | <Compile Include="types\Triangle.cs" /> | 51 | <Compile Include="types\Triangle.cs" /> |
52 | <Compile Include="Util.cs" /> | 52 | <Compile Include="Util.cs" /> |
53 | <Compile Include="VersionInfo.cs" /> | 53 | <Compile Include="VersionInfo.cs" /> |
54 | <Compile Include="world\Avatar.cs" /> | 54 | <Compile Include="world\Avatar.cs" /> |
55 | <Compile Include="world\Entity.cs" /> | 55 | <Compile Include="world\Entity.cs" /> |
56 | <Compile Include="world\HeightmapGenHills.cs" /> | ||
56 | <Compile Include="world\PhysicsEngine.cs" /> | 57 | <Compile Include="world\PhysicsEngine.cs" /> |
57 | <Compile Include="world\Primitive.cs" /> | 58 | <Compile Include="world\Primitive.cs" /> |
58 | <Compile Include="world\ScriptEngine.cs" /> | 59 | <Compile Include="world\ScriptEngine.cs" /> |
59 | <Compile Include="world\scripting\IScript.cs" /> | 60 | <Compile Include="world\scripting\IScript.cs" /> |
60 | <Compile Include="world\SurfacePatch.cs" /> | 61 | <Compile Include="world\SurfacePatch.cs" /> |
61 | <Compile Include="world\TerrainDecoder.cs" /> | ||
62 | <Compile Include="world\World.cs" /> | 62 | <Compile Include="world\World.cs" /> |
63 | </ItemGroup> | 63 | </ItemGroup> |
64 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> | 64 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> |
diff --git a/src/VersionInfo.cs b/src/VersionInfo.cs new file mode 100644 index 0000000..14581ee --- /dev/null +++ b/src/VersionInfo.cs | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | Copyright (c) OpenSim project, http://osgrid.org/ | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions are met: | ||
6 | * * Redistributions of source code must retain the above copyright | ||
7 | * notice, this list of conditions and the following disclaimer. | ||
8 | * * Redistributions in binary form must reproduce the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer in the | ||
10 | * documentation and/or other materials provided with the distribution. | ||
11 | * * Neither the name of the <organization> nor the | ||
12 | * names of its contributors may be used to endorse or promote products | ||
13 | * derived from this software without specific prior written permission. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY | ||
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
18 | * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY | ||
19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | using System; | ||
28 | |||
29 | namespace OpenSim | ||
30 | { | ||
31 | /// <summary> | ||
32 | /// </summary> | ||
33 | public class VersionInfo | ||
34 | { | ||
35 | public static string Version = "0.0.1-unofficial"; | ||
36 | } | ||
37 | } | ||
diff --git a/src/types/BitPack.cs b/src/types/BitPack.cs deleted file mode 100644 index 1abbcf0..0000000 --- a/src/types/BitPack.cs +++ /dev/null | |||
@@ -1,138 +0,0 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Text; | ||
4 | |||
5 | namespace OpenSim.types | ||
6 | { | ||
7 | /* New Method | ||
8 | * | ||
9 | * 1. Get all the individual bytes and their bitlength, put them in a dictionary | ||
10 | * 2. Mash together when wanted. | ||
11 | * | ||
12 | * */ | ||
13 | public class Bits { | ||
14 | public byte[] data; | ||
15 | public int len; | ||
16 | } | ||
17 | |||
18 | public class InverseBitPack | ||
19 | { | ||
20 | private List<Bits> bits; | ||
21 | |||
22 | public InverseBitPack() | ||
23 | { | ||
24 | bits = new List<Bits>(); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | public class BitPack | ||
29 | { | ||
30 | private const int MAX_BITS = 8; | ||
31 | |||
32 | private byte[] Data; | ||
33 | private int bytePos; | ||
34 | private int bitPos; | ||
35 | |||
36 | public BitPack(byte[] data, int pos) // For libsl compatibility | ||
37 | { | ||
38 | Data = data; | ||
39 | bytePos = pos; | ||
40 | } | ||
41 | |||
42 | public BitPack() // Encoding version | ||
43 | { | ||
44 | |||
45 | } | ||
46 | |||
47 | public void LoadData(byte[] data, int pos) { | ||
48 | Data = data; | ||
49 | bytePos = pos; | ||
50 | bitPos = 0; | ||
51 | } | ||
52 | |||
53 | private void PackBitsArray(byte[] bits, int bitLen) | ||
54 | { | ||
55 | int offset = bitPos % MAX_BITS; | ||
56 | int i; | ||
57 | byte temp1; | ||
58 | byte temp2; | ||
59 | |||
60 | for (i = 0; i < bits.Length; i++) | ||
61 | { | ||
62 | int Byte = bits[i]; | ||
63 | Byte <<= offset; | ||
64 | temp1 = (byte)(Byte & 0xFF); | ||
65 | temp2 = (byte)((Byte >> 8) & 0xFF); | ||
66 | |||
67 | Data[Data.Length - 1] |= temp1; | ||
68 | // Data | ||
69 | |||
70 | bitPos += bitLen; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | public float UnpackFloat() | ||
75 | { | ||
76 | byte[] output = UnpackBitsArray(32); | ||
77 | |||
78 | if (!BitConverter.IsLittleEndian) Array.Reverse(output); | ||
79 | return BitConverter.ToSingle(output, 0); | ||
80 | } | ||
81 | |||
82 | public int UnpackBits(int totalCount) | ||
83 | { | ||
84 | byte[] output = UnpackBitsArray(totalCount); | ||
85 | |||
86 | if (!BitConverter.IsLittleEndian) Array.Reverse(output); | ||
87 | return BitConverter.ToInt32(output, 0); | ||
88 | } | ||
89 | |||
90 | private byte[] UnpackBitsArray(int totalCount) | ||
91 | { | ||
92 | int count = 0; | ||
93 | byte[] output = new byte[4]; | ||
94 | int curBytePos = 0; | ||
95 | int curBitPos = 0; | ||
96 | |||
97 | while (totalCount > 0) | ||
98 | { | ||
99 | if (totalCount > MAX_BITS) | ||
100 | { | ||
101 | count = MAX_BITS; | ||
102 | totalCount -= MAX_BITS; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | count = totalCount; | ||
107 | totalCount = 0; | ||
108 | } | ||
109 | |||
110 | while (count > 0) | ||
111 | { | ||
112 | // Shift the previous bits | ||
113 | output[curBytePos] <<= 1; | ||
114 | |||
115 | // Grab one bit | ||
116 | if ((Data[bytePos] & (0x80 >> bitPos++)) != 0) | ||
117 | ++output[curBytePos]; | ||
118 | |||
119 | --count; | ||
120 | ++curBitPos; | ||
121 | |||
122 | if (bitPos >= MAX_BITS) | ||
123 | { | ||
124 | bitPos = 0; | ||
125 | ++bytePos; | ||
126 | } | ||
127 | if (curBitPos >= MAX_BITS) | ||
128 | { | ||
129 | curBitPos = 0; | ||
130 | ++curBytePos; | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | return output; | ||
136 | } | ||
137 | } | ||
138 | } | ||
diff --git a/src/world/Avatar.cs b/src/world/Avatar.cs index 26b2002..9d8d7d2 100644 --- a/src/world/Avatar.cs +++ b/src/world/Avatar.cs | |||
@@ -226,8 +226,8 @@ namespace OpenSim.world | |||
226 | handshake.RegionInfo.TerrainStartHeight10 = 10; | 226 | handshake.RegionInfo.TerrainStartHeight10 = 10; |
227 | handshake.RegionInfo.TerrainStartHeight11 = 10; | 227 | handshake.RegionInfo.TerrainStartHeight11 = 10; |
228 | handshake.RegionInfo.SimAccess = 13; | 228 | handshake.RegionInfo.SimAccess = 13; |
229 | handshake.RegionInfo.WaterHeight = 5; | 229 | handshake.RegionInfo.WaterHeight = 20.0f; |
230 | handshake.RegionInfo.RegionFlags = 72458694; | 230 | handshake.RegionInfo.RegionFlags = 72458694; // TODO: WTF sirs? Use an enum! |
231 | handshake.RegionInfo.SimName = _enc.GetBytes(OpenSim_Main.cfg.RegionName + "\0"); | 231 | handshake.RegionInfo.SimName = _enc.GetBytes(OpenSim_Main.cfg.RegionName + "\0"); |
232 | handshake.RegionInfo.SimOwner = new LLUUID("00000000-0000-0000-0000-000000000000"); | 232 | handshake.RegionInfo.SimOwner = new LLUUID("00000000-0000-0000-0000-000000000000"); |
233 | handshake.RegionInfo.TerrainBase0 = new LLUUID("b8d3965a-ad78-bf43-699b-bff8eca6c975"); | 233 | handshake.RegionInfo.TerrainBase0 = new LLUUID("b8d3965a-ad78-bf43-699b-bff8eca6c975"); |
diff --git a/src/world/HeightmapGenHills.cs b/src/world/HeightmapGenHills.cs new file mode 100644 index 0000000..12af005 --- /dev/null +++ b/src/world/HeightmapGenHills.cs | |||
@@ -0,0 +1,122 @@ | |||
1 | using System; | ||
2 | |||
3 | namespace libsecondlife | ||
4 | { | ||
5 | public class HeightmapGenHills | ||
6 | { | ||
7 | private Random Rand = new Random(); | ||
8 | private int NumHills; | ||
9 | private float HillMin; | ||
10 | private float HillMax; | ||
11 | private bool Island; | ||
12 | private float[] heightmap; | ||
13 | |||
14 | public float[] GenerateHeightmap(int numHills, float hillMin, float hillMax, bool island) | ||
15 | { | ||
16 | NumHills = numHills; | ||
17 | HillMin = hillMin; | ||
18 | HillMax = hillMax; | ||
19 | Island = island; | ||
20 | |||
21 | heightmap = new float[256 * 256]; | ||
22 | |||
23 | for (int i = 0; i < numHills; i++) | ||
24 | { | ||
25 | AddHill(); | ||
26 | } | ||
27 | |||
28 | Normalize(); | ||
29 | |||
30 | return heightmap; | ||
31 | } | ||
32 | |||
33 | private void AddHill() | ||
34 | { | ||
35 | float x, y; | ||
36 | float radius = RandomRange(HillMin, HillMax); | ||
37 | |||
38 | if (Island) | ||
39 | { | ||
40 | // Which direction from the center of the map the hill is placed | ||
41 | float theta = RandomRange(0, 6.28f); | ||
42 | |||
43 | // How far from the center of the map to place the hill. The radius | ||
44 | // is subtracted from the range to prevent any part of the hill from | ||
45 | // reaching the edge of the map | ||
46 | float distance = RandomRange(radius / 2.0f, 128.0f - radius); | ||
47 | |||
48 | x = 128.0f + (float)Math.Cos(theta) * distance; | ||
49 | y = 128.0f + (float)Math.Sin(theta) * distance; | ||
50 | } | ||
51 | else | ||
52 | { | ||
53 | x = RandomRange(-radius, 256.0f + radius); | ||
54 | y = RandomRange(-radius, 256.0f + radius); | ||
55 | } | ||
56 | |||
57 | float radiusSq = radius * radius; | ||
58 | float distSq; | ||
59 | float height; | ||
60 | |||
61 | int xMin = (int)(x - radius) - 1; | ||
62 | int xMax = (int)(x + radius) + 1; | ||
63 | if (xMin < 0) xMin = 0; | ||
64 | if (xMax > 255) xMax = 255; | ||
65 | |||
66 | int yMin = (int)(y - radius) - 1; | ||
67 | int yMax = (int)(y + radius) + 1; | ||
68 | if (yMin < 0) yMin = 0; | ||
69 | if (yMax > 255) yMax = 255; | ||
70 | |||
71 | // Loop through each affected cell and determine the height at that point | ||
72 | for (int v = yMin; v <= yMax; ++v) | ||
73 | { | ||
74 | float fv = (float)v; | ||
75 | |||
76 | for (int h = xMin; h <= xMax; ++h) | ||
77 | { | ||
78 | float fh = (float)h; | ||
79 | |||
80 | // Determine how far from the center of this hill this point is | ||
81 | distSq = (x - fh) * (x - fh) + (y - fv) * (y - fv); | ||
82 | height = radiusSq - distSq; | ||
83 | |||
84 | // Don't add negative hill values | ||
85 | if (height > 0.0f) heightmap[h + v * 256] += height; | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | private void Normalize() | ||
91 | { | ||
92 | float min = heightmap[0]; | ||
93 | float max = heightmap[0]; | ||
94 | |||
95 | for (int x = 0; x < 256; x++) | ||
96 | { | ||
97 | for (int y = 0; y < 256; y++) | ||
98 | { | ||
99 | if (heightmap[x + y * 256] < min) min = heightmap[x + y * 256]; | ||
100 | if (heightmap[x + y * 256] > max) max = heightmap[x + y * 256]; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | // Avoid a rare divide by zero | ||
105 | if (min != max) | ||
106 | { | ||
107 | for (int x = 0; x < 256; x++) | ||
108 | { | ||
109 | for (int y = 0; y < 256; y++) | ||
110 | { | ||
111 | heightmap[x + y * 256] = ((heightmap[x + y * 256] - min) / (max - min)) * (HillMax - HillMin); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | private float RandomRange(float min, float max) | ||
118 | { | ||
119 | return (float)Rand.NextDouble() * (max - min) + min; | ||
120 | } | ||
121 | } | ||
122 | } | ||
diff --git a/src/world/TerrainDecoder.cs b/src/world/TerrainDecoder.cs deleted file mode 100644 index 1a34826..0000000 --- a/src/world/TerrainDecoder.cs +++ /dev/null | |||
@@ -1,683 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) OpenSim project, http://sim.opensecondlife.org/ | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions are met: | ||
6 | * * Redistributions of source code must retain the above copyright | ||
7 | * notice, this list of conditions and the following disclaimer. | ||
8 | * * Redistributions in binary form must reproduce the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer in the | ||
10 | * documentation and/or other materials provided with the distribution. | ||
11 | * * Neither the name of the <organization> nor the | ||
12 | * names of its contributors may be used to endorse or promote products | ||
13 | * derived from this software without specific prior written permission. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY | ||
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
17 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
18 | * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY | ||
19 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | //using libsecondlife; | ||
31 | using libsecondlife.Packets; | ||
32 | |||
33 | namespace OpenSim | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Description of TerrainDecoder. | ||
37 | /// </summary> | ||
38 | public class TerrainDecode | ||
39 | { | ||
40 | |||
41 | public enum LayerType : byte | ||
42 | { | ||
43 | Land = 0x4C, | ||
44 | Water = 0x57, | ||
45 | Wind = 0x37, | ||
46 | Cloud = 0x38 | ||
47 | } | ||
48 | |||
49 | public struct GroupHeader | ||
50 | { | ||
51 | public int Stride; | ||
52 | public int PatchSize; | ||
53 | public LayerType Type; | ||
54 | } | ||
55 | |||
56 | public struct PatchHeader | ||
57 | { | ||
58 | public float DCOffset; | ||
59 | public int Range; | ||
60 | public int QuantWBits; | ||
61 | public int PatchIDs; | ||
62 | public uint WordBits; | ||
63 | } | ||
64 | |||
65 | public class Patch | ||
66 | { | ||
67 | public float[] Heightmap; | ||
68 | } | ||
69 | |||
70 | |||
71 | /// <summary> | ||
72 | /// | ||
73 | /// </summary> | ||
74 | /// <param name="simulator"></param> | ||
75 | /// <param name="x"></param> | ||
76 | /// <param name="y"></param> | ||
77 | /// <param name="width"></param> | ||
78 | /// <param name="data"></param> | ||
79 | // public delegate void LandPatchCallback(Simulator simulator, int x, int y, int width, float[] data); | ||
80 | |||
81 | |||
82 | /// <summary> | ||
83 | /// | ||
84 | /// </summary> | ||
85 | //public event LandPatchCallback OnLandPatch; | ||
86 | |||
87 | private Random RandomClass = new Random(); | ||
88 | |||
89 | private const byte END_OF_PATCHES = 97; | ||
90 | private const int PATCHES_PER_EDGE = 16; | ||
91 | private const float OO_SQRT2 = 0.7071067811865475244008443621049f; | ||
92 | |||
93 | //private SecondLife Client; | ||
94 | private Dictionary<ulong, Patch[]> SimPatches = new Dictionary<ulong, Patch[]>(); | ||
95 | private float[] DequantizeTable16 = new float[16 * 16]; | ||
96 | private float[] DequantizeTable32 = new float[32 * 32]; | ||
97 | private float[] ICosineTable16 = new float[16 * 16]; | ||
98 | private float[] ICosineTable32 = new float[32 * 32]; | ||
99 | private int[] DeCopyMatrix16 = new int[16 * 16]; | ||
100 | private int[] DeCopyMatrix32 = new int[32 * 32]; | ||
101 | |||
102 | |||
103 | /// <summary> | ||
104 | /// | ||
105 | /// </summary> | ||
106 | /// <param name="client"></param> | ||
107 | public TerrainDecode() | ||
108 | { | ||
109 | |||
110 | // Initialize the decompression tables | ||
111 | BuildDequantizeTable16(); | ||
112 | BuildDequantizeTable32(); | ||
113 | SetupICosines16(); | ||
114 | SetupICosines32(); | ||
115 | BuildDecopyMatrix16(); | ||
116 | BuildDecopyMatrix32(); | ||
117 | |||
118 | } | ||
119 | |||
120 | |||
121 | private void BuildDequantizeTable16() | ||
122 | { | ||
123 | for (int j = 0; j < 16; j++) | ||
124 | { | ||
125 | for (int i = 0; i < 16; i++) | ||
126 | { | ||
127 | DequantizeTable16[j * 16 + i] = 1.0f + 2.0f * (float)(i + j); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | private void BuildDequantizeTable32() | ||
133 | { | ||
134 | for (int j = 0; j < 32; j++) | ||
135 | { | ||
136 | for (int i = 0; i < 32; i++) | ||
137 | { | ||
138 | DequantizeTable32[j * 32 + i] = 1.0f + 2.0f * (float)(i + j); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
143 | private void SetupICosines16() | ||
144 | { | ||
145 | const float hposz = (float)Math.PI * 0.5f / 16.0f; | ||
146 | |||
147 | for (int u = 0; u < 16; u++) | ||
148 | { | ||
149 | for (int n = 0; n < 16; n++) | ||
150 | { | ||
151 | ICosineTable16[u * 16 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | private void SetupICosines32() | ||
157 | { | ||
158 | const float hposz = (float)Math.PI * 0.5f / 32.0f; | ||
159 | |||
160 | for (int u = 0; u < 32; u++) | ||
161 | { | ||
162 | for (int n = 0; n < 32; n++) | ||
163 | { | ||
164 | ICosineTable32[u * 32 + n] = (float)Math.Cos((2.0f * (float)n + 1.0f) * (float)u * hposz); | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | private void BuildDecopyMatrix16() | ||
170 | { | ||
171 | bool diag = false; | ||
172 | bool right = true; | ||
173 | int i = 0; | ||
174 | int j = 0; | ||
175 | int count = 0; | ||
176 | |||
177 | while (i < 16 && j < 16) | ||
178 | { | ||
179 | DeCopyMatrix16[j * 16 + i] = count++; | ||
180 | |||
181 | if (!diag) | ||
182 | { | ||
183 | if (right) | ||
184 | { | ||
185 | if (i < 16 - 1) i++; | ||
186 | else j++; | ||
187 | |||
188 | right = false; | ||
189 | diag = true; | ||
190 | } | ||
191 | else | ||
192 | { | ||
193 | if (j < 16 - 1) j++; | ||
194 | else i++; | ||
195 | |||
196 | right = true; | ||
197 | diag = true; | ||
198 | } | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | if (right) | ||
203 | { | ||
204 | i++; | ||
205 | j--; | ||
206 | if (i == 16 - 1 || j == 0) diag = false; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | i--; | ||
211 | j++; | ||
212 | if (j == 16 - 1 || i == 0) diag = false; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | |||
218 | private void BuildDecopyMatrix32() | ||
219 | { | ||
220 | bool diag = false; | ||
221 | bool right = true; | ||
222 | int i = 0; | ||
223 | int j = 0; | ||
224 | int count = 0; | ||
225 | |||
226 | while (i < 32 && j < 32) | ||
227 | { | ||
228 | DeCopyMatrix32[j * 32 + i] = count++; | ||
229 | |||
230 | if (!diag) | ||
231 | { | ||
232 | if (right) | ||
233 | { | ||
234 | if (i < 32 - 1) i++; | ||
235 | else j++; | ||
236 | |||
237 | right = false; | ||
238 | diag = true; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | if (j < 32 - 1) j++; | ||
243 | else i++; | ||
244 | |||
245 | right = true; | ||
246 | diag = true; | ||
247 | } | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | if (right) | ||
252 | { | ||
253 | i++; | ||
254 | j--; | ||
255 | if (i == 32 - 1 || j == 0) diag = false; | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | i--; | ||
260 | j++; | ||
261 | if (j == 32 - 1 || i == 0) diag = false; | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | private void EncodePatchHeader(BitPacker bitpack, PatchHeader header) | ||
268 | { | ||
269 | bitpack.PackBits(header.QuantWBits,8); | ||
270 | |||
271 | if (header.QuantWBits == END_OF_PATCHES) | ||
272 | return; | ||
273 | |||
274 | bitpack.PackFloat(header.DCOffset); | ||
275 | bitpack.PackBits(header.Range,16); | ||
276 | bitpack.PackBits(header.PatchIDs,10); | ||
277 | |||
278 | } | ||
279 | |||
280 | public void DCTLine16(float[] In, float[] Out, int line) | ||
281 | { | ||
282 | int N =16; | ||
283 | int lineSize = line * 16; | ||
284 | |||
285 | for(int k = 0; k < N;k++) | ||
286 | { | ||
287 | float sum = 0.0f; | ||
288 | for(int n = 0; n < N; n++) | ||
289 | { | ||
290 | float num = (float)(Math.PI*k*(2.0f*n+1)/(2*N)); | ||
291 | float cosine = (float)Math.Cos(num); | ||
292 | float product = In[lineSize +n] * cosine; | ||
293 | sum += product; | ||
294 | } | ||
295 | |||
296 | float alpha; | ||
297 | if(k == 0) | ||
298 | { | ||
299 | alpha = (float)(1.0f/Math.Sqrt(2)); | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | alpha = 1; | ||
304 | } | ||
305 | Out[lineSize + k] =(float)( sum * alpha ); | ||
306 | |||
307 | } | ||
308 | } | ||
309 | public void DCTColumn16(float[] In, float[] Out, int Column) | ||
310 | { | ||
311 | int N =16; | ||
312 | int uSize; | ||
313 | |||
314 | for(int k = 0; k < N; k++){ | ||
315 | float sum = 0.0f; | ||
316 | for(int n = 0; n < N; n++) | ||
317 | { | ||
318 | uSize = n * 16; | ||
319 | float num = (float)(Math.PI*k*(2.0f*n+1)/(2*N)); | ||
320 | float cosine = (float)Math.Cos(num); | ||
321 | float product = In[uSize + Column] * cosine; | ||
322 | sum += product; | ||
323 | } | ||
324 | |||
325 | float alpha; | ||
326 | if(k == 0) | ||
327 | { | ||
328 | alpha = (float)(1.0f/Math.Sqrt(2)); | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | alpha = 1; | ||
333 | } | ||
334 | Out[16 * k + Column] = (float)( sum * alpha * (2.0f /N)); | ||
335 | |||
336 | } | ||
337 | } | ||
338 | |||
339 | private void EncodePatch(int[] patches, BitPacker bitpack, int size) | ||
340 | { | ||
341 | int lastnum =0; | ||
342 | for(int n = 0; n < size * size; n++) | ||
343 | { | ||
344 | if(patches[n]!=0) | ||
345 | lastnum=n; | ||
346 | } | ||
347 | for (int n = 0; n < lastnum+1; n++) | ||
348 | { | ||
349 | if(patches[n] != 0) | ||
350 | { | ||
351 | bitpack.PackBits(1,1); //value or EOB | ||
352 | bitpack.PackBits(1,1); //value | ||
353 | if(patches[n] > 0) | ||
354 | { | ||
355 | |||
356 | bitpack.PackBits(0,1); // positive | ||
357 | bitpack.PackBits(patches[n],13); | ||
358 | |||
359 | } | ||
360 | else | ||
361 | { | ||
362 | bitpack.PackBits(1,1); // negative | ||
363 | |||
364 | int temp = patches[n] * -1; | ||
365 | bitpack.PackBits(temp,13); | ||
366 | |||
367 | } | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | bitpack.PackBits(0,1); // no value | ||
372 | } | ||
373 | } | ||
374 | |||
375 | bitpack.PackBits(1,1); //value or EOB | ||
376 | bitpack.PackBits(0,1); // EOB | ||
377 | } | ||
378 | |||
379 | public int[] CompressPatch(float[] patches) | ||
380 | { | ||
381 | int size = 16; | ||
382 | float[] block = new float[size * size]; | ||
383 | int[] output = new int[size * size]; | ||
384 | int prequant = (139 >> 4) + 2; | ||
385 | int quantize = 1 << prequant; | ||
386 | float ooq = 1.0f / (float)quantize; | ||
387 | float mult = ooq * (float)1; | ||
388 | float addval = mult * (float)(1 << (prequant - 1)) + 20.4989f; | ||
389 | |||
390 | if (size == 16) | ||
391 | { | ||
392 | for (int n = 0; n < 16 * 16; n++) | ||
393 | { | ||
394 | block[n] = (float)((patches[n] - addval)/ mult); | ||
395 | } | ||
396 | |||
397 | float[] ftemp = new float[32 * 32]; | ||
398 | |||
399 | for (int o = 0; o < 16; o++) | ||
400 | this.DCTColumn16(block, ftemp, o); | ||
401 | for (int o = 0; o < 16; o++) | ||
402 | this.DCTLine16(ftemp, block, o); | ||
403 | } | ||
404 | |||
405 | for (int j = 0; j < block.Length; j++) | ||
406 | { | ||
407 | output[DeCopyMatrix16[j]] = (int)(block[j] / DequantizeTable16[j]); | ||
408 | } | ||
409 | |||
410 | return output; | ||
411 | } | ||
412 | |||
413 | public Packet CreateLayerPacket(float[] heightmap, int minX, int minY, int maxX, int maxY) | ||
414 | { | ||
415 | //int minX = 0, maxX = 2, minY = 0, maxY = 1; //these should be passed to this function | ||
416 | LayerDataPacket layer = new LayerDataPacket(); | ||
417 | byte[] Encoded = new byte[2048]; | ||
418 | layer.LayerID.Type = 76; | ||
419 | GroupHeader header = new GroupHeader(); | ||
420 | header.Stride = 264; | ||
421 | header.PatchSize = 16; | ||
422 | header.Type = LayerType.Land; | ||
423 | BitPacker newpack = new BitPacker(Encoded,0); | ||
424 | newpack.PackBits(header.Stride,16); | ||
425 | newpack.PackBits(header.PatchSize,8); | ||
426 | newpack.PackBits((int)header.Type,8); | ||
427 | |||
428 | |||
429 | float[] height; | ||
430 | for(int y = minY; y< maxY; y++) | ||
431 | { | ||
432 | for(int x = minX ; x < maxX ; x++) | ||
433 | { | ||
434 | height = new float[256]; | ||
435 | Array.Copy(heightmap, (4096 *y) +(x *256), height, 0, 256); | ||
436 | |||
437 | this.CreatePatch(height, newpack, x, y); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | PatchHeader headers = new PatchHeader(); | ||
442 | headers.QuantWBits = END_OF_PATCHES; | ||
443 | this.EncodePatchHeader(newpack, headers); | ||
444 | |||
445 | int lastused=0; | ||
446 | for(int i = 0; i < 2048 ; i++) | ||
447 | { | ||
448 | if(Encoded[i] !=0) | ||
449 | lastused = i; | ||
450 | } | ||
451 | |||
452 | byte[] data = new byte[lastused+1]; | ||
453 | Array.Copy(Encoded, data, lastused+1); | ||
454 | layer.LayerData.Data =data; | ||
455 | |||
456 | return(layer); | ||
457 | } | ||
458 | public void CreatePatch(float[] heightmap, BitPacker newpack, int x, int y) | ||
459 | { | ||
460 | PatchHeader header = new PatchHeader(); | ||
461 | header.DCOffset = 20.4989f; | ||
462 | header.QuantWBits = 139; | ||
463 | header.Range = 1; | ||
464 | header.PatchIDs = (y & 0x1F); | ||
465 | header.PatchIDs += x <<5 ; | ||
466 | |||
467 | this.EncodePatchHeader(newpack, header); | ||
468 | |||
469 | int[] newpatch = this.CompressPatch(heightmap); | ||
470 | this.EncodePatch(newpatch, newpack, 16); | ||
471 | |||
472 | } | ||
473 | } | ||
474 | |||
475 | //*************************************************** | ||
476 | public class BitPacker | ||
477 | { | ||
478 | private const int MAX_BITS = 8; | ||
479 | |||
480 | private byte[] Data; | ||
481 | public int bytePos; | ||
482 | public int bitPos; | ||
483 | |||
484 | /// <summary> | ||
485 | /// Default constructor, initialize the bit packer / bit unpacker | ||
486 | /// with a byte array and starting position | ||
487 | /// </summary> | ||
488 | /// <param name="data">Byte array to pack bits in to or unpack from</param> | ||
489 | /// <param name="pos">Starting position in the byte array</param> | ||
490 | public BitPacker(byte[] data, int pos) | ||
491 | { | ||
492 | Data = data; | ||
493 | bytePos = pos; | ||
494 | } | ||
495 | |||
496 | /// <summary> | ||
497 | /// Pack a floating point value in to the data | ||
498 | /// </summary> | ||
499 | /// <param name="data">Floating point value to pack</param> | ||
500 | public void PackFloat(float data) | ||
501 | { | ||
502 | byte[] input = BitConverter.GetBytes(data); | ||
503 | PackBitArray(input, 32); | ||
504 | } | ||
505 | |||
506 | /// <summary> | ||
507 | /// Pack part or all of an integer in to the data | ||
508 | /// </summary> | ||
509 | /// <param name="data">Integer containing the data to pack</param> | ||
510 | /// <param name="totalCount">Number of bits of the integer to pack</param> | ||
511 | public void PackBits(int data, int totalCount) | ||
512 | { | ||
513 | byte[] input = BitConverter.GetBytes(data); | ||
514 | PackBitArray(input, totalCount); | ||
515 | } | ||
516 | |||
517 | /// <summary> | ||
518 | /// Unpacking a floating point value from the data | ||
519 | /// </summary> | ||
520 | /// <returns>Unpacked floating point value</returns> | ||
521 | public float UnpackFloat() | ||
522 | { | ||
523 | byte[] output = UnpackBitsArray(32); | ||
524 | |||
525 | if (!BitConverter.IsLittleEndian) Array.Reverse(output); | ||
526 | return BitConverter.ToSingle(output, 0); | ||
527 | } | ||
528 | |||
529 | /// <summary> | ||
530 | /// Unpack a variable number of bits from the data in to integer format | ||
531 | /// </summary> | ||
532 | /// <param name="totalCount">Number of bits to unpack</param> | ||
533 | /// <returns>An integer containing the unpacked bits</returns> | ||
534 | /// <remarks>This function is only useful up to 32 bits</remarks> | ||
535 | public int UnpackBits(int totalCount) | ||
536 | { | ||
537 | byte[] output = UnpackBitsArray(totalCount); | ||
538 | |||
539 | if (!BitConverter.IsLittleEndian) Array.Reverse(output); | ||
540 | return BitConverter.ToInt32(output, 0); | ||
541 | } | ||
542 | |||
543 | private void PackBitArray(byte[] data, int totalCount) | ||
544 | { | ||
545 | int count = 0; | ||
546 | int curBytePos = 0; | ||
547 | int curBitPos = 0; | ||
548 | |||
549 | while (totalCount > 0) | ||
550 | { | ||
551 | if (totalCount > (MAX_BITS )) | ||
552 | { | ||
553 | count = MAX_BITS ; | ||
554 | totalCount -= MAX_BITS ; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | count = totalCount; | ||
559 | totalCount = 0; | ||
560 | } | ||
561 | |||
562 | while (count > 0) | ||
563 | { | ||
564 | switch(count) | ||
565 | { | ||
566 | case 1: | ||
567 | if ((data[curBytePos] & (0x01)) != 0) | ||
568 | { | ||
569 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
570 | } | ||
571 | break; | ||
572 | case 2: | ||
573 | if ((data[curBytePos] & (0x02)) != 0) | ||
574 | { | ||
575 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
576 | } | ||
577 | break; | ||
578 | case 3: | ||
579 | if ((data[curBytePos] & (0x04)) != 0) | ||
580 | { | ||
581 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
582 | } | ||
583 | break; | ||
584 | case 4: | ||
585 | if ((data[curBytePos] & (0x08)) != 0) | ||
586 | { | ||
587 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
588 | } | ||
589 | break; | ||
590 | case 5: | ||
591 | if ((data[curBytePos] & (0x10)) != 0) | ||
592 | { | ||
593 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
594 | } | ||
595 | break; | ||
596 | case 6: | ||
597 | if ((data[curBytePos] & (0x20)) != 0) | ||
598 | { | ||
599 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
600 | } | ||
601 | break; | ||
602 | case 7: | ||
603 | if ((data[curBytePos] & (0x40)) != 0) | ||
604 | { | ||
605 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
606 | } | ||
607 | break; | ||
608 | case 8: | ||
609 | if ((data[curBytePos] & (0x80)) != 0) | ||
610 | { | ||
611 | Data[bytePos] |= (byte)(0x80 >> bitPos); | ||
612 | } | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | bitPos++; | ||
617 | --count; | ||
618 | ++curBitPos; | ||
619 | |||
620 | if (bitPos >= MAX_BITS) | ||
621 | { | ||
622 | bitPos = 0; | ||
623 | ++bytePos; | ||
624 | } | ||
625 | if (curBitPos >= MAX_BITS) | ||
626 | { | ||
627 | curBitPos = 0; | ||
628 | ++curBytePos; | ||
629 | } | ||
630 | } | ||
631 | } | ||
632 | } | ||
633 | |||
634 | |||
635 | private byte[] UnpackBitsArray(int totalCount) | ||
636 | { | ||
637 | int count = 0; | ||
638 | byte[] output = new byte[4]; | ||
639 | int curBytePos = 0; | ||
640 | int curBitPos = 0; | ||
641 | |||
642 | while (totalCount > 0) | ||
643 | { | ||
644 | if (totalCount > MAX_BITS) | ||
645 | { | ||
646 | count = MAX_BITS; | ||
647 | totalCount -= MAX_BITS; | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | count = totalCount; | ||
652 | totalCount = 0; | ||
653 | } | ||
654 | |||
655 | while (count > 0) | ||
656 | { | ||
657 | // Shift the previous bits | ||
658 | output[curBytePos] <<= 1; | ||
659 | |||
660 | // Grab one bit | ||
661 | if ((Data[bytePos] & (0x80 >> bitPos++)) != 0) | ||
662 | ++output[curBytePos]; | ||
663 | |||
664 | --count; | ||
665 | ++curBitPos; | ||
666 | |||
667 | if (bitPos >= MAX_BITS) | ||
668 | { | ||
669 | bitPos = 0; | ||
670 | ++bytePos; | ||
671 | } | ||
672 | if (curBitPos >= MAX_BITS) | ||
673 | { | ||
674 | curBitPos = 0; | ||
675 | ++curBytePos; | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | |||
680 | return output; | ||
681 | } | ||
682 | } | ||
683 | } | ||
diff --git a/src/world/World.cs b/src/world/World.cs index 83788cd..158ddc2 100644 --- a/src/world/World.cs +++ b/src/world/World.cs | |||
@@ -1,9 +1,9 @@ | |||
1 | using System; | 1 | using System; |
2 | using System.Threading; | 2 | using System.Threading; |
3 | using libsecondlife; | ||
4 | using libsecondlife.Packets; | ||
5 | using System.Collections.Generic; | 3 | using System.Collections.Generic; |
6 | using System.Text; | 4 | using System.Text; |
5 | using libsecondlife; | ||
6 | using libsecondlife.Packets; | ||
7 | 7 | ||
8 | namespace OpenSim.world | 8 | namespace OpenSim.world |
9 | { | 9 | { |
@@ -12,77 +12,98 @@ namespace OpenSim.world | |||
12 | public Dictionary<libsecondlife.LLUUID, Entity> Entities; | 12 | public Dictionary<libsecondlife.LLUUID, Entity> Entities; |
13 | public float[] LandMap; | 13 | public float[] LandMap; |
14 | public ScriptEngine Scripts; | 14 | public ScriptEngine Scripts; |
15 | public TerrainDecode terrainengine = new TerrainDecode(); | 15 | public uint _localNumber = 0; |
16 | public uint _localNumber=0; | 16 | public PhysicsEngine physics; |
17 | public PhysicsEngine physics; | 17 | |
18 | 18 | private libsecondlife.TerrainManager TerrainManager; | |
19 | private Random Rand = new Random(); | 19 | private Random Rand = new Random(); |
20 | 20 | ||
21 | public World() | 21 | public World() |
22 | { | 22 | { |
23 | OpenSim_Main.localcons.WriteLine("World.cs - creating new entitities instance"); | 23 | OpenSim_Main.localcons.WriteLine("World.cs - creating new entitities instance"); |
24 | Entities = new Dictionary<libsecondlife.LLUUID, Entity>(); | 24 | Entities = new Dictionary<libsecondlife.LLUUID, Entity>(); |
25 | |||
26 | OpenSim_Main.localcons.WriteLine("World.cs - creating LandMap"); | ||
27 | TerrainManager = new TerrainManager(new SecondLife()); | ||
28 | } | ||
25 | 29 | ||
26 | OpenSim_Main.localcons.WriteLine("World.cs - creating LandMap"); | 30 | public void InitLoop() |
27 | terrainengine = new TerrainDecode(); | 31 | { |
28 | LandMap = new float[65536]; | 32 | OpenSim_Main.localcons.WriteLine("World.cs:StartLoop() - Initialising physics"); |
29 | 33 | this.physics = new PhysicsEngine(); | |
34 | physics.Startup(); | ||
30 | } | 35 | } |
31 | 36 | ||
32 | public void InitLoop() { | 37 | public void DoStuff() |
33 | OpenSim_Main.localcons.WriteLine("World.cs:StartLoop() - Initialising physics"); | 38 | { |
34 | this.physics = new PhysicsEngine(); | 39 | lock (this) |
35 | physics.Startup(); | 40 | { |
36 | } | 41 | physics.DoStuff(this); |
37 | 42 | this.Update(); | |
38 | public void DoStuff() { | 43 | } |
39 | lock(this) { | 44 | } |
40 | physics.DoStuff(this); | ||
41 | this.Update(); | ||
42 | } | ||
43 | } | ||
44 | 45 | ||
45 | public void Update() { | 46 | public void Update() |
47 | { | ||
46 | foreach (libsecondlife.LLUUID UUID in Entities.Keys) | 48 | foreach (libsecondlife.LLUUID UUID in Entities.Keys) |
47 | { | 49 | { |
48 | if(Entities[UUID].needupdate) { | 50 | if (Entities[UUID].needupdate) |
49 | Entities[UUID].update(); | 51 | { |
50 | 52 | Entities[UUID].update(); | |
51 | if(Entities[UUID] is Avatar) { | 53 | |
52 | Avatar avatar=(Avatar)Entities[UUID]; | 54 | if (Entities[UUID] is Avatar) |
53 | if((avatar.oldpos!=avatar.position) || (avatar.oldvel!=avatar.velocity) || avatar.walking) { | 55 | { |
54 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = Entities[UUID].CreateTerseBlock(); | 56 | Avatar avatar = (Avatar)Entities[UUID]; |
55 | foreach(OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) { | 57 | if ((avatar.oldpos != avatar.position) || (avatar.oldvel != avatar.velocity) || avatar.walking) |
56 | ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); | 58 | { |
57 | terse.RegionData.RegionHandle = OpenSim_Main.cfg.RegionHandle; // FIXME | 59 | ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseBlock = Entities[UUID].CreateTerseBlock(); |
58 | terse.RegionData.TimeDilation = 0; | 60 | foreach (OpenSimClient client in OpenSim_Main.sim.ClientThreads.Values) |
59 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; | 61 | { |
60 | terse.ObjectData[0] = terseBlock; | 62 | ImprovedTerseObjectUpdatePacket terse = new ImprovedTerseObjectUpdatePacket(); |
61 | client.OutPacket(terse); | 63 | terse.RegionData.RegionHandle = OpenSim_Main.cfg.RegionHandle; // FIXME |
62 | } | 64 | terse.RegionData.TimeDilation = 0; |
63 | }} | 65 | terse.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1]; |
64 | } | 66 | terse.ObjectData[0] = terseBlock; |
67 | client.OutPacket(terse); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | } | ||
65 | } | 72 | } |
66 | } | 73 | } |
67 | 74 | ||
68 | public void SendLayerData(OpenSimClient RemoteClient) { | 75 | public void SendLayerData(OpenSimClient RemoteClient) |
69 | for(int x=0; x<16; x=x+4) for(int y=0; y<16; y++){ | 76 | { |
70 | Packet layerpack=this.terrainengine.CreateLayerPacket(LandMap, x,y,x+4,y+1); | 77 | int[] patches = new int[4]; |
71 | RemoteClient.OutPacket(layerpack); | ||
72 | } | ||
73 | } | ||
74 | 78 | ||
75 | public void AddViewerAgent(OpenSimClient AgentClient) { | 79 | for (int y = 0; y < 16; y++) |
76 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent"); | 80 | { |
77 | Avatar NewAvatar = new Avatar(AgentClient); | 81 | for (int x = 0; x < 16; x = x + 4) |
78 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world"); | 82 | { |
79 | this.Entities.Add(AgentClient.AgentID, NewAvatar); | 83 | patches[0] = x + 0 + y * 16; |
80 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake "); | 84 | patches[1] = x + 1 + y * 16; |
81 | NewAvatar.SendRegionHandshake(this); | 85 | patches[2] = x + 2 + y * 16; |
82 | this.Update(); // will work for now, but needs to be optimised so we don't update everything in the sim for each new user | 86 | patches[3] = x + 3 + y * 16; |
83 | } | ||
84 | 87 | ||
85 | public bool Backup() { | 88 | Packet layerpack = TerrainManager.CreateLandPacket(LandMap, patches); |
89 | RemoteClient.OutPacket(layerpack); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | public void AddViewerAgent(OpenSimClient AgentClient) | ||
95 | { | ||
96 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Creating new avatar for remote viewer agent"); | ||
97 | Avatar NewAvatar = new Avatar(AgentClient); | ||
98 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Adding new avatar to world"); | ||
99 | this.Entities.Add(AgentClient.AgentID, NewAvatar); | ||
100 | OpenSim_Main.localcons.WriteLine("World.cs:AddViewerAgent() - Starting RegionHandshake "); | ||
101 | NewAvatar.SendRegionHandshake(this); | ||
102 | this.Update(); // will work for now, but needs to be optimised so we don't update everything in the sim for each new user | ||
103 | } | ||
104 | |||
105 | public bool Backup() | ||
106 | { | ||
86 | /* TODO: Save the current world entities state. */ | 107 | /* TODO: Save the current world entities state. */ |
87 | 108 | ||
88 | return false; | 109 | return false; |