Testováno pouze na Windows 7 bez aera, dejte vědět jak kde (ne)funguje. Přepočítání trvá cca 16ms, při hodně velkém počtu updatů by to mohlo být i znát. Návrhy na zrychlení nebo pořešení problikávání při přepočtu klidně pište. Úplatky a sponzorské dary přijímám taky.
Screen: http://dl.dropbox.com/u/1799304/uo/reso ... ounter.png
Changelog:
27-08-2010 13:20: Fixed wrong packet usage
27-08-2010 13:07: Moar performance tweaks
27-08-2010 11:45: Performance update
Kód: Vybrat vše
//#define CONFIG_MODE
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using MulLib;
using Phoenix.Runtime;
using Phoenix.WorldData;
using Phoenix.Communication;
using System.Text;
namespace Phoenix.Scripts {
public class CreateCharacter {
[ClientMessageHandler(0x00)]
public CallbackResult OnCreateCharacter( byte[] data, CallbackResult prevResult ) {
byte[] bytes = Encoding.ASCII.GetBytes( "Kringelbert Fishtybuns" );
Array.Copy( bytes, 0, data, 10, bytes.Length );
return prevResult;
}
}
[RuntimeObject]
public class ResourceCounter : IDisposable {
private const int GWLP_WNDPROC = -4;
private const int BoxSpacing = 15;
public ResourceCounter() {
items = new List<IDrawable>() {
new ItemInfo( "BM", 0x0F7B, 0x0000, new Rectangle( 6, -4, 30, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "BP", 0x0F7A, 0x0000, new Rectangle( 17, -7, 10, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "GC", 0x0F84, 0x0000, new Rectangle( 0, -5, 30, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "GS", 0x0F85, 0x0000, new Rectangle( 15, -3, 20, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "MR", 0x0F86, 0x0000, new Rectangle( 11, -3, 20, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "NS", 0x0F88, 0x0000, new Rectangle( 5, 1, 30, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "SA", 0x0F8C, 0x0000, new Rectangle( 9, -4, 30, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "SS", 0x0F8D, 0x0000, new Rectangle( 8, -3, 20, SystemInformation.CaptionHeight - 2 ) ),
new Separator( "|" ),
new ItemInfo( "Bloodspawn", 0x0F7C, 0x0000, new Rectangle( 8, -3, 17, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Brimstone", 0x0F7F, 0x0000, new Rectangle( 17, -4, 15, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Obsidian", 0x0F89, 0x0000, new Rectangle( 7, -3, 25, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Blackmoor", 0x0F79, 0x0000, new Rectangle( 16, -4, 20, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Batwing", 0x0F78, 0x0000, new Rectangle( 14, -2, 16, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Eye of Newt", 0x0F87, 0x0000, new Rectangle( 16, -7, 9, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Vial of Blood", 0x0F7D, 0x0000, new Rectangle( 16, -1, 10, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "Bone", 0x0F7E, 0x0000, new Rectangle( 16, -3, 23, SystemInformation.CaptionHeight - 2 ) ),
new Separator( "|" ),
new ItemInfo( "TMR", 0x0F09, 0x0003, new Rectangle( 9, -1, 15, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "GH", 0x0F0C, 0x0000, new Rectangle( 9, -1, 15, SystemInformation.CaptionHeight - 2 ) ),
new ItemInfo( "TR", 0x0F0B, 0x0000, new Rectangle( 9, -1, 15, SystemInformation.CaptionHeight - 2 ) ),
new Separator( "|" ),
new ItemInfo( "Bandage", 0x0E21, 0x0000, new Rectangle( 11, -2, 22, SystemInformation.CaptionHeight - 2) ),
};
Debug.WriteLine( "Installing wndproc hook", "ResourceCounter" );
originalWndProc = NativeMethods.GetWindowLong( Client.HWND, GWLP_WNDPROC );
if ( originalWndProc == IntPtr.Zero )
throw new Win32Exception();
wndProc = new WndProcDelegate( WndProc );
if ( NativeMethods.SetWindowLong( Client.HWND, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate( wndProc ) ) == IntPtr.Zero )
throw new Win32Exception();
RuntimeCore.UnregisteringAssembly += new UnregisteringAssemblyEventHandler( RuntimeCore_UnregisteringAssembly );
Redraw();
}
~ResourceCounter() {
Dispose();
}
private List<IDrawable> items;
private WndProcDelegate wndProc;
private IntPtr originalWndProc;
public void Redraw() {
if ( ( from t in items.OfType<ItemInfo>()
join i in World.Player.Backpack.AllItems on new {
t.Graphic,
t.Color
} equals new {
i.Graphic,
i.Color
} into x
from i in x.DefaultIfEmpty()
group i by t into r
select new {
Type = r.Key,
Amount = r.Sum( a => a != null ? a.Amount : 0 )
} ).Count( i => i.Type.Update( i.Amount ) ) > 0 ) {
NativeMethods.SendMessage( Client.HWND, 0x85, IntPtr.Zero, IntPtr.Zero );
if ( Marshal.GetLastWin32Error() != 0 )
throw new Win32Exception();
}
}
[ServerMessageHandler( 0x33, Priority = CallbackPriority.Lowest )]
public CallbackResult OnAddItemToContainer( byte[] data, CallbackResult prevResult ) {
if ( data[ 1 ] == 0 )
Redraw();
return prevResult;
}
private IntPtr WndProc( IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam ) {
IntPtr result = NativeMethods.CallWindowProc( originalWndProc, hwnd, uMsg, wParam, lParam );
switch ( uMsg ) {
case 0x86: // WM_NCACTIVATE
case 0x85: // WM_NCPAINT
DrawStuff( hwnd );
break;
}
return result;
}
private void DrawStuff( IntPtr hwnd ) {
if ( !World.Player.Exist )
return;
IntPtr hDC = NativeMethods.GetWindowDC( hwnd );
Rectangle windowRect = new Rectangle();
if ( !NativeMethods.GetWindowRect( hwnd, ref windowRect ) )
throw new Win32Exception();
using ( Graphics graphics = Graphics.FromHdc( hDC ) ) {
float totalWidth = -BoxSpacing;
foreach ( IDrawable info in items )
totalWidth += info.Measure( graphics ) + BoxSpacing;
PointF p = new Point( SystemInformation.FrameBorderSize );
p.X += ( ( windowRect.Width - SystemInformation.CaptionHeight * 2 ) - totalWidth ) / 2;
p.Y += 1;
foreach ( IDrawable info in items )
p.X += info.Draw( graphics, p ) + BoxSpacing;
}
NativeMethods.ReleaseDC( hwnd, hDC );
}
#region Event handlers
private void RuntimeCore_UnregisteringAssembly( object sender, UnregisteringAssemblyEventArgs e ) {
Dispose();
}
#endregion
#region IDisposable
public void Dispose() {
if ( originalWndProc == IntPtr.Zero )
return;
Debug.WriteLine( "Removing wndproc hook", "ResourceCounter" );
if ( NativeMethods.SetWindowLong( Client.HWND, GWLP_WNDPROC, originalWndProc ) == IntPtr.Zero )
throw new Win32Exception();
GC.SuppressFinalize( this );
}
#endregion
#region Delegates
[UnmanagedFunctionPointer( CallingConvention.Winapi )]
private delegate IntPtr WndProcDelegate( IntPtr hwnd, uint uMsg, IntPtr wParam, IntPtr lParam );
#endregion
#region Nested type: IDrawable
private interface IDrawable {
bool Update( int itemCount );
float Measure( Graphics graphics );
float Draw( Graphics graphics, PointF point );
}
#endregion
#region Nested type: Separator
private class Separator : IDrawable {
public Separator( string text ) {
Text = text;
}
private float textWidth;
#region IDrawable
public bool Update( int itemCount ) {
return false;
}
public virtual float Measure( Graphics graphics ) {
textWidth = graphics.MeasureString( Text, SystemFonts.CaptionFont ).Width;
return textWidth;
}
public virtual float Draw( Graphics graphics, PointF point ) {
graphics.DrawString( Text, SystemFonts.CaptionFont, SystemBrushes.ActiveCaptionText, point );
return textWidth;
}
#endregion
#region Public properties
public string Text {
get;
private set;
}
#endregion
}
#endregion
#region Nested type: ItemInfo
private class ItemInfo : IDrawable {
public ItemInfo( string name, Graphic graphic, UOColor color, Rectangle iconBounds ) {
Name = name;
Graphic = graphic;
Color = color;
this.iconBounds = iconBounds;
prevAmount = -1;
Bitmap = DataFiles.Art.Items.Get( graphic );
if ( color.IsConstant && color != 0x0000 ) {
HueEntry hue = DataFiles.Hues.Get( color );
if ( hue != null )
Dyes.RecolorFull( hue, Bitmap );
}
}
private Rectangle iconBounds;
private string text;
private float textWidth;
private int prevAmount;
#region IDrawable
public bool Update( int amount ) {
if ( prevAmount == amount )
return false;
text = ": " + amount;
prevAmount = amount;
return true;
}
public float Measure( Graphics graphics ) {
textWidth = graphics.MeasureString( text, SystemFonts.CaptionFont ).Width;
return iconBounds.Width + textWidth;
}
public float Draw( Graphics graphics, PointF point ) {
#if CONFIG_MODE
graphics.DrawRectangle( Pens.Azure, point.X, point.Y, iconBounds.Width, iconBounds.Height );
#endif
graphics.DrawImage( Bitmap, point.X, point.Y, iconBounds, GraphicsUnit.Pixel );
point.X += iconBounds.Width;
point.Y = SystemInformation.FrameBorderSize.Height + ( SystemInformation.CaptionHeight - SystemFonts.CaptionFont.Height ) / 2 - 1;
graphics.DrawString( text, SystemFonts.CaptionFont, SystemBrushes.ActiveCaptionText, point );
return iconBounds.Width + textWidth;
}
#endregion
#region Public properties
public string Name {
get;
private set;
}
public Graphic Graphic {
get;
private set;
}
public UOColor Color {
get;
private set;
}
public Bitmap Bitmap {
get;
private set;
}
#endregion
}
#endregion
#region Native methods
private static class NativeMethods {
[DllImport( "user32.dll" )]
public static extern IntPtr CallWindowProc( IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam );
[DllImport( "user32.dll", SetLastError = true )]
public static extern IntPtr SetWindowLong( IntPtr hWnd, int nIndex, IntPtr dwNewLong );
[DllImport( "user32.dll", SetLastError = true )]
public static extern IntPtr GetWindowLong( IntPtr hWnd, int nIndex );
[DllImport( "user32.dll", SetLastError = true )]
public static extern IntPtr GetWindowDC( IntPtr hWnd );
[DllImport( "user32.dll" )]
public static extern int ReleaseDC( IntPtr hWnd, IntPtr hDC );
[DllImport( "user32.dll" )]
public static extern bool GetWindowRect( IntPtr hWnd, ref Rectangle lpRect );
[DllImport( "user32.dll" )]
public static extern bool UpdateWindow( IntPtr hWnd );
[DllImport( "user32.dll" )]
public static extern bool InvalidateRect( IntPtr hWnd, ref Rectangle lpRect, bool bErase );
[DllImport( "user32.dll", SetLastError = true )]
public static extern IntPtr SendMessage( IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam );
}
#endregion
}
}