RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

UltimaSDK for XNA

Poplicola

Sorceror
UltimaSDK for

I'm adding support for the XNA library to UltimaSDK as I work on an XNA Ultima Online client. I'll post my additions and modifications here, so that people can reference them as they work on their own XNA Ultima Online projects. You can also use these in your non-XNA projects that are using code from UltimaSDK by commenting out the "#define IsXNA" line, which will strip all references to the XNA library from the source during debug and compile.

I've also attached an image from the running engine which displays the pitch, yaw, roll, etc. values you will need to create an orthogonal projection that matches Ultima Online (well, nearly) in XNA.

Comments and suggestions are welcome!

UltimaSDK Art.cs (May 4, 2009)
Code:
// Poplicola last XNA Update: 5/4/09
// Comment out the following line if you are not referencing the XNA library.
#define IsXNA 

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
#if IsXNA
using Microsoft.Xna.Framework.Graphics;
#endif

namespace UndeadNET.UltimaSDK
{
	public sealed class Art
	{
		private static FileIndex m_FileIndex = new FileIndex( "Artidx.mul", "Art.mul", 0x10000, 4 );
		public static FileIndex FileIndex{ get{ return m_FileIndex; } }

		private static Bitmap[] m_Cache = new Bitmap[0x10000];
		private static Bitmap[] Cache{ get{ return m_Cache; } }
        

		private Art()
		{
		}

        public unsafe static void Measure(Bitmap bmp, out int xMin, out int yMin, out int xMax, out int yMax)
        {
            xMin = yMin = 0;
            xMax = yMax = -1;

            if (bmp == null || bmp.Width <= 0 || bmp.Height <= 0)
                return;

            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppRgb555);

            int delta = ((bd.Stride) >> 1) - bd.Width;
            int lineDelta = bd.Stride >> 1;

            ushort* pBuffer = (ushort*)bd.Scan0;
            ushort* pLineEnd = pBuffer + bd.Width;
            ushort* pEnd = pBuffer + (bd.Height * lineDelta);

            bool foundPixel = false;

            int x = 0, y = 0;

            while (pBuffer < pEnd)
            {
                while (pBuffer < pLineEnd)
                {
                    ushort c = *pBuffer++;

                    if ((c & 0x8000) != 0)
                    {
                        if (!foundPixel)
                        {
                            foundPixel = true;
                            xMin = xMax = x;
                            yMin = yMax = y;
                        }
                        else
                        {
                            if (x < xMin)
                                xMin = x;

                            if (y < yMin)
                                yMin = y;

                            if (x > xMax)
                                xMax = x;

                            if (y > yMax)
                                yMax = y;
                        }
                    }

                    ++x;
                }

                pBuffer += delta;
                pLineEnd += lineDelta;
                ++y;
                x = 0;
            }

            bmp.UnlockBits(bd);
        }

		public static Bitmap GetLand( int index )
		{
            return GetLand(index, true);
        }

        public static Bitmap GetLand(int index, bool cache)
        {
            index &= 0x3FFF;

            if (m_Cache[index] != null)
                return m_Cache[index];

            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            if (cache)
                return m_Cache[index] = LoadLand(stream);
            else
                return LoadLand(stream);
        }

        public static Bitmap GetStatic(int index)
        {
            return GetStatic(index, true);
        }

        public static Bitmap GetStatic(int index, bool cache)
		{
            if (index + 0x4000 > int.MaxValue)
            {
                throw new ArithmeticException("The index must not excede (int.MaxValue - 0x4000)");
            }

            index += 0x4000;
            index &= 0xFFFF;

			if ( m_Cache[index] != null )
				return m_Cache[index];

			int length, extra;
			bool patched;
			Stream stream = m_FileIndex.Seek( index, out length, out extra, out patched );

			if ( stream == null )
				return null;

            if (cache)
                return m_Cache[index] = LoadStatic(stream);
            else
                return LoadStatic(stream);
		}

