我想实现我所知道的CVAR系统,我不完全确定它的正式名称(如果有的话)。
它本质上是一些程序和视频游戏中使用的系统,用户可以在其中下拉控制台并输入命令,例如“变量500”以将该变量设置为500.可以在任何一半中找到此实例 - 生活游戏,厄运和地震游戏等等。一般的想法似乎是隐藏底层架构,但仍然允许受保护的访问,例如,人们可以查看的值,比如引力,但不会改变它。其中一些值也可能是函数,例如,用户可能能够输入“创建”以在其位置或指定的其他位置创建敌人类型。
通过Half Life 2 SDK,以及我在GoldSrc SDK上记得的内容,看起来他们至少实现了“标记”类别,其中某些命令只能在某些条件下工作,例如,如果另一个值是设置,或者如果用户具有某种权限级别。
我最初的想法是创建一个Dictionary或类似的对象,并使用它来将字符串值绑定到函数委托,以及保持“保护”级别的排序,以限制某些命令的使用。但是,这似乎相当麻烦,因为我认为我必须通过手动为我想要实现的每个值或函数添加一个新条目。我也不知道这是否会给我我正在寻找的控制水平。
我认为理想情况下我想要的是一个CVAR System类,以及一个可以接受它的Register函数,一个变量/函数委托,一个访问它的字符串,以及我需要的任何保护级别。这样我可以在看到它时添加我需要的东西,所以一切都还在它的相关类和文件中。
我真的只是在寻找一些想法,所以我的问题是:
我并不是在寻找具体的代码,只是更多的结构化设计。而且它不一定是“商业”或者像其他人一样工作,我只需要一些东西让我走。
答案 0 :(得分:2)
你在考虑这样的事情吗?
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
}
}
}
}
答案 1 :(得分:1)
这通常被称为“调整”变量。
答案 2 :(得分:1)
您可以编写一个查找
等命令的解析器/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"); }
}
}
希望有所帮助!