views:

575

answers:

2

I have a base class, BaseObject, and a number of classes which derive from BaseObject (DerivedObject1, DerivedObject2 etc)

I have a collection of BaseObjects in which I storing the derived objects. The code I use to do this is:

// declaring and initializing the idictionary
public IDictionary<ulong, BaseObject> ObjectList = new Dictionary<ulong, BaseObject>();
// how i add derived objects to the collection
ObjectList.Add(TempObject.Guid, new DerivedObject1(this, TempObject.BaseAddress));
ObjectList.Add(TempObject2.Guid, new DerivedObject2(this, TempObject2.BaseAddress));

In the class where the collection is held, I am declaring a reference to an important object in the collection like this:

// in the class
public DerivedObject3 LocalPlayer;
// in a method inside a class
LocalPlayer = (DerivedObject3)ObjectList[TempObject.Guid];

After I call the method that assigns LocalPlayer a reference to the object held in the Idictionary, I attempt to access information (specific to 'DerivedObject3') about LocalPlayer in my main method:

static void Main()
{
    ObjectManager OM = new ObjectManager();
    OM.LoadAddresses();
    OM.PopulateList();
    Console.WriteLine(OM.LocalPlayer.Type);
    Console.ReadLine();
}

However this is just returning '0'. I think I must have accidently 'reset' the object. I'm not too experienced with .NET or OOP in general (this is a hobby).

I can post more code (real code as opposed to 'BaseObject' etc) if necessary. Thankyou.

Edit After a comment that I needed to post more code (I'm not sure which bits are related to the problem) I will post more code (and not use "BaseObject" etc any more) WowObject classes:

class WowObject
{
    protected const uint GuidOffset = 0x30,
        NextObjectOffset = 0x3C,
        TypeOffset = 0x14,
        XPositionOffset = 0x7D0,
        YPositionOffset = 0x7D4,
        ZPositionOffset = 0x7D8,
        RotationOffset = 0x7DC,
        DescriptorFieldsOffset = 0x8;

    protected uint baseAddress;
    protected ObjectManager OM;

    public WowObject(ObjectManager OM, uint baseAddress)
    {
        this.baseAddress = baseAddress;
        this.OM = OM;
    }

    public uint BaseAddress
    {
        get { return baseAddress; }
        set { baseAddress = value; }
    }

    public uint DescriptorFields
    {
        get { return OM.ReadUInt32((IntPtr)(BaseAddress + DescriptorFieldsOffset)); }
    }

    public int Type
    {
        get { return OM.ReadInt32((IntPtr)(BaseAddress + TypeOffset)); }
    }

    public virtual ulong Guid
    {
        get { return OM.ReadULong((IntPtr)(BaseAddress + GuidOffset)); }
        set { return;  }
    }

    public virtual float XPos
    {
        get { return OM.ReadFloat((IntPtr)(BaseAddress + XPositionOffset)); }
    }

    public virtual float YPos
    {
        get { return OM.ReadFloat((IntPtr)(BaseAddress + YPositionOffset)); }
    }

    public virtual float ZPos
    {
        get { return OM.ReadFloat((IntPtr)(BaseAddress + ZPositionOffset)); }
    }

    public float Rotation
    {
        get { return OM.ReadFloat((IntPtr)(BaseAddress + RotationOffset)); }
    }
}

class CreatureObject : WowObject
{
    protected const uint LevelOffset = 0x35 * 4,
        CurrentHealthOffset = 0x17 * 4,
        MaxHealthOffset = 0x1F * 4,
        CurrentManaOffset = 0x18 * 4,
        MaxManaOffset = 0x20 * 4,
        TargetGuidOffset = 0x12*4;
    private CreatureObject targetObject;

    public CreatureObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public CreatureObject TargetObject
    {
        get { return targetObject; }
        set { targetObject = value; }
    }

    public ulong TargetGuid
    {
        get { return OM.ReadULong((IntPtr)(BaseAddress + TargetGuid)); }
    }

    public int Level
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + LevelOffset)); }
    }

    public int CurrentHealth
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + CurrentHealthOffset)); }
    }

    public int MaxHealth
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + MaxHealthOffset)); }
    }

    public int CurrentMana
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + CurrentMana)); }
    }

    public int MaxMana
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + MaxManaOffset)); }
    }

    public int HealthPercent
    {
        get
        {
            double percentage = CurrentHealth / MaxHealth;
            percentage = percentage * 100;
            return (int)Math.Round(percentage);
        }
    }
}

class NpcObject : CreatureObject
{
    protected const uint SummonedByOffset = 0xE * 4,
        AttackingGuidOffset = 0x0A38;

    public NpcObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public ulong AttackingGuid
    {
        get { return OM.ReadULong((IntPtr)(BaseAddress + AttackingGuidOffset)); }
    }

    public ulong SummonedBy
    {
        get { return OM.ReadULong((IntPtr)(DescriptorFields + SummonedByOffset)); }
    }
}

class PlayerObject : CreatureObject
{
    protected const uint CurrentRageOffset = 0x19 * 4,
        CurrentEnergyOffset = 0x1B * 4,
        MaxEnergyOffset = 0x23 * 4;

