烦恼一般都是想太多了。

0%

Evennia中游戏对象的管理机制

看了这么多,有个疑问,对于数据库内的对象,是游戏开始就加载的,还是在需要的时候进行加载的呢?或者是两者联合使用的?就我认为来说,比如像账号,角色这样的内容,应该都是在需要的时候进行建立的。而对于房间类似的东西,应该是游戏启动的时候就加载的吧?

这我们就不能不从 Evennia 初始化的时候说起了。

evennia.init()

在我们的 Server 启动的时候,实际上就对 Evennia 环境做了一个初始化的:

django.setup()

import evennia

evennia._init()

实际上关键在于,Evennia 定义了一个针对 Model 的 Manager。

 managers = None
global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers

class DBmanagers(_EvContainer):
"""
Links to instantiated Django database managers. These are used
to perform more advanced custom database queries than the standard
search functions allow.

helpentries - HelpEntry.objects
accounts - AccountDB.objects
scripts - ScriptDB.objects
msgs - Msg.objects
channels - Channel.objects
objects - ObjectDB.objects
serverconfigs - ServerConfig.objects
tags - Tags.objects
attributes - Attributes.objects

"""

from .help.models import HelpEntry
from .accounts.models import AccountDB
from .scripts.models import ScriptDB
from .comms.models import Msg, ChannelDB
from .objects.models import ObjectDB
from .server.models import ServerConfig
from .typeclasses.attributes import Attribute
from .typeclasses.tags import Tag

# create container's properties
helpentries = HelpEntry.objects
accounts = AccountDB.objects
scripts = ScriptDB.objects
msgs = Msg.objects
channels = ChannelDB.objects
objects = ObjectDB.objects
serverconfigs = ServerConfig.objects
attributes = Attribute.objects
tags = Tag.objects
# remove these so they are not visible as properties
del HelpEntry, AccountDB, ScriptDB, Msg, ChannelDB
# del ExternalChannelConnection
del ObjectDB, ServerConfig, Tag, Attribute

managers = DBmanagers()

而实际上此 manager 持有了所有的 Model 的管理器,不要被类似 ScriptDb, ObjectDB 后面类似 objects 所迷惑,实际上这是 Evennia 进行封装的的一个管理器。

这些 Manager 都有一个特点,如 ObjectDBManager ,继承自 TypedObjectManager,而 TypedObjectManager 继承自 SharedMemoryManager,前者的用途是能通过相关的 Attribute, Tag 来查询对象,而后者的作用是,让从我们查询获取的对象是同一个(Django 的模型查询出来的数据,即使同一条数据库记录,也可能是不同的对象了)。

Evennia Server

启动

我们可以只启动我们的 Evennia Server ,而不启动 Portal 来看一下启动的过程。

evennia sstart

最终,是通过向 Portal(AMP Server) 发送 SSTART 命令来启动 Server 的。

#evennia/server/evennia_launcher.py

def start_only_server():
"""
Tell portal to start server (debug)
"""
portal_cmd, server_cmd = _get_twistd_cmdline(False, False)
print("launcher: Sending to portal: SSTART + {}".format(server_cmd))
collectstatic()
send_instruction(SSTART, server_cmd)
#evennia/server/evennia_launcher.py
def _send():
if operation == PSTATUS:
return AMP_CONNECTION.callRemote(MsgStatus, status=b"").addCallbacks(
_callback, _errback
)
else:
return AMP_CONNECTION.callRemote(
MsgLauncher2Portal,
operation=bytes(operation, "utf-8"),
arguments=pickle.dumps(arguments, pickle.HIGHEST_PROTOCOL),
).addCallbacks(_callback, _errback)

而我们的 AMP Server 收到指令后就会进行执行相关的命令:

# evennia/server/portal/amp_server.py
if operation == amp.SSTART: # portal start #15
# first, check if server is already running
if not server_connected:
self.wait_for_server_connect(self.send_Status2Launcher)
self.start_server(amp.loads(arguments))
# evennia/server/portal/amp_server.py
def start_server(self, server_twistd_cmd):
"""
(Re-)Launch the Evennia server.

Args:
server_twisted_cmd (list): The server start instruction
to pass to POpen to start the server.

"""
# start the Server
print("Portal starting server ... {}".format(server_twistd_cmd))
process = None
with open(settings.SERVER_LOG_FILE, "a") as logfile:
# we link stdout to a file in order to catch
# eventual errors happening before the Server has
# opened its logger.
try:
if _is_windows():
# Windows requires special care
create_no_window = 0x08000000
process = Popen(
server_twistd_cmd,
env=getenv(),
bufsize=-1,
stdout=logfile,
stderr=STDOUT,
creationflags=create_no_window,
)

else:
process = Popen(
server_twistd_cmd, env=getenv(), bufsize=-1, stdout=logfile, stderr=STDOUT
)
except Exception:
logger.log_trace()

self.factory.portal.server_twistd_cmd = server_twistd_cmd
logfile.flush()
if process and not _is_windows():
# avoid zombie-process on Unix/BSD
process.wait()
return

当 Server 启动后,实际上 Server 中的 AmpClient 会主动连接 AmpServer,而一旦连接建立,就会执行初始化。

但是实际上, Evennia 不会预加载任何数据,只有在需要的时候才会进行数据的加载。因此,对于一个房间,只有我们登录后,才会有相关的信息出现。