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!

C# Scripting: Objects, Classes, Constructors, and Inheritance

Lokai

Knight
C# Scripting: Objects, Classes, Constructors, and Inheritance

Objects, Classes, Constructors, and Inheritance

Objects:

An object is the base class of all classes.

Think of it this way: every Item, Mobile, Integer, String, Packet, Socket, etc. is an object. As such, each of these 'Inherits' certain things which define how they can be dealt with in code, how they interact with eachother, and how we get information into or out of them, from their ultimate Parent type -- object.

What does an object look like?

An object is defined by its characteristics, just like food, or government, or a person is defined by their characteristics. What defines every object are the properties it keeps, the methods we use to access those properties, and the methods that define what the object can do, think, say, write, or read. For example: PlayerMobile is a class derived from the Mobile class, which is derived from the object class. So, PlayerMobile is an object, which inherits some things from object, more things from Mobile, and finally has even more characteristics not found in either object or Mobile, which define who or what it is.

Class:

The class is the definition of a new type of object.

A class is always derived from a Parent class of some type, and can sometimes have Child classes which are derived from it. We will call a Parent class a "Superclass", and a Child class a "subclass". For example, as stated earlier, every class derives from the ultimate superclass - object, and Item, Mobile, etc. are considered subclasses. PlayerMobile is a subclass of Mobile, BaseContainer is a subclass of Item, and Backpack is a subclass of BaseContainer. Every subclass "inherits" all of the properties, attributes, methods, or characteristics, of its Parent or Parents (its superclasses.) These characteristics can be overriden in the subclass, but if not otherwise specified, they will behave like their superclass counterparts.

Property:

Properties are the bits and pieces that describe the basic parts of a class. Properties have a datatype, a variable name, and a value. They can also have an accessibility defined. If not specified, the accessibility is Private. It can also be Public, or Protected. Properties are defined, and usually initialized in the beginning of the definition of a class, and serve to create a "description" of the class. For example:

Code:
private int Size = 4;
int Color = 302;
string Name = "TestClass";

Method:

A method is a means of interacting with the class.

Methods also have accessibility, datatype (called "return type") and name. In addition, they can have zero or more parameters passed to them which help control what happens when the method is "called" from the outside. "Calling" a method simply means using the name of the method, and giving it any parameters it is expecting to receive. For example, this method is called "GetName" and it accepts no parameters, and it returns a datatype 'String' back to the program that called it:

Code:
public string GetName()
{
 return Name;
}

Here is what this method might look like inside a class:

Code:
public class TestClass
{
 private string Name = "TestClass";
 public string GetName()
 {
  return Name;
 }
}

And here is what the code of a program might look like that calls this method:

Code:
string MyString;
MyString = TestClass.GetName();
Console.WriteLine(MyString);

That code should output the word "TestClass" to the Console.
If no return type is specified, the word 'void' must be used in its place. This indicates that the method will not return any values to the program calling it, but will instead simply perform whatever operations it needs to perform on its own.

Constructors:

A constructor is the method of initializing an instance of a class.

A constructor is called when the 'new' keyword is used or when a System Reflection is used to instantiate an object.

The constructor resembles a method, but has no return type, and the name of the method is always the same as the class itself. Every constructor of every class other than the 'object' class either explicitly or implicitly calls a base class, or another constructor from the same class.

There are two forms of constructor initializer - one which calls a base class constructor and one which calls another constructor from this class, using the this (...) syntax. There must always be a "chain" of constructors which runs all the way up the class hierarchy. Every class in the hierarchy will have a constructor invoked, although some of those constructors may not explicitly appear in the code. The parameters (if any) within the brackets of base(...) or this(...) are passed as the parameters to the invoked constructors. They can be the parameters given in the constructor declaration, but don't have to be. Here's an example:

Code:
public class MyTestClass
{
    public MyTestClass (int x) : base() // Invokes the parameterless constructor in object ( the " : base()" can be omitted.)
    {
        Console.WriteLine ("In the base class constructor taking an int, which is " + x);
    }
}
public class MyDerivedTestClass : MyTestClass
{
    public MyDerivedTestClass () : this (10) // Invokes the MyDerivedTestClass constructor taking an int
    {
        Console.WriteLine ("Received no parameters, and passed 10 to this class.");
    }
    public MyDerivedTestClass (int y) : base (y * 5) // Invokes the MyTestClass constructor, gets an int, and passes an int
    {
        Console.WriteLine ("Received {0}, and passed {1} to the base class.", y, y * 5);
    }
              
    public MyDerivedTestClass (string x) : base (50) // Invokes the MyTestClass constructor, gets a string, and passes an int
    {
        Console.WriteLine ("Received a string, and passed 50 to the base class.");
    }
}

With the above code, a bit of code saying new MyDerivedTestClass(); would invoke the MyDerivedTestClass parameterless constructor, which would in turn invoke the MyDerivedTestClass constructor which takes an int parameter (with 10 as that parameter value), which would in turn invoke the MyTestClass constructor which takes an int parameter (with 10 * 5 as that parameter value).

Not all constructors in the hierarchy need to be invoked, as demonstrated above - the constructor taking a string parameter is not invoked at all when you do new MyDerivedTestClass() - but as stated earlier, there must be at least one constructor invoked in each class in the hierarchy.
 

Kitchen_

Sorceror
Lokai;694876 said:
Property:

Properties are the bits and pieces that describe the basic parts of a class. Properties have a datatype, a variable name, and a value. They can also have an accessibility defined. If not specified, the accessibility is Private. It can also be Public, or Protected. Properties are defined, and usually initialized in the beginning of the definition of a class, and serve to create a "description" of the class. For example:

Code:
private int Size = 4;
int Color = 302;
string Name = "TestClass";

