管理变化的设计师数据和变化的球员数据的方法


14

我有一个在线游戏,玩家可以通过某种方式塑造世界-例如。Ultima Online的房屋,您可以在其中直接在世界地图的某些部分上建造房屋。这些变化应作为持久世界的一部分随着时间的流逝而持久。

同时,设计团队正在添加新内容并修改旧内容,以改善和扩展新玩家的游戏。他们将首先在测试期间在开发服务器上执行此操作,然后再将其工作与实时服务器上播放器的“工作”合并。

假设我们解决了游戏设计问题-例如。玩家只能在指定区域内建造游戏,因此他们永远不会与设计者进行地理上的冲突- 处理新数据或安排数据结构的最佳方法是什么,以避免在将新设计者数据与新玩家数据合并时发生冲突?

示例1:玩家制作了一种新的物品,然后游戏为其分配了ID 123456。该项目的实例全部回溯到123456。现在想象游戏设计师有一个类似的系统,而设计师创建了一个新项目,编号也为123456。如何避免这种情况?

示例2:某人制作了一个流行的mod,可以为您的所有龙赋予法国口音。它包括一个带有新对象的脚本assignFrenchAccent,他们使用该脚本将新的语音资产分配给每个龙对象。但是,您将部署具有相同名称的对象的“拿破仑与史矛革” DLC-如何在没有很多客户服务问题的情况下做到这一点?

我想到了以下策略:

  • 您可以使用2个单独的文件/目录/数据库,但是读取操作非常复杂。“显示所有项目”必须在设计器DB上执行一次读取,在播放器DB上执行一次读取(并且仍然必须以某种方式区分这两个)。
  • 您可以在一个商店中使用2个不同的名称空间,例如。使用字符串作为主键,并以“ DESIGN:”或“ PLAYER:”作为前缀,但是创建这些名称空间可能并非易事,并且依赖关系不清楚。(例如,在RDBMS中,您可能无法有效地将字符串用作主键。您可以使用整数并将低于某个数字(例如1百万)的所有主键分配为设计器数据,而高于该数字的所有主键则分配为玩家数据。但是该信息对于RDBMS是不可见的,并且外键链接将跨越“分隔线”,这意味着所有工具和脚本都需要明确地解决它。)
  • 您始终可以实时处理同一个共享数据库,但是性能可能很差,损坏播放器数据的风险可能会增加。它也不会扩展到在具有不同世界数据的多于一台服务器上运行的游戏。
  • ...还有其他想法吗?

在我看来,尽管这主要是在线游戏的问题,但这些概念也可能适用于改装,即社区在开发人员修补其游戏的同时创建mod。是否有任何策略可以用来减少新补丁发布时模块破解的机会?

我也将其标记为“版本控制”,因为在一个层面上这就是-需要合并的2个数据开发分支。也许某些见解可能来自该方向。

编辑-上面添加了一些示例以帮助阐明问题。我开始认为这个问题实际上是命名空间问题之一,可以通过组合键在商店中实现。至少,这简化了合并策略。但是可能还有其他我看不到的选择。


1
我想答案可能至少部分取决于设计师添加的数据类型以及玩家添加的数据。
lathomas64 '02

可以,但是我对两个参与单个数据存储的各方的通用解决方案更感兴趣。
Kylotan '02

1
很多人都忽略了这个问题的重点-冲突的不是玩家的改变:而是内容更新等打破了现有的布局。@Kylotan对吗?
乔纳森·迪金森

开发人员内容更新可能与播放器内容更新发生冲突。我对游戏设计变通办法(例如,仅允许玩家在某些地方搭建)并不真正感兴趣,但对数据结构变通办法(例如,仅允许玩家创建ID大于100万的东西)不感兴趣。
Kylotan '02

2
您没有指定,是否希望实时更新现实世界?附带说明:一个数据库有两个参与方,那就是数据库,这就是数据库的作用,您无法绕开这个事实,而忽略数十年来如何避免共享数据问题的知识将是愚蠢的。
Patrick Hughes

