【问题标题】:Implementing a CVAR system实施 CVAR 系统
【发布时间】:2011-03-03 22:31:17
【问题描述】:

我想实施我所知道的 CVAR 系统,我不完全确定它的正式名称是什么(如果有的话)。

它本质上是一些程序和视频游戏中使用的系统,用户可以在其中拉下控制台并输入命令,例如“变量 500”以将该变量设置为 500。这种实例可以在任何一半中找到-Life 游戏、Doom 和 Quake 游戏等等。总的想法似乎是隐藏底层架构,但仍然允许受保护的访问,例如,可以查看例如重力的值,但不会改变强>它。其中一些值也可能是函数,例如,用户可以输入“create”以在其位置或指定的其他位置创建敌人类型。

查看半条命 2 SDK,从我对 GoldSrc SDK 的记忆来看,似乎他们至少实现了某种“标记”,其中某些命令只能在某些条件下工作,例如如果另一个值是设置,或者如果用户有一些权限级别。

我最初的想法是创建一个 Dictionary 或类似的对象,并使用它来将字符串值绑定到函数委托,并保持某种“保护”级别,以限制某些命令的使用。然而,这似乎相当麻烦,因为我相信我必须手动为我想要实现的每个值或函数添加一个新条目。我也不知道这是否会给我想要的控制水平。

我相信理想情况下我想要的是一个 CVAR System 类,以及一个可以接受它的 Register 函数、一个变量/函数委托、一个访问它的字符串,以及我需要的任何保护级别。这样我就可以在我看到它们时添加我需要的东西,所以一切仍然在它的相关类和文件中。

我真的只是在这里寻找一些想法,所以我的问题是:

  • 以前有没有人做过这样的事情,如果有,是怎么做的?
  • 我的实施会起作用吗? (理论上,如果没有,你能想到更好的方法吗?)
  • 如果有人更了解前面提到的标题之一,您能详细说明一下吗?似乎很难找到关于它们的文档。

我并不是真的在寻找特定的代码,只是更多的结构化设计。而且它不必是“商业”或像另一个一样工作,我只需要一些东西来让我前进。

【问题讨论】:

  • 属于 gamedev.stackexchange
  • @Axarydax 虽然您可能会发现那里的一些人能够回答这个问题,但这个问题很容易出现在订单输入应用程序、工资单应用程序或任何其他应用程序中。迁移到 gamedev 确实只适用于游戏,而不是一般的软件开发。
  • 我本来打算在gamedev上发布这个,但我认为因为它与实际的游戏设计或开发过程无关,而且它更面向概念,所以更适合这里。尽管我的大多数示例都是游戏,而且是针对游戏的,但我相信该原则几乎可以应用于任何被认为必要的程序。
  • 我认为,除了游戏之外,很少有程序认为需要这样做。也许是模拟。

标签: c# xna game-engine


【解决方案1】:

你有想过这样的事情吗?

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
           }
       }
   }
}

【讨论】:

  • 这似乎抓住了一般的想法,我希望我可以使用类外部的变量,所以比如说我有我的物理类,它定义了重力和摩擦力,以及一个引擎定义版本的类,那么我仍然可以通过 CVAR 类访问这些值。
【解决方案2】:

你可以编写一个解析器来查找类似的命令

/object_property value
/object_method arg1 arg2

像您建议的那样,字典可以将这些字符串映射到属性和函数。可以使用反射动态地创建字典,方法是遍历合格的对象,获取它们的公共方法和访问器,并为它们生成一个字符串。

为了方便和错误检查,可以将字典映射到一个类中。

对于方法,字典值可以是接受 0..n 个参数的委托,对于属性/字段,您需要能够在实际字段和字典值之间进行一些数据绑定。除非,您的对象本身引用字典来获取它们的值,在这种情况下,这些值只存在于原处。

为此,您只需在对象构造函数中使用反射注册您的属性,然后在您的属性中调用字典。

[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"); }
    }
 }

希望有帮助!

【讨论】:

  • 这看起来正是我正在寻找的东西,但我想我将尝试使用 CVarRegistry.Register 函数对其进行修改。暂时给这个 +1 一个,但我将把这个问题留一两天。
【解决方案3】:

【讨论】:

    猜你喜欢
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-12
    • 2013-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多