		private static unsafe Bitmap LoadStatic( Stream stream )
		{
			BinaryReader bin = new BinaryReader( stream );

			bin.ReadInt32();
			int width = bin.ReadInt16();
			int height = bin.ReadInt16();

			if ( width <= 0 || height <= 0 )
				return null;

			int[] lookups = new int[height];

			int start = (int)bin.BaseStream.Position + (height * 2);

			for ( int i = 0; i < height; ++i )
				lookups[i] = (int)(start + (bin.ReadUInt16() * 2));

			Bitmap bmp = new Bitmap( width, height, PixelFormat.Format16bppRgb555 );
            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);

			ushort *line = (ushort *)bd.Scan0;
			int delta = bd.Stride >> 1;

			for ( int y = 0; y < height; ++y, line += delta )
			{
				bin.BaseStream.Seek( lookups[y], SeekOrigin.Begin );

				ushort *cur = line;
				ushort *end;

				int xOffset, xRun;

				while ( ((xOffset = bin.ReadUInt16()) + (xRun = bin.ReadUInt16())) != 0 )
				{
					cur += xOffset;
					end = cur + xRun;

					while ( cur < end )
						*cur++ = (ushort)(bin.ReadUInt16() ^ 0x8000);
				}
			}

			bmp.UnlockBits( bd );