Answers:


2

我认为提出DB解决方案的答案正在跳到特定的实现方式,而没有理解问题。数据库使合并变得不容易,它们只是为您提供了一个用于存储数据的框架。即使在数据库中,冲突仍然是冲突。签出是穷人解决问题的方法-可以解决问题,但会给您的可用性带来巨大的损失。

您在这里所说的属于问题的分布式开发模型。我认为,第一步不应该将玩家和设计师视为独立的内容创作者。这消除了不影响解决方案的人为因素。

实际上,您拥有主线-规范的,开发人员认可的版本。您可能(可能)还有其他分支机构-实时服务器是人们正在积极开发和共享mod的地方。内容可以添加到任何分支上。至关重要的是,您的设计师在这里没什么特别的-他们只是内容创作者,而他们恰好住在内部(您可以去找他们,当他们搞砸了之后再打他们)。

然后,接受用户生成的内容是一个标准的合并问题。您必须将其更改拉回到主线上,合并,然后再次推出,或将主线更改拉到其分支上并合并(保留用户生成的东西“干净”的主线)。像往常一样,拉到您的分支并在那里进行修复比要求其他人拉您所做的更改然后尝试远程修复该问题更为友好。

一旦使用了这种模型,就将应用所有避免合并冲突的常规过程。一些更明显的:

  • 鼓励自由使用名称空间来围栏特定作者/ mod /团队的内容。
  • 在需要交互内容的地方,建立清晰的调用/使用约定,命名约定以及其他指导开发的宽松“规则”,以便轻松地将其合并。提供允许内容创建者知道他们是否遵守这些规则的工具,最好将其集成到内容创建本身中。
  • 提供报告/分析工具,以在可能发生的合并失败之前发现它们。合并后修复它可能非常痛苦。做到这一点,以便可以检查特定的内容位并将所有内容清楚地显示为可合并的,这样合并就轻松了
  • 使您的合并/集成稳健。允许轻松回滚。对合并的内容进行严格的测试:如果测试失败,请不要合并!迭代他们或你自己的内容,直到合并顺利进行为止。
  • 避免对任何东西使用增量整数ID(您没有可靠的方式将它们分配给创建者)。这仅在数据库中有效,因为数据库本身是ID的规范提供者,因此您永远不会重复。但是,它也会在系统中引入单点故障/负载。
  • 而是使用GUID-存储成本更高,但特定于计算机,因此不会引起冲突。或者使用字符串标识符,这更容易调试/解析,但存储和比较则更昂贵。

不幸的是,其中一些对我的问题没有帮助(例如,让玩家遵循某些规则,因为这必须在服务器端自动完成),而且我认为支持合并管理和事务处理的程度并不可行。您提到的语义,但是分配保证的唯一ID(可能是GUID)的一般方法可能与我将要使用的最接近。
Kylotan '02

知道了 好吧,因为您可以控制他们的构建工具,所以至少可以强制执行那些易于合并的方法(命名空间等),而无需参与者同意。
MrCranky

如果两个播放器创建重复的内容该怎么办?还是您的游戏世界的单独实例被视为唯一?在这种情况下,这可能是一种有用的方法,可以自动将您知道的每个唯一实例与您的核心/主线分支进行检查,以防在您将这些更改推送到实例时发生冲突。如果您无法控制玩家,则至少可以在开发初期就警告内部团队他们正在做的工作与世界实例X发生冲突。
MrCranky '02

命名空间的概念不是问题,而是从所有可能的命名空间的命名空间中选择足够的命名空间!:)对我来说,重复的内容不是问题-只是两个等同的实例。重要的是,不会发生破坏性的合并或覆盖。至于自动冲突检查,这可以停止写入过程中造成的损坏,但不能解决原始的命名问题。(由于交叉引用,为避免碰撞而重命名的东西可能并不容易。)
Kylotan 2012年

