/* * Copyright (c) 2006, Second Life Reverse Engineering Team * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the Second Life Reverse Engineering Team nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections; using System.Threading; namespace libsecondlife { /// /// Main class to expose Second Life functionality to clients. All of the /// classes are accessible through this class. /// public class SecondLife { public ProtocolManager Protocol; public NetworkManager Network; public ParcelManager Parcels; public MainAvatar Avatar; public Inventory Inventory; public ArrayList Regions; public Mutex RegionsMutex; public Region CurrentRegion; public byte[] CurrentParcelOverlay; public uint ParcelOverlaysReceived; public SecondLife(string keywordFile, string mapFile) { Protocol = new ProtocolManager(keywordFile, mapFile); Network = new NetworkManager(this, Protocol); Parcels = new ParcelManager(this); Avatar = new MainAvatar(this); Inventory = new Inventory(this); Regions = new ArrayList(); RegionsMutex = new Mutex(false, "RegionsMutex"); CurrentRegion = null; CurrentParcelOverlay = new byte[4096]; ParcelOverlaysReceived = 0; } public override string ToString() { return Avatar.FirstName + " " + Avatar.LastName; } public void Tick() { System.Threading.Thread.Sleep(0); } public Region FindRegion(string name) { RegionsMutex.WaitOne(); foreach (Region region in Regions) { if (region.Name == name) { RegionsMutex.ReleaseMutex(); return region; } } RegionsMutex.ReleaseMutex(); return null; } } /// /// Static helper functions and global variables /// public class Helpers { public readonly static string VERSION = "libsecondlife-cs 0.0.5"; public const byte MSG_APPENDED_ACKS = 0x10; public const byte MSG_RESENT = 0x20; public const byte MSG_RELIABLE = 0x40; public const byte MSG_ZEROCODED = 0x80; public const ushort MSG_FREQ_HIGH = 0x0000; public const ushort MSG_FREQ_MED = 0xFF00; public const ushort MSG_FREQ_LOW = 0xFFFF; public enum LogLevel { Info, Warning, Error }; /// /// Send a log message to the debugging output system /// /// The log message /// From the LogLevel enum, either Info, Warning, or Error public static void Log(string message, LogLevel level) { Console.WriteLine(level.ToString() + ": " + message); } /// /// Converting a variable length field (byte array) to a string /// /// The Data member of the Field class you are converting public static string FieldToString(object data) { byte[] byteArray; try { byteArray = (byte[])data; } catch (Exception e) { Helpers.Log(e.ToString(), Helpers.LogLevel.Warning); return ""; } return System.Text.Encoding.ASCII.GetString(byteArray).Replace("\0", ""); } /// /// Decode a zerocoded byte array. Used to decompress packets marked /// with the zerocoded flag. Any time a zero is encountered, the /// next byte is a count of how many zeroes to expand. One zero is /// encoded with 0x00 0x01, two zeroes is 0x00 0x02, three zeroes is /// 0x00 0x03, etc. The first four bytes are copied directly to the /// output buffer. /// /// The byte array to decode /// The length of the byte array to decode /// The output byte array to decode to /// The length of the output buffer public static int ZeroDecode(byte[] src, int srclen, byte[] dest) { uint zerolen = 0; try { Array.Copy(src, 0, dest, 0, 4); zerolen += 4; for (uint i = zerolen; i < srclen; i++) { if (src[i] == 0x00) { for (byte j = 0; j < src[i + 1]; j++) { dest[zerolen++] = 0x00; } i++; } else { dest[zerolen++] = src[i]; } } } catch (Exception e) { Helpers.Log(e.ToString(), Helpers.LogLevel.Error); } return (int)zerolen; } /// /// Encode a byte array with zerocoding. Used to compress packets marked /// with the zerocoded flag. Any zeroes in the array are compressed down /// to a single zero byte followed by a count of how many zeroes to expand /// out. A single zero becomes 0x00 0x01, two zeroes becomes 0x00 0x02, /// three zeroes becomes 0x00 0x03, etc. The first four bytes are copied /// directly to the output buffer. /// /// The byte array to encode /// The length of the byte array to encode /// The output byte array to encode to /// The length of the output buffer public static int ZeroEncode(byte[] src, int srclen, byte[] dest) { uint zerolen = 0; byte zerocount = 0; Array.Copy(src, 0, dest, 0, 4); zerolen += 4; for (uint i = zerolen; i < srclen; i++) { if (src[i] == 0x00) { zerocount++; if (zerocount == 0) { dest[zerolen++] = 0x00; dest[zerolen++] = 0xff; zerocount++; } } else { if (zerocount != 0) { dest[zerolen++] = 0x00; dest[zerolen++] = (byte)zerocount; zerocount = 0; } dest[zerolen++] = src[i]; } } if (zerocount != 0) { dest[zerolen++] = 0x00; dest[zerolen++] = (byte)zerocount; } return (int)zerolen; } } }