Fields: Fields (C# Programming Guide)

Properties: Properties (C# Programming Guide)

:)
 

Lokai

Knight
C# Scripting: Breaking down an example script

C# Scripting: breaking down some of the basics using a simple script as an example

You may have trouble reading the script here, so it is also attached below.

PHP:
/* ~using~
 * 
 * This section says which namespaces we want to include (or 'use') when scripting this item.
    when we add something here, it allows us to shorten the convention we use to refer to 
    things elsewhere in the script. For example, we use the class 'ArmorMaterialType' in
    this script. But, that class is not defined in this script, so how does the program know
    what it is? It assumes that we mean Server.Items.ArmorMaterialType, since we are using
    Server.Items, we can shorten that to just the last part. See the 'namespace' description
    below for more about namespaces.
 */
using System;
using Server.Items;

/* ~namespace~
 * 
 * The 'namespace' line tells the program where we want to 'store' the item, or how it is
    categorized. If you are making an Item, chances are you will place it in here. If you 
    are making a new type of Mobile, like a monster or vendor, you would probably place it
    in the Server.Mobiles namespace. Think of it like a container where they are all stored.
 */
namespace Server.Items
{
    /* ~attribute~
     * 
     * Attributes are a complicated subject. The 'FlipableAttribute' is needed so that we can have
        both a South-facing and an East-facing item. The hex numbers here (0x13be, 0x13c3) are 
        the ItemIDs that the item will use for South or East-facing. You will often have this
        attribute for Armor, Weapons, Furniture, etc.
     */
    [FlipableAttribute(0x13be, 0x13c3)]
    public class MyChainLegs : BaseArmor /* This is the class identifier. Here we give the name of
                                            our new class, and we also indicate what class our item
                                            is 'derived' from. We derive from another type so that
                                            our item can 'inherit' characteristics from that type.
                                            Basically, our item is a 'BaseArmor' with some modifications
                                            or 'overrides' as we call them.
                                          */
    {
        /* ~override~
         * 
         * These are the overrides. All of these are defined in BaseArmor, which is the base class for
            our item. We can override anything that is defined as either override or virtual in the
            previous class. Because these have only 'get' statements, we know that these are what are
            known as 'read-only' values. We can get the value, but we may NOT 'set' the value.
         */
        public override int BasePhysicalResistance { get { return 4; } }
        public override int BaseFireResistance { get { return 4; } }
        public override int BaseColdResistance { get { return 4; } }
        public override int BasePoisonResistance { get { return 1; } }
        public override int BaseEnergyResistance { get { return 2; } }

        public override int InitMinHits { get { return 45; } }
        public override int InitMaxHits { get { return 60; } }

        public override int AosStrReq { get { return 60; } }
        public override int OldStrReq { get { return 20; } }

        public override int OldDexBonus { get { return -3; } }

        public override int ArmorBase { get { return 28; } }

        public override ArmorMaterialType MaterialType { get { return ArmorMaterialType.Chainmail; } }

        /* ~Constructable~ 
         * 
         * This is another attribute. This particular attribute lets the compiler know
            that this item can be constructed. To simplify, we can use the [add command
            in-game, and create the item. */
        [Constructable]
        public MyChainLegs() /* This is the primary constructor for this class.*/
            : base(0x13BE) /* Here we specify what we are passing to the base class. Since this is
                                a type of 'BaseArmor', the BaseArmor constructor requires that we
                                include an integer value specifying the default ItemID of the item.
                                We 'pass' the ItemID 0x13BE, which is the ID for Chain Legs.*/
        {
            /* ~initializing the constructor~
             * 
             * Inside the constructor, we can 'initialize' values which are not read-only. In this
                case, we chose to set the weight of the item to '7'. This value would override any
                value defined in the base class, similar to the 'override' values above.*/
            Weight = 7.0;
        }

        /* ~overloading~
         * 
         * When you have 2 or more constructors, we call it 'overloading'. The most important rule to
            overloading is that each constructor must have a different set of values passed to it
            or you will get a compiler error. This is because it would have no way of knowing which
            constructor was being called if both of them looked the same. So, in this constructor, we
            are passing a 'Serial' type, whereas in the base constructor above, we pass nothing.
         */
        public MyChainLegs(Serial serial)
            : base(serial)
        {
        }

        /* ~Serialize~
         * 
         * Whenever the Server does a save, all items are automatically Serialized, meaning their
            values are saved to a binary storage file called a GenericWriter. We do this, so that
            when the Server is loaded, every item can be properly loaded in the state it was in
            the last time it was saved.
         */
        public override void Serialize(GenericWriter writer)
        {
            /*NOTE: It is critical when building the Serialize/Deserialize methods, you keep the
                Serialized items in the same order in both methods. Think of this like placing items
                in a row on a bookshelf. The first item you place when you Serialize needs to be the 
                first item you will be picking up when you Deserialize.
             */
            base.Serialize(writer); /*Here we call the Serialize method of the base class. Note, that
                                        we pass the same GenericWriter so that it can continue to use
                                        it to save whatever variables are stored in the base class.
                                     */
            writer.Write((int)0); /* ~explicit cast~
                                   * 
                                   * An explicit cast is when we use parentheses '()' around a datatype
                                        to indicate that we want the program to treat whatever comes
                                        after the parentheses as that datatype. If the value is normally
                                        viewed as another type, the program will convert it to the type
                                        that we specified.
                                   */
        }

        /* ~Deserialize~
         * 
         * Whenever the Server starts up, every item can be properly loaded in the state it was in
            the last time it was saved, if everything significant about the item was properly
            Serialized in the previous step.
         */
        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();
        }
    }
}
 

Attachments

  • LearningScript.cs
    7.4 KB · Views: 151

Lokai

Knight
Deegs;756965 said:
You have no idea how much this post is helping me at the moment. I am keeping that chainlegs script open while looking at other scripts to actually start to understand them better.


I do have a question regarding attributes i.e.

[FlipableAttribute(0x13be, 0x13c3)]
[Constructable]

Where exactly are those contained, and how do you know when you can use what attributes? Sort of like, how the overrides in that script, are derived from BaseArmor. Not sure if im making alot of sense.

Anyway, great post, I hope you will add some more, I for one am learning quite a bit from it.

+rep