是的,我现在知道,名称空间本身与其说是名称选择,不如说是名称本身。在这种情况下,GUID可能再次成为答案-将内容有效地保留在自己的小区域中。可以给出装饰性名称,但游戏将使用GUID。
MrCranky 2012年

1

将所有内容存储为属性(或装饰器)-带有安装点。让我们以玩家设计的房屋为例:

o House: { Type = 105 } // Simple square cottage.
 o Mount point: South Wall:
  o Doodad: Chair { Displacement = 10cm }
   o Mount point: Seat:
    o Doodad: Pot Plant { Displacement = 0cm, Flower = Posies } // Work with me here :)
 o Mount point: North Wall:
  o Doodad: Table { Displacement = 1m }
    o Mount point: Left Edge:
     o Doodad: Food Bowl { Displacement = 20cm, Food = Meatballs}

因此,每个实体可以具有一个或多个安装点-每个安装点可以接受零个或多个其他组件。该数据将与保存时的版本以及任何相关属性(例如,在我的示例中为Displacement等)一起存储-NoSQL在这里可能非常合适(键=实体ID,值=序列化二进制)数据)。

然后,每个组件都需要能够“升级”以前版本中的旧数据(永远不要从序列化数据中删除字段-只是将它们“空”)-这种升级发生在加载之时(然后将其立即存储回原位)最新版本)。假设我们的房子已经改变了尺寸。升级代码将相对地计算出北墙和南墙之间的距离,并按比例更改所有包含实体的位移。再举一个例子,我们的肉碗可能删除了“食物”字段,取而代之的是“品种”(肉)和“食谱”(球)。升级脚本会将“肉丸”变成“肉”,“球”。每个组件还应该知道如何处理安装点的更改-例如

这一切都只剩下一个问题:如果两个对象彼此冲突(而不是它们的容器-挂载点可以保护您),会发生什么?升级后,您应该检查碰撞并尝试解决它们(将物体分开,有点像SAT)。如果您不知道如何解决碰撞,请删除其中一个对象并将其放置在储藏柜中-在这里,他们可以免费(免费)购买这些物品或以全价出售这些物品;并明显通知玩家升级已中断了某些布局-可能具有“放大”功能,以便他们可以看到问题。

最终,您应该将复杂的更改留在玩家的手上(快速失败),因为没有算法可以说明美学问题–您应该只能够为玩家提供有关该物品过去所在的上下文(以便他们能够记住,而不仅仅是将所有这些物品降落在它们的藏匿处,却不知道它们在哪里)。


这过于狭窄地集中在对象定位上,这并不是我要解决的关键问题。它更多的是关于在并发数据集中具有唯一标识符,并且需要能够将它们合并而不会产生任何冲突风险。前几天,我在帖子中添加了2个示例,以尝试进一步解释。
Kylotan '02

1

我正在尝试将其与我了解的东西联系起来,所以我现在正在考虑Minecraft。我正在描绘一个实时服务器,其中的玩家可以实时进行更改,而开发人员正在测试服务器上运行,以修复/创建新内容。

您的问题几乎像2个独特的问题:

  1. 如何确保对象ID是唯一的
  2. 如何确保脚本名称空间不冲突

我会尝试通过一个临时引用系统来解决#1问题。例如,当某人创建新对象时,可以将其标记为易失性或临时性。我可以想象在测试服务器上创建的所有新内容都将标记为易失性(尽管它也可能引用非易失性内容)。

当您准备将新内容带入实时服务器时,导入过程将查找易失对象,并为其分配以石头形式设置的实时服务器对象ID。这与直接导入/合并不同,因为如果需要修复或更新它们,则需要能够引用现有的非易失性对象。

对于#2,看来您确实需要某种程度的中间脚本转换,可以将函数名称哈希到唯一的名称空间。即

assignFrenchAccent

成为

