Django 回合制浏览器游戏 - 数据库设计以处理独立时间步伐
我正在用Python/Django开发一个回合制策略网页游戏。这个游戏的想法是这样的:玩家在第n回合时与网站互动。他们查看自己的游戏状态(游戏“世界”),并下达将在下一个时间步执行的命令。某个时刻,网站会暂停,然后回合引擎会根据第n步的状态和所有玩家的命令,计算出第n+1步的新游戏状态。在这个时间步评估期间,我需要读取第n步的对象状态,并在第n+1步创建/写入对象。怎样做才能最有效呢?(这是关于数据库设计的问题)
我考虑了以下几种方案: 第一种方法是:让每个世界对象都带有一个时间步参数。 这样做可能会很麻烦,因为每次都要根据时间步来筛选。而且,数据库会随着每个时间步的增加而增长,因为它会包含从第0步开始的整个历史记录。
第二种方法是:为每个时间步使用不同的物理数据库。 也就是说,在时间步演变过程中,为第n+1步创建一个新的数据库。在评估时,同时处理数据库(n, n+1)。一旦时间步评估完成,就删除(或者更好:归档)第n步的数据库,并用第n+1步的数据库替换它。(这样做的好处是可以保留每个时间步的数据库快照作为备份) 我觉得后者似乎是更好的方法。但我需要一些建议,关于如何同时处理两个数据库。
你能给我其他建议,帮助我做出选择吗? 你觉得还有其他可能的方法吗? 有没有第三方库或Django插件可以处理类似的问题? 如果我使用第二种方法,如何告诉Django同时使用两个数据库,每个数据库中的对象类型相同?
1 个回答
我觉得你大概已经明白了。这里有两个数据库,分别叫做 default
和 future
。
DATABASES = {
'default': {
'NAME': 'default',
'ENGINE': 'django.db.backends.mysql',
'USER': '',
'PASSWORD': '',
},
'future': {
'NAME': 'future',
'ENGINE': 'django.db.backends.mysql',
'USER': '',
'PASSWORD': '',
},
}
你可以像往常一样,使用模型来写你的视图或其他东西。这些内容会被写入到 default
数据库,就像你之前习惯的那样。
接下来,创建一个管理命令来更新游戏状态……(你也可以把这段代码放到 Celery 任务里或者其他地方,不过在这个回答中,我打算通过命令行和定时任务来调用它。)
# project/app/management/commands/run_turn.py
from django.conf import settings
from django.core.management.base import BaseCommand
import subprocess
from optparse import make_option
def copy_default_to_future():
# Copy database before acting on game state
# use the subprocess library for bash execution of mysql/postgres commands
# ...
def copy_future_to_default():
# Copy database after acting on game state
# use the subprocess library for bash execution of mysql/postgres commands
# ...
def upload_backup_to_cloud():
# i recommend using django-cumulus and a custom backups storage container
# ...
class Command(BaseCommand):
args = '<attachment_path attachment_path ...>'
help = 'Processes game state at end of turn'
option_list = BaseCommand.option_list + (
make_option('-u', '--upload-backup',
action='store_true',
dest='upload',
default=False,
help='Upload database export to cloud object storage'),
)
def handle(self, *args, **options):
if options.get('upload', None):
upload_backup_to_cloud()
copy_default_to_future()
# ... change your gamestate
for player in Player.objects.using('future').all():
player.increment()
# ...
copy_future_to_default()
print "Game state updated."
patrick@lucca:~$ crontab -e
@hourly /home/patrick/.virtualenvs/browsergame/bin/python /path/to/project/manage.py run_turn --upload-backup
参考资料: