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
/
physicsserver.py
executable file
·130 lines (111 loc) · 4.97 KB
/
physicsserver.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
#!/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 #####
'''PhysicsServer
A server that runs a physics simulation for all the objects in a zone.
It doesn't really care why or how objects ended up where they claim to be now.
It pretends to be a client with omniscient control over all the little
puppets, er, I mean movable Objects in the zone.
It determines if an object can occupy the space it claims to be in now,
and if not, it fixes it.
Think of it as a physics-based position sanity check.
This should be started by the ZoneServer.
'''
from uuid import uuid4
import datetime
# TODO: This still needs ported from Mongo to Peewee, but it's unused so I'm leaving it for now.
import pymunk as pm
from pymunk import Vec2d
### Physics collision types
COLLTYPE_BALL = 2
from settings import CLIENT_UPDATE_FREQ, DATETIME_FORMAT
from basetickserver import BaseTickServer
class PhysicsServer(BaseTickServer):
'''This class is responsible for simulating all the physics in the zone.'''
def __init__(self, zoneid):
super(PhysicsServer, self).__init__()
self.zoneid = zoneid
print "Started with data for zone: %s" % zoneid
# Set up a PyMunk scene for our simulation.
self.space = pm.Space()
self.space.gravity = Vec2d(0.0, 0.0)
self.space.damping = 0.5
# self.space.idleSpeedThreshold = 1.0
# self.space.sleepTimeThreshold = 0.05
self.objects = {}
# Initialize our scene by grabbing all the objects since the beginning of time.
self.last_update = datetime.datetime.strptime('0001-01-01 00:00:00:000000', DATETIME_FORMAT)
self.update_scene()
def insert_space_object(self, me_obj, mass=10, radius=10):
moment = pm.moment_for_circle(mass, 0, radius, (0,0))
body = pm.Body(mass, moment)
body.position = me_obj.loc.x, me_obj.loc.y
shape = pm.Circle(body, radius, (0,0))
shape.friction = 0.7
shape.collision_type = COLLTYPE_BALL
self.space.add(body, shape)
self.objects.update({me_obj.id: {"body": body, "me_obj": me_obj, "shape": shape}})
def tick(self):
'''Get any updated objects in the scene since the last tick,
and update their position in the physics simulation.
Step the sim forward a bit and see what got jostled out of place.
Then update the database with any objects that have changed positions.'''
self.update_scene()
self.step()
self.update_database()
def update_scene(self):
'''Update the internal scene with any changes to the zone's objects.
This is like get_objects() from the client, only directly grabbing from the server.'''
# Get all the objects since our last update.
for o in Object.objects(last_modified__gte=self.last_update, physical=True):
if o.id in self.objects:
# This object is already in our scene, let's update its position
# with what the database says its position is.
self.objects[o.id]['me_obj'] = o
self.objects[o.id]['body'].position = o.loc.x, o.loc.y
else:
# This object is not in our physics scene yet
self.insert_space_object(o)
self.last_update = datetime.datetime.now()
def step(self):
'''Step the scene simulation forward until we're satisfied.'''
dt = 1.0/60.0
for x in range(1):
self.space.step(dt)
def update_database(self):
'''Send any changes we made to our internal scene to the database,
so that any movement or bumping or jostling is persisted into the zone.'''
for _id, o in self.objects.items():
body = o['body']
me_obj = o['me_obj']
newx, newy = body.position
oldx, oldy = me_obj.loc.x, me_obj.loc.y
if newx != oldx or newy != oldy:
me_obj.loc.x = newx
me_obj.loc.y = newy
me_obj.set_modified()
def start(self):
print "Running PhysicsServer."
super(PhysicsServer, self).start()
if __name__ == "__main__":
import sys
zoneid = sys.argv[1] if len(sys.argv) > 1 else "playerinstance-defaultzone-None"
ps = PhysicsServer(zoneid)
ps.start()