8

我一直在开发一个在线扑克游戏。但我一直在撞墙。我想在系统中实施奖项,但我希望它们是动态的。这意味着我不想为我想添加的每个奖项重新编译。

我考虑过为每个奖项使用 Python 代码。然后,当服务器检查用户是否有资格获得奖励时,它使用 Jython 运行 python 脚本(服务器使用 Java 和 Netty NIO),如果函数返回某个值,我将奖励奖励给用户。这可能有效,但是否有一种更有效的技术不会迫使我每次需要检查用户是否获得奖励时都运行数百个 python 脚本。

什么时候是做这些检查的最佳时间?我有一个钩子系统,我将在其中指定钩子,例如( [onconnect][ondisconnect][chatmessage.received] )。这也可以工作,但感觉有点粗糙,我仍然必须运行数据库中的所有脚本。

4

4 回答 4

6

如果我是你,我会有一个完全独立的流程来授予奖项。它可能每天在包含所有玩家/游戏数据的基础数据库上运行一次。

你的核心面向客户的应用程序知道奖项,但它所知道的只是从数据库加载的数据——比如标题、图像、描述,可能有多少人获得了奖项等,以及(基于数据库)表)谁获得了奖项。

您的“奖励授予者”流程只是以批处理模式运行,每天/每小时一次等,并向符合条件的玩家授予新奖励。然后,面向客户的核心应用程序会通知他们,但实际上并不需要知道如何授予他们的聪明才智。这使您可以随时自由地重新编译和重新运行您的奖励授予者,而不会影响核心应用程序。

另一种方法,取决于您的奖励的限制程度,是编写一个简单的规则接口,允许您在数据中定义规则。这将是实现您所描述的理想的理想选择,但在我看来,这是一项相当多的工作而没有太多的回报。

PS——在运行像在线扑克服务器这样的东西时,你会一直遇到这个问题的不同版本。您绝对需要开发一种方法来部署新代码,而不会终止您的服务或有停机时间窗口。从长远来看,围绕以 Java 为中心的奖励代码解决方案不会为您解决这个问题。您应该查看有关运行真正的 24/7 服务的文献,有很多方法可以解决这个问题,而且这些天实际上并没有那么困难。

于 2011-08-15T23:42:56.643 回答
3

我能想到的选择有很多:

  • 如上所述的 OSGi - 它是有代价的,但可能是最通用和最动态的解决方案
  • 如果您愿意重新启动(只是不重新编译),那么众所周知的文件夹和 spring 中的 jar 集合会为您提供更便宜但同样通用的解决方案。只需让您的奖励 bean 实现一个标准接口,成为 bean,然后让 spring 将 @Autowire 所有可用的奖励计算到您的检查器中。
  • 如果您的奖励执行相当标准,并且奖励之间的唯一变化是规则本身,那么您可以进行某种脚本化配置。那里有很多选择,从你描述的python(除了我会去一些管理所有奖项的大脚本),到基本的正则表达式,中间有LUA和Drools。在所有情况下,您都在查看某种规则引擎架构,它在奖励可以触发的内容方面是灵活的,但在奖励可以导致的内容方面没有提供太大的灵活性(即完美的成就)。
于 2011-08-15T23:26:14.410 回答
3

对批处理想法的答案的一些评论: 实施动态奖励系统

该批处理可以在单独的服务器/机器上,因此您可以随时重新编译应用程序或重新启动服务器。有了新的奖励可以使用例如添加罐子和重新启动服务器的提到的方法来处理,也可以随时引入新的批处理作业等等。因此,您的核心应用程序 99% 的时间都在运行,批处理服务器可以频繁重启。所以单独的批处理机是好的。

当您需要部署新版本的核心应用程序时,我认为您可以停止、部署和启动它,并向用户发出维护通知。这种方法甚至被具有出色软件的顶级扑克室使用(例如 FullTiltPoker 就这样做了,现在由于许可证丢失,它已关闭,但他们的网站显示“系统更新”:))。

因此,版本更新的一种方法是在下班时间重新部署/重新启动。

另一种方法是实时更新。通常,它是通过将用户一捆一捆地迁移到新版本来完成的。所以同时一些用户正在使用旧版本,一些 - 新的。如果不同版本的用户可以交互,扑克软件就不是很酷了。但是,如果您确定版本“兼容性”,您可以采用这种方法,例如在登录时检查用户的客户端版本。

在我的回答中,我试图说您不需要在代码中引入 24/7 支持逻辑。将系统可用性问题留给硬件(故障转移、负载平衡器等)。您可以遵循您用来编写代码的任何好的技术,只需要记住您的关键核心逻辑不经常部署(例如每周一次),并且可以根据需要随时更新/重新启动批处理部分。

于 2011-08-16T21:04:02.483 回答
2

据我了解,您可能不必从应用程序运行外部进程,也不必使用 OSGI。只需创建一个简单的 Java 接口并将每个插件('award')实现为实现该接口的类。然后,您可以简单地编译任何新插件,并在运行时使用Class.forName(String className). 您需要从此类插件中获得的任何逻辑都将包含在接口上的方法中。

http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Class.html#forName(java.lang.String)

于 2011-08-11T18:31:39.413 回答