For something like FlippableAttribute, you need InsideUO, or another tool that lets you see the images used. Basically, if the image of the item is facing one way, and there is another image facing another way, then FlippableAttribute lets you use the [flip command in game to change the facing of the item. This is especially important for furniture items, signs, and multis.

I STRONGLY recommend downloading Microsoft Visual C# Express Edition 2008. It's free, and can be found here:

Downloads

With it, you can right-click on a class name, its base class or any object, and navigate to the constructor or definition of that object. This will help you greatly with trying to figure out where a particular class is derived, what it's methods are, etc.
 

Vorspire

Knight
Lokai;694876 said:
...A class is always derived from a Parent class of some type...

A class is always an "object" but never "Always" derived from another class.

You can create your own "SuperClasses" that have no specific parents.

Examples:
Rich (BB code):
//A Derived "SubClass" using inheritance
public class SubClass : SuperClass
{
    //This is known as a "Ctor" or "Constructor", since we inherit "SuperClass", we must call it's "Ctor" using "base()"
    public SuperClass() : base(args) //"args" would be variables you pass to or set for, the base "Ctor", if any are required.
    {
          //Set the "SuperClass" variables here
    }
}

Rich (BB code):
//A custom "SuperClass", drop the inheritance
public class SuperClass
{
    //"Constructor", since we do not inherit anything, we do not need to define "base()"
    public SuperClass()
    {
          //Set Class Variables, which you need to define
    }
}

Rich (BB code):
//A custom "SuperClass", drop the inheritance, use custom variables
public class SuperClass
{
    //Define your new variables
    private int m_Int;
    private double m_Double;
    private bool m_Bool;
    private string m_String;

    //"Constructor", since we do not inherit anything, we do not need to define "base()"
    public SuperClass()
    {
          //Set Class Variables, which you need to define as above
          m_Int = 1234;
          m_Double = 123.4;
          m_Bool = true; //Or false
          m_String = "Hello World";
    }
}
 

daat99

Moderator
Staff member
I know that this thread isn't supposed to be in this scope, but I also know that Vorspire want to learn so I decided to correct minor errors:

Vorspire;757001 said:
A class is always an "object" but never "Always" derived from another class.
Every object is made from a class, but there are several classes that doesn't make objects (static classes can't be used to make objects).
Take for example the Utility.cs class from the core.
The class itself isn't static but all the methods inside it are static so making an object from that class won't serve any purpose.

Vorspire;757001 said:
You can create your own "SuperClasses" that have no specific parents.
All the classes are derived (behind the scenes) from a single parent: the "object" class itself.
That why before .NET 2.0 (which introduced generics) we could have a list of "objects" and insert any kind of object from any class we want into them.
The list simply expected an object from type "object" (the class) and because every single class is derived from the "object" class then they all match the criteria (even int, double, bool...).
 

Vlek

Sorceror
Your description was highly technical, and very hard to follow. David's was much better.
 

Vorspire

Knight
Your description was highly technical, and very hard to follow. David's was much better.

Just because you don't understand something one way, does not make another way "better", that's just ignorance.
But I guess since he titled his threads with the word "dummies" that's probably why you understood it "better".

I mean, please, by all means, learn enough and take time out of your busy schedule to write you own tutorial on the fundamentals of programming so I can tell you someone did it better.
 

Vlek

Sorceror
When writing a tutorial about the utmost basics of a scripting language, one most do so in a way that isn't so thick. So, yes, I can say one person did it better than another. I probably shouldn't have the way I did, but this tut could use some rethinking if it's going to be of any use to the people he's trying to reach with the tutorial: the beginners.
 

Vlek

Sorceror
Okay, instead, lets make this constructive:

Properties have a datatype, a variable name, and a value.

What are datatypes, variable names and values?

If not specified, the accessibility is Private. It can also be Public, or Protected.
What does the property setting Private, Public, or Protected do? How does that influence the way it functions?


The whole idea is still very confusing. They interact with classes, but can also be used in classes? What does "get name" do, and how is method used in a practical sense?

I would've been completely lost on the construction section as well if I didn't have some groundwork from other tutorials. I can barely follow along.
 

