8

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.

shmeeps
  • 7,725
  • 2
  • 27
  • 35
  • 2
    belongs to gamedev.stackexchange – Axarydax Mar 03 '11 at 22:37
  • 3
    @Axarydax while you might find some of the guys there are able to answer this, this problem is easily one that could come up in an order-entry application, a payroll application, or any other. migration to gamedev is really for things that only apply to gaming, as opposed to software development in general. – corsiKa Mar 03 '11 at 22:39
  • 1
    I was going to post this on gamedev, but I figured that since it is not related to the actual game design or development process, and that this was more concept oriented it would fit in better here. Even though most of my examples are games, and it is for a game, I believe the principle can be applied to just about any program that was deemed necessary. – shmeeps Mar 03 '11 at 22:42
  • I think few programs other than games see much need to do this, however. Maybe simulations. – Kylotan Mar 04 '11 at 19:26

3 Answers3

2

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
           }
       }
   }
}
arul
  • 13,998
  • 1
  • 57
  • 77
  • This seems to capture the general idea, I was hoping that I could use variables that are external to the class though, so say for instance I have my Physics class which defines gravity and friction, and an Engine class which defines the Version, then I could still access those values through the CVAR class. – shmeeps Mar 04 '11 at 01:17
1

This is more commonly known as 'tweak' variables.

Good discussion here: https://gamedev.stackexchange.com/questions/3631/tweaking-and-settings-runtime-variable-modification-and-persistence

Community
  • 1
  • 1
Kylotan
  • 18,290
  • 7
  • 46
  • 74
1

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!

tugudum
  • 387
  • 1
  • 4
  • This looks just about what I'm looking for, but I think I'm going to try to modify it with a CVarRegistry.Register function. Gave this a +1 one for now, but I'm going to leave the question open up for a day or two more. – shmeeps Mar 05 '11 at 05:36