			return bmp;
		}

		private static unsafe Bitmap LoadLand( Stream stream )
		{
            Bitmap bmp = new Bitmap(44, 44, PixelFormat.Format16bppRgb555);
            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, 44, 44), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
			BinaryReader bin = new BinaryReader( stream );

			int xOffset = 21;
			int xRun = 2;

			ushort *line = (ushort *)bd.Scan0;
			int delta = bd.Stride >> 1;

			for ( int y = 0; y < 22; ++y, --xOffset, xRun += 2, line += delta )
			{
				ushort *cur = line + xOffset;
				ushort *end = cur + xRun;

				while ( cur < end )
					*cur++ = (ushort)(bin.ReadUInt16() | 0x8000);
			}

			xOffset = 0;
			xRun = 44;

			for ( int y = 0; y < 22; ++y, ++xOffset, xRun -= 2, line += delta )
			{
				ushort *cur = line + xOffset;
				ushort *end = cur + xRun;

				while ( cur < end )
					*cur++ = (ushort)(bin.ReadUInt16() | 0x8000);
			}

			bmp.UnlockBits( bd );

			return bmp;
		}

        #if IsXNA
        private static Texture2D[] m_CacheXNA = new Texture2D[0x10000];

        public static Texture2D GetLandXNA(GraphicsDevice nGraphicsDevice, int index)
        {
            return GetLandXNA(nGraphicsDevice, index, true);
        }

        public static Texture2D GetLandXNA(GraphicsDevice nGraphicsDevice, int index, bool cache)
        {
            index &= 0x3FFF;

            if (m_Cache[index] != null)
                return m_CacheXNA[index];

            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            if (cache)
                return m_CacheXNA[index] = LoadLandXNA(nGraphicsDevice, stream);
            else
                return LoadLandXNA(nGraphicsDevice, stream);
        }

        public static Texture2D GetStaticXNA(GraphicsDevice nGraphicsDevice, int index)
        {
            return GetStaticXNA(nGraphicsDevice, index, true);
        }

        public static Texture2D GetStaticXNA(GraphicsDevice nGraphicsDevice, int index, bool cache)
        {
            if (index + 0x4000 > int.MaxValue)
            {
                throw new ArithmeticException("The index must not excede (int.MaxValue - 0x4000)");
            }

            index += 0x4000;
            index &= 0xFFFF;

            if (m_CacheXNA[index] != null)
                return m_CacheXNA[index];

            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            if (cache)
                return m_CacheXNA[index] = LoadStaticXNA(nGraphicsDevice, stream);
            else
                return LoadStaticXNA(nGraphicsDevice, stream);
        }

        private static unsafe Texture2D LoadStaticXNA(GraphicsDevice nGraphicsDevice, Stream stream)
        {
            BinaryReader bin = new BinaryReader(stream);
            bin.ReadInt32();
            int width = bin.ReadInt16();
            int height = bin.ReadInt16();

            if (width <= 0 || height <= 0)
                return null;

            int[] lookups = new int[height];

            int start = (int)bin.BaseStream.Position + (height * 2);

            for (int i = 0; i < height; ++i)
                lookups[i] = (int)(start + (bin.ReadUInt16() * 2));

            int iHeightOffset = 0;
            if (height < 44)
            {
                iHeightOffset = 44 - height;
            }

            uint[] pixels = new uint[width * (height + iHeightOffset)];
            fixed (uint* iFirstPixel = &pixels[0])
            {
                for (int y = 0; y < height; ++y)
                {
                    bin.BaseStream.Seek(lookups[y], SeekOrigin.Begin);

                    int xOffset, xRun;

                    uint* cur = iFirstPixel + (y + iHeightOffset) * width;
                    uint* end;

                    while (((xOffset = bin.ReadUInt16()) + (xRun = bin.ReadUInt16())) != 0)
                    {
                        cur += xOffset;
                        end = cur + xRun;

                        while (cur < end)
                        {
                            uint color = (uint)bin.ReadUInt16() ^ 0x8000;
                            *cur++ = 0xff000000 + (
                                    ((((color >> 10) & 0x1F) * 0xFF / 0x1F) << 16) |
                                    ((((color >> 5) & 0x1F) * 0xFF / 0x1F) << 8) |
                                    (((color & 0x1F) * 0xFF / 0x1F))
                                    );
                        }
                    }
                }
            }
            Texture2D iTexture = new Texture2D(nGraphicsDevice, width, height + iHeightOffset);
            iTexture.SetData(pixels);
            return iTexture;
        }

        private static unsafe Texture2D LoadLandXNA(GraphicsDevice nGraphicsDevice, Stream stream)
        {
            BinaryReader bin = new BinaryReader(stream);
            int xOffset = 21;
            int xRun = 2;

        
            uint[] pixels = new uint[44 * 44];
            fixed (uint* iFirstPixel = &pixels[0])
            {
                for (int y = 0; y < 22; ++y, --xOffset, xRun += 2)
                {
                    uint* cur = iFirstPixel + (y * 44) + xOffset;
                    uint* end = cur + xRun;

                    while (cur < end)
                    {
                        uint color = (uint)bin.ReadUInt16() ^ 0x8000;
                        *cur++ = 0xff000000 + (
                                    ((((color >> 10) & 0x1F) * 0xFF / 0x1F) << 16) |
                                    ((((color >> 5) & 0x1F) * 0xFF / 0x1F) << 8) |
                                    (((color & 0x1F) * 0xFF / 0x1F))
                                    );
                    }
                }

                xOffset = 0;
                xRun = 44;

                for (int y = 0; y < 22; ++y, ++xOffset, xRun -= 2)
                {
                    uint* cur = iFirstPixel + ((y + 22) * 44) + xOffset;
                    uint* end = cur + xRun;

                    while (cur < end)
                    {
                        uint color = (uint)bin.ReadUInt16() ^ 0x8000;
                        *cur++ = 0xff000000 + (
                                    ((((color >> 10) & 0x1F) * 0xFF / 0x1F) << 16) |
                                    ((((color >> 5) & 0x1F) * 0xFF / 0x1F) << 8) |
                                    (((color & 0x1F) * 0xFF / 0x1F))
                                    );
                    }
                }
            }

            Texture2D iTexture = new Texture2D(nGraphicsDevice, 44, 44);
            iTexture.SetData(pixels);
            return iTexture;
        }
        #endif
	}
}

UltimaSDK Gumps.cs (May 4, 2009)
Code:
// Poplicola last XNA Update: 5/4/09
// Comment out the following line if you are not referencing the XNA library.
#define IsXNA 
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
#if IsXNA
using Microsoft.Xna.Framework.Graphics;
#endif

namespace UndeadNET.UltimaSDK
{
    public class Gumps
    {
        private static FileIndex m_FileIndex = new FileIndex("Gumpidx.mul", "Gumpart.mul", 0x10000, 12);
        public static FileIndex FileIndex { get { return m_FileIndex; } }

        private static byte[] m_PixelBuffer;
        private static byte[] m_StreamBuffer;
        private static byte[] m_ColorTable;

