diff options
Diffstat (limited to '')
-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 |
4 files changed, 203 insertions, 743 deletions
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; |