C# 实施CVAR系统

C# 实施CVAR系统,c#,xna,game-engine,C#,Xna,Game Engine,我想实现我所知道的CVAR系统,我不完全确定它的官方名称(如果有的话) 它本质上是一个用于某些程序和视频游戏的系统,用户可以下拉控制台并输入命令,例如“变量500”,将该变量设置为500。这种情况可以在任何半衰期游戏、厄运和地震游戏以及更多游戏中找到。总体思路似乎是隐藏底层架构,但仍然允许受保护的访问,例如,可以查看重力的值,但不改变它。其中一些值也可能是函数,例如,用户可以输入“创建”以在其位置或指定的其他位置创建敌人类型 查看半衰期2 SDK,从我对GoldSrc SDK的记忆来看,似乎他们

我想实现我所知道的CVAR系统,我不完全确定它的官方名称(如果有的话)

它本质上是一个用于某些程序和视频游戏的系统,用户可以下拉控制台并输入命令,例如“变量500”,将该变量设置为500。这种情况可以在任何半衰期游戏、厄运和地震游戏以及更多游戏中找到。总体思路似乎是隐藏底层架构,但仍然允许受保护的访问,例如,可以查看重力的值,但不改变它。其中一些值也可能是函数,例如,用户可以输入“创建”以在其位置或指定的其他位置创建敌人类型

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

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

我认为理想情况下,我想要的是一个CVAR系统类,以及一个可以接受它的寄存器函数,比如一个变量/函数委托,一个访问它的字符串,以及我需要的任何保护级别。通过这种方式,我可以在看到它们时添加所需的内容,因此所有内容都仍然位于相关的类和文件中

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

  • 以前有人做过类似的事情吗?如果有,怎么做
  • 我的实施是否有效?(理论上,如果没有,你能想出更好的办法吗?)
  • 如果有人对前面提到的某个标题更了解,你能详细说明一下吗?似乎很难找到关于它们的文档

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

你有没有想过这样的事情

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

这通常被称为“调整”变量


这里的讨论很好:

您可以编写一个解析器来查找以下命令

/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"); }
    }
 }
[标志]
公共枚举可访问性
{
可设置,
可获得
}
公共类CVar
{
公共CVarAccessibilities可访问性{get;set;}
T值;
公共T值{
获取{return val;}
设置
{
if(!Accessibility.HasFlag(CVarAccessibilities.setable))
return;//只是不要设置它,可能会打印一些警告
val=值;
}
}
}
公共静态类CVarRegistry
{
静态字典CVAR;
静态CVarRegistry{/*使用反射初始化字典*/}
公共静态T GetValue(类型所有者,字符串参数名)
{
CVar-CVar;
if(!CVars.TryGetValue(owner.Name+“”+paramName,out-cvar)
抛出新的MyCustomException();
返回(T)cvar.值;
}
公共静态void SetValue(类型所有者、字符串参数名、T值)
{
CVar-CVar;
if(!CVars.TryGetValue(owner.Name+“”+paramName,out-cvar)
抛出新的MyCustomException();
cvar.值=价值;
}
}
公共类MyObject
{
公共静态int MyRegisteredValue
{
获取{return Global.CVarRegistry.GetValue(typeof(MyObject),“MyRegisteredValue”);}
set{Global.CVarRegistry.SetValue(typeof(MyObject),“MyRegisteredValue”);}
}
}

希望有帮助!

属于gamedev。stackexchange@Axarydax虽然你可能会发现那里的一些人能够回答这个问题,但这个问题很容易在订单输入应用程序、工资单应用程序或任何其他应用程序中出现。迁移到gamedev实际上只适用于游戏,而不是软件开发总的来说,我想在gamedev上发布这个,但我认为,因为它与实际的游戏设计或开发过程无关,而且它更面向概念,所以更适合这里。尽管我的大多数示例都是游戏,而且是针对游戏的,但我相信这个原则可以应用于几乎任何有我认为这是必要的。但是,我认为除了游戏之外,几乎没有其他程序认为有必要这样做。可能是模拟。这似乎抓住了总体思路,我希望我可以使用课堂之外的变量,比如说,我有一个物理课,它定义了重力和摩擦力,还有一个引擎课,它定义了V那我就可以