        public unsafe static Bitmap GetGump(int index, Hue hue, bool onlyHueGrayPixels)
        {
            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            int width = (extra >> 16) & 0xFFFF;
            int height = extra & 0xFFFF;

            if (width <= 0 || height <= 0)
                return null;

            int bytesPerLine = width << 1;
            int bytesPerStride = (bytesPerLine + 3) & ~3;
            int bytesForImage = height * bytesPerStride;

            int pixelsPerStride = (width + 1) & ~1;
            int pixelsPerStrideDelta = pixelsPerStride - width;

            byte[] pixelBuffer = m_PixelBuffer;

            if (pixelBuffer == null || pixelBuffer.Length < bytesForImage)
                m_PixelBuffer = pixelBuffer = new byte[(bytesForImage + 2047) & ~2047];

            byte[] streamBuffer = m_StreamBuffer;

            if (streamBuffer == null || streamBuffer.Length < length)
                m_StreamBuffer = streamBuffer = new byte[(length + 2047) & ~2047];

            byte[] colorTable = m_ColorTable;

            if (colorTable == null)
                m_ColorTable = colorTable = new byte[128];

            stream.Read(streamBuffer, 0, length);

            fixed (short* psHueColors = hue.Colors)
            {
                fixed (byte* pbStream = streamBuffer)
                {
                    fixed (byte* pbPixels = pixelBuffer)
                    {
                        fixed (byte* pbColorTable = colorTable)
                        {
                            ushort* pHueColors = (ushort*)psHueColors;
                            ushort* pHueColorsEnd = pHueColors + 32;

                            ushort* pColorTable = (ushort*)pbColorTable;

                            ushort* pColorTableOpaque = pColorTable;

                            while (pHueColors < pHueColorsEnd)
                                *pColorTableOpaque++ = *pHueColors++;

                            ushort* pPixelDataStart = (ushort*)pbPixels;

                            int* pLookup = (int*)pbStream;
                            int* pLookupEnd = pLookup + height;
                            int* pPixelRleStart = pLookup;
                            int* pPixelRle;

                            ushort* pPixel = pPixelDataStart;
                            ushort* pRleEnd = pPixel;
                            ushort* pPixelEnd = pPixel + width;

                            ushort color, count;

                            if (onlyHueGrayPixels)
                            {
                                while (pLookup < pLookupEnd)
                                {
                                    pPixelRle = pPixelRleStart + *pLookup++;
                                    pRleEnd = pPixel;

                                    while (pPixel < pPixelEnd)
                                    {
                                        color = *(ushort*)pPixelRle;
                                        count = *(1 + (ushort*)pPixelRle);
                                        ++pPixelRle;

                                        pRleEnd += count;

                                        if (color != 0 && (color & 0x1F) == ((color >> 5) & 0x1F) && (color & 0x1F) == ((color >> 10) & 0x1F))
                                            color = pColorTable[color >> 10];
                                        else if (color != 0)
                                            color ^= 0x8000;

                                        while (pPixel < pRleEnd)
                                            *pPixel++ = color;
                                    }

                                    pPixel += pixelsPerStrideDelta;
                                    pPixelEnd += pixelsPerStride;
                                }
                            }
                            else
                            {
                                while (pLookup < pLookupEnd)
                                {
                                    pPixelRle = pPixelRleStart + *pLookup++;
                                    pRleEnd = pPixel;

                                    while (pPixel < pPixelEnd)
                                    {
                                        color = *(ushort*)pPixelRle;
                                        count = *(1 + (ushort*)pPixelRle);
                                        ++pPixelRle;

                                        pRleEnd += count;

                                        if (color != 0)
                                            color = pColorTable[color >> 10];

                                        while (pPixel < pRleEnd)
                                            *pPixel++ = color;
                                    }

                                    pPixel += pixelsPerStrideDelta;
                                    pPixelEnd += pixelsPerStride;
                                }
                            }

                            return new Bitmap(width, height, bytesPerStride, PixelFormat.Format16bppArgb1555, (IntPtr)pPixelDataStart);
                        }
                    }
                }
            }
        }