    public PlayerObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public int CurrentRage
    {
        get
        {
            int RageTemp = OM.ReadInt32((IntPtr)(DescriptorFields + CurrentRageOffset));
            return (int)(Math.Floor((double)(RageTemp / 10)));
        }
    }

    public int MaxRage
    {
        get { return 100; }
    }

    public int CurrentEnergy
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + CurrentEnergyOffset)); }
    }

    public int MaxEnergy
    {
        get { return OM.ReadInt32((IntPtr)(DescriptorFields + MaxEnergyOffset)); }
    }
}

class LocalCharacter : PlayerObject
{
    private ulong guid = 0;

    public LocalCharacter(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public override ulong Guid
    {
        get { return guid; }
        set { guid = value; }
    }
}

class GameObject : WowObject
{
    protected const uint gameObject_XPos = 0x10 * 4,
        gameObject_YPos = 0x11 * 4,
        gameObject_ZPos = 0x12 * 4;

    public GameObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public override float XPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + gameObject_XPos)); }
    }

    public override float YPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + gameObject_YPos)); }
    }

    public override float ZPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + gameObject_ZPos)); }
    }
}

class DynamicObject : WowObject
{
    protected const uint dynamicObject_XPos = 0xB * 4,
        dynamicObject_YPos = 0xC * 4,
        dynamicObject_ZPos = 0xD * 4;

    public DynamicObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public override float XPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + dynamicObject_XPos)); }
    }

    public override float YPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + dynamicObject_YPos)); }
    }

    public override float ZPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + dynamicObject_ZPos)); }
    }
}

class CorpseObject : WowObject
{
    protected const uint corpseObject_XPos = 0xB * 4,
            corpseObject_YPos = 0xC * 4,
            corpseObject_ZPos = 0xD * 4;

    public CorpseObject(ObjectManager OM, uint BaseAddress)
        : base(OM, BaseAddress)
    { }

    public override float XPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + corpseObject_XPos)); }
    }

    public override float YPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + corpseObject_YPos)); }
    }

    public override float ZPos
    {
        get { return OM.ReadFloat((IntPtr)(DescriptorFields + corpseObject_ZPos)); }
    }
}

The Object Manager - extends a memory reading class (which is where ReadUInt32 etc comes from)

class ObjectManager : Memory
{
    public IDictionary<ulong, WowObject> ObjectList = new Dictionary<ulong, WowObject>();

    public LocalCharacter LocalPlayer;

    private const uint staticClientConnection = 0x011CA310,     // static client connection, same address every boot
        objectManagerOffset = 0x28A4,                           // offset from the ClientConnection to the object manager
        localGuidOffset = 0xC0,                                 // offset from the object manager to the local guid
        firstObjectOffset = 0xAC,                               // offset from the object manager to the first object
        nextObjectOffset = 0x3C;                                // offset from
    private uint objectManagerBase;                             // the address off the object manager

    public void LoadAddresses()
    {
        objectManagerBase = ReadUInt32((IntPtr)(ReadUInt32((IntPtr)(staticClientConnection)) + objectManagerOffset));
        LocalPlayer = new LocalCharacter(this, ReadUInt32((IntPtr)(objectManagerBase + localGuidOffset)));
    }

    public void PopulateList()
    {
        WowObject TempObject = new WowObject(this, ReadUInt32((IntPtr)(objectManagerBase + firstObjectOffset)));

        while (TempObject.BaseAddress != 0 && TempObject.BaseAddress % 2 == 0)
        {
            if (TempObject.Type == 3)
                ObjectList.Add(TempObject.Guid, new NpcObject(this, TempObject.BaseAddress));
            if (TempObject.Type == 4)
            {
                if (TempObject.Guid != LocalPlayer.Guid)
                    ObjectList.Add(TempObject.Guid, new PlayerObject(this, TempObject.BaseAddress));
                else
                {
                    ObjectList.Add(TempObject.Guid, new PlayerObject(this, TempObject.BaseAddress));
                    LocalPlayer = (LocalCharacter)ObjectList[TempObject.Guid];
                }
            }

            TempObject.BaseAddress = ReadUInt32((IntPtr)(TempObject.BaseAddress + nextObjectOffset));
        }
    }
}

Main method:

static void Main()
{
    ObjectManager OM = new ObjectManager();
    OM.SetProcess("Wow", "Read");
    OM.LoadAddresses();
    OM.PopulateList();
    Console.WriteLine(OM.LocalPlayer.Type);
    Console.ReadLine();
}
A: 

Make the method from the base class virtual and the one from the derived class override. And a rule of thumb, avoid downcasting to a specific type, you should use properties/methods from the base class.

Adrian Magdas
A: 

If you store multiple objects of the same base type in a collection generally you never want to specify the exact type of the object. Take a look at this blog post on OOD principles. Specifically you're violating the Liskov Substitution principle which is explained briefly in this article and a more indepth explanation is linked to there.

I'd recommend reading over this article a few times, taking sometime to explore OOD both on the links included in that blog and on Wikipedia as it is a very technical subject. It's not something that can commonly be learned in a single reading. It's also something that requires conscious effort to use correctly even after you understand the concepts but it is basically imperative in writing software in the current day.

Chris Marisic