Sythen

Sorceror
Vlek you're preaching to the choir man and... this topic has been breached - just saying. It's impossible to get those who know how to code to dumb down their train of thought to where a 3rd grader could understand it because most of them are those, really above average intelligent, dudes who just don't have the capability of simplifying their thought processes; and the people who aren't all that intelligent, but know how to code through some miracle, seemingly want to get one over on the rest of us.

Also keep in mind the fact that just because people on here can code extremely well, doesn't necessarily make them good teachers. Teaching can get very frustrating at times and I'm willing to bet, through my own experiences on here, that the ones who could potentially code your entire server in a week, are the same people that probably punch their monitors and break their keyboards when they get player-killed in UO; so don't expect simplified tutorials because they don't have the patience to write them.

If you're so headstrong about tutorials, why don't you write one?! I mean we can never have enough and I'm sure there are people who would benefit from an elementary tutorial on C# and RunUO; keeping in mind that RunUO has its own variation of C# when calling specific actions from the server. My suggestion would be to start from the basics; ie. what is a method, statement, namespace etc. and then go into how to design simple RunUO scripts using those and create notations in the script files explaining what each segment of code does.

Tutorials can go from: Learning The Basics of RunUO, all the way to, Creating Advanced Systems Using Multiple Namespaces. There has to be a method to your madness, but what ever you do, go from A-Z and avoid skipping around. Eventually this could lead to helping Ryan with the .svn (making it a true community project rather than a select few trying to update it) because by making everything RunUO specific - editing core files becomes simplified. I see RunUO dwindling, the .svn is broken - it wont update... not a lot of people are as active as they used to be... and support seems limited - just an observation.

Anyway, i'm good at writing books in posts... didn't mean to offend anyone, I'm just trying to keep perspective on the tutorial thing because its a topic that comes up at least once or twice a year. lol
 

Vorspire

Knight
My wife has no idea how to program, but she perfectly understands the dumbed-down way that I explain things to her, maybe not right away, but she does, when I ask follow-up questions, she gets them right 90% of the time; She has absolutely no programming background and no interest in ever actually developing.

It really depends on the person doing the explaining.
The problem is, it's REALLY hard to explain a complex subject, here's why.

You ask: What is an "object"?
My Answer: Well, it's the most very basic structure of data in programming, every class is derived from an object some how.

You ask: Then, what's a class?
My Answer: A class is a data model, the structure that defines the skeleton of the object it represents.

You ask: So, what is a data model?
My Answer: The data model is the design of the structure of the class, much like the foundations of a building.

You ask: Right, but why did you call it a skeleton?
My Answer: We're going to be at this forever, JFGI.

Just for the record, I hold 1-to-1 sessions with many members of this community over PM or MSN in a bid to help them with further learning about RunUO and general programming, I do see myself as a teacher, however I don't know it all; I know enough for most people to consider me a guru, but that's their opinion based on their own experience and knowledge.
I believe this tutorial covered enough, in enough logical sense, for me to not need to write up another and tread on Lokai's toes.

One of the hardest things to do when answering young dev's questions about silly things is to keep it toned well, the mentor who helped me learn the basics all those years ago was a "know it all" with the facetious attitude to boot. -It's hard to dumb things down without coming across as a know-it-all asswipe IMO.

You'll find a few tutorials, or replies to tutorials by myself in this forum, I try to get things done in as simple a manner as possible, explaining specific terminology as it is cited, which I feel I did pretty well in this tutorial: http://www.runuo.com/community/thre...ariables-properties-and-serialization.104964/
 

Vlek

Sorceror
Are you offering to spend a little one on one time? I'd greatly appreciate it. I kinda got a little frustrated and didn't bother to read two posts down when he went line by line through a chainmail leggings item script. That was much more helpful seeing how things fit together instead of trying to compartmentalize the abstract parts. Now I would like to know how I'd go from looking at the overview.html, finding a class I'd like to make an item a sub of, and then using the information from the class in the script. Do you have IRC? I'm ususally in RunUO's IRC almost every day.
 
Top