This repository has been archived by the owner on Oct 19, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
scriptserver.py
executable file
·156 lines (126 loc) · 5.64 KB
/
scriptserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python
# ##### BEGIN AGPL LICENSE BLOCK #####
# This file is part of SimpleMMO.
#
# Copyright (C) 2011, 2012 Charles Nelson
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ##### END AGPL LICENSE BLOCK #####
'''ZoneScriptServer
A server that runs scripts for all the objects in a zone.
This is started by the MasterZoneServer when its sibling ZoneServer is started.
'''
import time
import logging
logger = logging.getLogger('ScriptServer')
hdlr = logging.FileHandler('log/scriptserver.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from elixir_models import Object, Message, ScriptedObject
from games.objects.basescript import Script
import settings
from basetickserver import BaseTickServer
class ScriptEventHandler(FileSystemEventHandler):
def on_any_event(self, event):
import tornado.autoreload
tornado.autoreload._reload()
class ZoneScriptRunner(BaseTickServer):
'''This is a class that holds all sorts of methods for running scripts for
a zone. It does not talk to the HTTP handler(s) directly, but instead uses
the same database. It might take player movement updates directly in the
future for speed, but this is unlikely.'''
def __init__(self, zoneid):
super(ZoneScriptRunner, self).__init__()
# While the zone is not loaded, wait.
logger.info("Waiting for zone to complete loading.")
while not Object.get_objects(name="Loading Complete."):
time.sleep(.1)
# Watch the script path for any changes, and reboot the scriptserver if they do.
self.observer = Observer()
self.observer.schedule(ScriptEventHandler(), path=settings.SCRIPT_PATH, recursive=True)
self.observer.start()
self.load_scripts()
logger.info("Started with data for zone: %s" % zoneid)
def load_scripts(self):
'''(Re)Load scripts for objects in this zone.'''
self.scripts = {}
# Query DB for a list of all objects' script names,
# ordered according to proximity to players
logger.info(Object.get_objects(scripted=True))
for o in Object.get_objects(scripted=True):
logger.info("Scripted Object: {0}".format(o.name))
# Store list of script names in self
# For each script name in the list:
for script in o.scripts:
logger.info("Importing %s" % script)
if script not in self.scripts:
self.scripts[script] = []
# Import those by name via __import__
scriptclass = script.split('.')[-1]
module = __import__(script, globals(), locals(), [scriptclass], -1)
# For each entry in the script's dir()
for key in dir(module):
C = getattr(module, key)
# No sense in instantiating the default Script instance.
if C == Script:
continue
try:
# Does this object have the attributes that scripts need?
if not all((C.tick, C.activate, C.create)):
continue
except AttributeError:
continue
# Store object instance in a list.
self.scripts[script].append(C(mongo_engine_object=o))
return self.scripts
def tick(self):
'''Iterate through all known scripts and call their tick method.'''
# Tick all the things
logger.info(self.scripts)
for scriptname, scripts in self.scripts.items():
for script in scripts:
logger.debug("Ticking {0}".format(script))
# TODO: Pass some locals or somesuch so that they can query the db
script.tick()
# Clean up mongodb's messages by deleting all but the most recent 100 non-player messages
for m in Message.select().where(Message.player_generated==False).order_by('-sent')[settings.MAX_ZONE_OBJECT_MESSAGE_COUNT:]:
logger.info("Deleting message from %s" % m.sent.time())
m.delete()
def start(self):
logger.info("Running ZoneScript Server.")
super(ZoneScriptRunner, self).start()
if __name__ == "__main__":
import sys
import tornado
from tornado.options import options, define
define("dburi", default='testing.sqlite', help="Where is the database?", type=str)
define("zoneid", default='playerinstance-defaultzone-None', help="What is the zoneid?", type=str)
tornado.options.parse_command_line()
dburi = options.dburi
zoneid = options.zoneid
# Connect to the elixir db
from elixir_models import setup
setup(db_uri=dburi)
zsr = ZoneScriptRunner(zoneid)
try:
zsr.start()
except:
zsr.observer.stop()
zsr.observer.join()
logger.info("Exiting Scriptserver.")