Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a CVAR system

I would like to implement what I know as a CVAR System, I'm not entirely sure on what the official name of it is (if any).

It's essentially a system used in some programs and video games, where a user can pull down a console and input a command, such as "variable 500" to set that variable to 500. Instances of this can be found in any Half-Life game, Doom and Quake games, and many more. The general idea seems to be to hide the underlying architecture, but still allow protected access, for instance, one may be able to view the value for, say, gravity, but not change it. Some of these values may also be functions, for instance, a user may be able to input "create " to create an enemy type at their location, or some other location specified.

Looking through the Half Life 2 SDK, and from what I remember on the GoldSrc SDK, it seems like they at least implemented "flagging" of sorts, where certain commands would only work under certain conditions, such as if another value was set, or if the user has some permission level.

My initial thought was to create a Dictionary, or an object similar to do that, and use that to bind string values to function delegates, as well as keep a "protection" level of sorts, to limit usage of certain commands. However, this seems rather cumbersome, as I believe I would have to go through and add in a new entry manually for each value or function I wanted to implement. I also don't know if this would give me the control level I'm looking for.

I believe ideally what I would like would be a CVAR System class, as well as a Register function that can take it say, a variable/function delegate, a string to access it, and whatever protection level I need. This way I can add what I need as I see them, so everything is still in it's related classes and files.

I'm really just looking for some ideas here, so my questions are:

  • Has anyone ever done something like this before, and if so, how?
  • Would my implementation work? (Theoretically, if not, can you think of a better way?)
  • If someone is more knowledgeable with how one of the previously mentioned titles does it, can you elaborate on that a bit? It seems to be hard to find documentation on them.

I'm not really looking for specific code, just more of structuring design. And it doesn't have to be "commercial" or work just like another, I just need something to get me going.

like image 967
shmeeps Avatar asked Mar 03 '11 22:03

shmeeps


2 Answers

Were you thinking about something like this?

class CVAR
{
   [ProtectionLevel(CVARFlags.InGameOnly | CVARFlags.Admin)]
   private float gravity = 0.1f;

   [ProtectionLevel(CVARFlags.InGameOnly | CVARFlags.Admin)]
   private float friction = 0.1f;

   [ProtectionLevel(CVARFlags.ReadOnly)]
   private string serverVersion = "x.x.x";

   public void SetCVARValue(string commandLine) {
       string cvarName = GetCvarName(commandLine); // parse the cmd line and get the cvar name from there
       object cvarValue = GetCvarValue(commandLine); // parse the value from the string

       FieldInfo field = typeof(CVAR).GetField(cvarName);
       object[] attributes = field.GetCustomAttributes(typeof(ProtectionLevel), false);

       if(attributes.Length > 0) {
           ProtectionLevelAttribute attr = (ProtectionLevelAttribute)attributes[0];

           if(attr.CheckConditions(World.Instance)) {
               field.SetValue(this, cvarValue);
           } else {
               // error report
           }
       }
   }
}
like image 116
arul Avatar answered Nov 05 '22 10:11

arul


You could write a parser that looks for commands like

/object_property value
/object_method arg1 arg2

A dictionary, like you suggested, could map those strings to properties and functions. The creation of the dictionary could be done dynamically using reflection by looping through eligible objects, taking their public methods and accessors, and generating a string for them.

Then the dictionary could be mapped in a class for convenience and error checking.

For the methods, the dictionary values could be delegates that take 0..n arguments, for the properties/fields, you will need to be able to some data binding between your actual fields and the dictionary value. UNLESS, your objects themselves refer to the dictionaries for their values, in which case the values only live in place.

To do so, you could simply register your properties using reflection in the object constructor, then call the dictionary in your properties.

[Flags]
public enum CVarAccessibilities
{
     Settable,
     Gettable
}

public class CVar<T>
{
     public CVarAccessibilities Accessibility { get; set; }
     T val;
     public T Value { 
        get { return val; }
        set
        {
             if (!Accessibility.HasFlag(CVarAccessibilities.Settable))
                  return; // just don't set it, maybe print some warning
             val = value;
        }
     }
}

public static class CVarRegistry
{
     static Dictionary<string, Object> CVars;

     static CVarRegistry { /* use reflections to initialize the dictionary */ }

     public static T GetValue<T>(Type owner, string paramName)
     {
          CVar cvar;
          if (!CVars.TryGetValue(owner.Name + "_" + paramName, out cvar)
                 throw new MyCustomException();
          return (T)cvar.Value;
     }

     public static void SetValue<T>(Type owner, string paramName, T value)
     {
          CVar cvar;
          if (!CVars.TryGetValue(owner.Name + "_" + paramName, out cvar)
                 throw new MyCustomException();
          cvar.Value = value;
     }
}



public class MyObject
{
    public static int MyRegisteredValue
    {
        get { return Global.CVarRegistry.GetValue<int>(typeof(MyObject), "MyRegisteredValue");  }
        set { Global.CVarRegistry.SetValue(typeof(MyObject), "MyRegisteredValue"); }
    }
 }

Hope that helps!

like image 34
tugudum Avatar answered Nov 05 '22 08:11

tugudum