        public unsafe static Bitmap GetGump(int index)
        {
            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            int width = (extra >> 16) & 0xFFFF;
            int height = extra & 0xFFFF;

            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppRgb555);
            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
            BinaryReader bin = new BinaryReader(stream);

            int[] lookups = new int[height];
            int start = (int)bin.BaseStream.Position;

            for (int i = 0; i < height; ++i)
                lookups[i] = start + (bin.ReadInt32() * 4);

            ushort* line = (ushort*)bd.Scan0;
            int delta = bd.Stride >> 1;

            for (int y = 0; y < height; ++y, line += delta)
            {
                bin.BaseStream.Seek(lookups[y], SeekOrigin.Begin);

                ushort* cur = line;
                ushort* end = line + bd.Width;

                while (cur < end)
                {
                    ushort color = bin.ReadUInt16();
                    ushort* next = cur + bin.ReadUInt16();

                    if (color == 0)
                    {
                        cur = next;
                    }
                    else
                    {
                        color ^= 0x8000;

                        while (cur < next)
                            *cur++ = color;
                    }
                }
            }

            bmp.UnlockBits(bd);
            return bmp;
        }

        #if IsXNA
        public unsafe static Texture2D GetGumpXNA(GraphicsDevice nGraphicsDevice, int index)
        {
            int length, extra;
            bool patched;
            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            int width = (extra >> 16) & 0xFFFF;
            int height = extra & 0xFFFF;

            uint[] pixels = new uint[width * height];
            BinaryReader bin = new BinaryReader(stream);

            int[] lookups = new int[height];
            int start = (int)bin.BaseStream.Position;

            for (int i = 0; i < height; ++i)
                lookups[i] = start + (bin.ReadInt32() * 4);

            fixed (uint* line = &pixels[0])
            {
                for (int y = 0; y < height; ++y)
                {
                    bin.BaseStream.Seek(lookups[y], SeekOrigin.Begin);

                    uint* cur = line + (y * width);
                    uint* end = cur + (width);

                    while (cur < end)
                    {
                        uint color = bin.ReadUInt16();
                        uint* next = cur + bin.ReadUInt16();

                        if (color == 0)
                        {
                            cur = next;
                        }
                        else
                        {
                            uint color32 = 0xff000000 + (
                                ((((color >> 10) & 0x1F) * 0xFF / 0x1F) << 16) |
                                ((((color >> 5) & 0x1F) * 0xFF / 0x1F) << 8) |
                                (((color & 0x1F) * 0xFF / 0x1F) )
                                );
                            while (cur < next)
                                *cur++ = color32;
                        }
                    }
                }
            }

            Texture2D iTexture = new Texture2D(nGraphicsDevice, width, height);
            iTexture.SetData(pixels);
            return iTexture;
        }
        #endif
    }
}

UltimaSDK Textures.cs (May 4, 2009)
Code:
// Poplicola last XNA Update: 5/4/09
// Comment out the following line if you are not referencing the XNA library.
#define IsXNA 

using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

#if IsXNA
using Microsoft.Xna.Framework.Graphics;
#endif

namespace UndeadNET.UltimaSDK
{
    /// <summary>
    /// Part of the UltimaSDK library. This class loads and provides
    /// access to textures from the Ultima Online Client. You can
    /// load a texture as a 16bpp(RGB=555) bmp, or if you are
    /// using this in an XNA game, you can also load textures as XNA
    /// Texture2D objects.
    /// </summary>
    public class Textures
    {
        private static FileIndex m_FileIndex = new FileIndex("Texidx.mul", "Texmaps.mul", 0x4000, 10);
        private static FileIndex FileIndex { get { return m_FileIndex; } }