_Z11assignFrenchAccent

0

如果数据文件是文本文件而不是二进制文件,并且设计者和播放器正在修改其他区域,则可以尝试SVN合并。


0

我认为使用“签出”过程跨环境复制的数据库/文件系统是最好的。

因此,每当设计师想要对世界进行一些修改时,他都会在数据库的所有副本(开发和生产)上签出/锁定他想要创建/修改的所有资产,因此没有其他玩家或设计师可以对其进行修改。 。然后,他将在开发数据库上工作,直到完成新设计为止,那时更改将与生产数据库合并,并且将在所有环境中检入/解锁这些资产。

播放器编辑的工作方式几乎相同,除了数据库/文件系统角色将撤消-它们在生产数据库上工作,并且所有更新完成后都上传到开发人员。

资产锁定可以限制为您要保证没有冲突的属性:在示例1中,您将ID 123456在播放器开始制作后立即锁定它,因此不会为开发人员分配该ID。在示例2中,您的开发人员将锁定脚本名称assignFrenchAccent在开发过程中,因此玩家在进行修改时必须选择一个不同的名称(通过命名空间可以减少小小的麻烦,但是除非您给每个,否则它本身不会避免冲突用户/开发人员特定的名称空间,然后在管理名称空间时也会遇到同样的问题)。这确实意味着所有开发都必须从单个联机数据库中读取,但是在这些示例中,您从该数据库中所需要的只是对象名称,因此性能应该不是问题。

就实现而言,在所有环境中具有实时同步/可访问的,具有所有键和资产状态(可用,已锁定开发人员,产品已锁定)的单个表就足够了。一个更复杂的解决方案将实现完整的版本控制系统-如果资产全部位于文件系统中,则可以使用现有系统(例如CVS或SVN)。


通常,在全球范围内锁定任何数据都是不切实际的-玩家可能只是通过正常玩法来编辑世界,并且您不希望该玩法阻止设计师进行工作。如果允许全局锁,那么合并操作基本上就是一个覆盖操作,这很容易-但是,如果您没有全局锁,那该怎么办?
Kylotan '02

正如lathomas64所提到的,答案将取决于您在谈论哪种数据。没有全局锁,我想您将必须具有版本控制系统和一组规则来解决任何冲突-这些规则将取决于数据和游戏要求。一旦有了这些,我想每次合并都会简化为一个简单的覆盖操作。
SkimFlux 2012年

0

我认为这里的重点是明确承担您的责任。1)服务器说出当前可接受的内容以及要使用的API。根据某些规则,正在修改数据库。2)允许创作者创建内容,但更新后必须可以播放。这完全是您的责任:任何更新都必须能够解析旧数据结构,并且最好尽可能简洁明了。

如果您有兴趣跟踪可锻结构内的独特项和位置,尤其是如果我们接受玩家的整个“主场”结构会发生巨大变化,而您希望保持这种状态,那么坐骑点创意是有好处的。各自储物柜中的小装饰物。

这是一个非常复杂的问题,祝您好运!可能没有任何答案。


0

我认为这在您制造时没有什么大问题。

我只是要覆盖用户创建的mod,并发出一条警告,指出“ Mod X可能无法在此版本中正常工作”,将其留给mod创建者更改其工作。我不认为更新可能会禁用某些Mod是不切实际的期望。

与用户创建的内容相同,只是进行备份并覆盖。

我没有实际经验,只是提出建议。


我认为,如果仅用于用户提供的mod,那您将是正确的。但是某些游戏明确涉及用户创建的内容,因此您不能仅仅破坏它。
Kylotan '02

然后,在系统中留出空间,以便稍后添加内容。如果您使用的是ID号,请保留1-1000。或者,如果用户可以命名其资产,则不要让用户以“ FINAL-”或其他名称开头(为您自己的资产保留名称)。编辑:或者更好的,做反,迫使用户内容为范围或前缀
伍迪Zantzinger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.