        /// <summary>
        /// Loads a UO Texture as a 16bpp(RGB=555) bmp.
        /// </summary>
        public unsafe static Bitmap GetTexture(int index)
        {
            int length, extra;
            bool patched;

            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            if (stream == null)
                return null;

            int size = extra == 0 ? 64 : 128;

            Bitmap bmp = new Bitmap(size, size, PixelFormat.Format16bppRgb555);
            BitmapData bd = bmp.LockBits(new Rectangle(0, 0, size, size), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
            BinaryReader bin = new BinaryReader(stream);

            ushort* line = (ushort*)bd.Scan0;
            int delta = bd.Stride >> 1;

            for (int y = 0; y < size; ++y, line += delta)
            {
                ushort* cur = line;
                ushort* end = cur + size;

                while (cur < end)
                    *cur++ = (ushort)(bin.ReadUInt16() ^ 0x8000);
            }

            bmp.UnlockBits(bd);

            return bmp;
        }

        #if IsXNA
        /// <summary>
        /// Loads a UO Texture as a XNA Texture2D object.
        /// Only works if you are referencing the XNA library.
        /// </summary>

        private static Texture2D[] m_XNATextureCache = new Texture2D[0x4000];

        public unsafe static Texture2D GetTextureXNA(GraphicsDevice nGraphicsDevice, int index)
        {
            if (m_XNATextureCache[index] != null)
                return m_XNATextureCache[index];

            int length, extra;
            bool patched;

            Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched);

            int size = extra == 0 ? 64 : 128;

            BinaryReader bin = new BinaryReader(stream);

            uint[] pixels = new uint[size * size];
            fixed (uint* line = &pixels[0])
            {
                uint* cur = line;
                for (int y = 0; y < size; ++y)
                {
                    uint* end = cur + size;
                    while (cur < end)
                    {
                        uint color = (uint)bin.ReadUInt16() ^ 0x8000;
                        *cur++ = 0xff000000 + (
                                ((((color >> 10) & 0x1F) * 0xFF / 0x1F) << 16) |
                                ((((color >> 5) & 0x1F) * 0xFF / 0x1F) << 8) |
                                (((color & 0x1F) * 0xFF / 0x1F))
                                );
                        *cur++ = color32;
                    }
                }
            }
            m_XNATextureCache[index] = new Texture2D(nGraphicsDevice, size, size);
            m_XNATextureCache[index].SetData(pixels);
            return m_XNATextureCache[index];
        }
        #endif
    }
}
 

Attachments

  • UndeadTest05042009.jpg
    UndeadTest05042009.jpg
    206.7 KB · Views: 167

Poplicola

Sorceror
I've continued working on this engine based on the UltimaSDK. I've added smoothly-moving player objects, mouse-based movement and tile-picking, and the xWinForms GUI. I've also adopted ClintXNA's renderer.

Entire source attached, comments and questions welcome. This is my first XNA project, so I'd especially appreciate help with regards to best practices.
 

Attachments

  • Screenshot.png
    Screenshot.png
    137.3 KB · Views: 108
  • UndeadTwo.zip
    934.7 KB · Views: 36

Poplicola

Sorceror
I am interested in making the client look as good as I can. First, however, I'll focus on getting gameplay elements up and running. Getting graphics perfect should be secondary to, say, combat.
 

Poplicola

Sorceror
I've now added per-face terrain lighting, receiving and display WorldItems and NPCs from the server, chat and global message display, and packet decoding and decompressing of the 35 packets that RunUO sends during player login.

I plan to work on Player equipment display; NPC display, movement, and animations; roof visibility when inside a building; and finally Player movement.
 

Attachments

  • Capture.JPG
    Capture.JPG
    214.2 KB · Views: 103

Poplicola

Sorceror
Since the last update, I've added:

NPC Display with equipment
NPC movement and animations
Roof transparency when inside a building, per floor.
Player equipment

Bugs that I can see are: Animations are not perfectly synced with movement, I haven't figured out the proper draw order for equipment, and robes are not drawing yet.

I am working on player movement and animations. Once I get that completed, I'll see if I can get hues working, fix the aforementioned bugs, and then I'll start work on the interface so I can begin interacting with the world. I'll probably work on an inventory window first.

I've attached two pictures to this post: the first is my client, and the second is the OSI client.
 

Attachments

  • Capture2.JPG
    Capture2.JPG
    180.5 KB · Views: 105
  • Compare3.JPG
    Compare3.JPG
    194.3 KB · Views: 95
Top