Skip to content

Commit

Permalink
Bullet physics and transmit new datestamp on login
Browse files Browse the repository at this point in the history
  • Loading branch information
croxis committed May 20, 2012
1 parent 8b4dca5 commit 0e28274
Show file tree
Hide file tree
Showing 14 changed files with 1,414 additions and 328 deletions.
930 changes: 918 additions & 12 deletions ITF.sublime-workspace

Large diffs are not rendered by default.

105 changes: 105 additions & 0 deletions client.py
@@ -0,0 +1,105 @@
import sandbox

from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "notify-level-ITF-ClientNetwork debug")
from direct.directnotify.DirectNotify import DirectNotify
log = DirectNotify().newCategory("ITF-ClientNetwork")

from panda3d.core import QueuedConnectionManager, QueuedConnectionReader, ConnectionWriter, NetAddress, NetDatagram
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator

import protocol
import solarSystem
import universals

class ClientNetworkSystem(sandbox.EntitySystem):
def init(self, port=2000, server="127.0.0.1", serverPort=1999, backlog=1000, compress=False):
self.packetCount = 0
self.port = port
self.serverPort = serverPort
self.serverIP = server
self.serverAddress = NetAddress()
self.serverAddress.setHost(server, serverPort)
self.cManager = QueuedConnectionManager()
self.cReader = QueuedConnectionReader(self.cManager, 0)
self.cWriter = ConnectionWriter(self.cManager, 0)

self.udpSocket = self.cManager.openUDPConnection(self.port)
self.cReader.addConnection(self.udpSocket)

self.startPolling()

def startPolling(self):
taskMgr.add(self.tskReaderPolling, "serverListenTask", -40)

def tskReaderPolling(self, taskdata):
if self.cReader.dataAvailable():
datagram = NetDatagram() # catch the incoming data in this instance
# Check the return value; if we were threaded, someone else could have
# snagged this data before we did
if self.cReader.getData(datagram):
myIterator = PyDatagramIterator(datagram)
msgID = myIterator.getUint8()

#If not in our protocol range then we just reject
if msgID < 0 or msgID > 200:
return taskdata.cont

#Order of these will need to be optimized later
#We now pull out the rest of our headers
remotePacketCount = myIterator.getUint8()
ack = myIterator.getUint8()
acks = myIterator.getUint16()
hashID = myIterator.getUint16()
sourceOfMessage = datagram.getConnection()

if msgID == protocol.LOGIN_ACCEPTED:
log.info("Login accepted")
universals.day = myIterator.getFloat32()
print "Day set to", universals.day
elif msgID == protocol.LOGIN_DENIED:
log.info("Login failed")
return taskdata.cont

def genBasicData(self, proto):
myPyDatagram = PyDatagram()
myPyDatagram.addUint8(proto)
myPyDatagram.addUint8(self.packetCount)
myPyDatagram.addUint8(0)
myPyDatagram.addUint16(0)
myPyDatagram.addUint16(0)
self.packetCount += 1
return myPyDatagram

def sendLogin(self, username, hashpassword):
datagram = self.genBasicData(protocol.LOGIN)
datagram.addString("User name")
datagram.addString("Hashed password")
log.debug("sending login")
self.sendData(datagram)

def sendData(self, datagram):
sent = self.cWriter.send(datagram, self.udpSocket, self.serverAddress)
while not sent:
print "resending"
sent = self.cWriter.send(datagram, self.udpSocket, self.serverAddress)

log.info("Setting up Solar System Body Simulator")
sandbox.addSystem(solarSystem.SolarSystemSystem(solarSystem.BaryCenter, solarSystem.Body, solarSystem.Star))

def planetPositionDebug(task):
log.debug("===== Day: " + str(universals.day) + " =====")
for bod in sandbox.getSystem(solarSystem.SolarSystemSystem).bodies:
log.debug(bod.getName() + ": " + str(bod.getPos()))
return task.again

taskMgr.doMethodLater(10, planetPositionDebug, "Position Debug")

network = ClientNetworkSystem()
sandbox.addSystem(network)



taskMgr.doMethodLater(2, network.sendLogin, 'Task Name', extraArgs=["croxis", "pass"])
sandbox.run()
236 changes: 63 additions & 173 deletions main.py
Expand Up @@ -23,8 +23,9 @@
from pandac.PandaModules import loadPrcFileData
#import Globals

def usage(code, msg = ''):
print >> sys.stderr, usageText % {'prog' : os.path.split(sys.argv[0])[1]}

def usage(code, msg=''):
print >> sys.stderr, usageText % {'prog': os.path.split(sys.argv[0])[1]}
print >> sys.stderr, msg
sys.exit(code)

Expand Down Expand Up @@ -99,189 +100,78 @@ def usage(code, msg = ''):
from direct.directnotify.DirectNotify import DirectNotify
log = DirectNotify().newCategory("ITF")

log.debug("Loading SandBox")
import sys
sys.path.append("/home/croxis/src")
import SandBox

from direct.stdpy.file import *
from direct.task.Task import Task

from panda3d.core import NodePath, Point3
log.debug("Loading sandbox")

import math
from math import sin, cos, pi, radians, degrees, sqrt, atan2
import sandbox

import yaml
from direct.stdpy.file import *

import serverNet
from panda3d.bullet import BulletRigidBodyNode, BulletSphereShape, BulletWorld
from panda3d.core import Point3, Vec3

log.debug("Making room for globals")
solarSystemRoot = 0
# Connivance constant, number of seconds in an Earth day
SECONDSINDAY = 86400

# Time acceleration factor
# Default is 31,536,000 (365.25*24*60), or the earth orbits the sun in one minute
#TIMEFACTOR = 525969.162726
# Factor where it orbits once every 5 minutes
#TIMEFACTOR = 105193.832545
# Once an hour
#TIMEFACTOR = 8766.1527121
# Once a day
#TIMEFACTOR = 365.256363004
# Realtime
#TIMEFACTOR = 1
TIMEFACTOR = 100.0

# Julian day based on J2000.
day = 9131.25
bods = []


class BaryCenter(NodePath):
pass

class Body(BaryCenter):
period = 0
mass = 1
radius = 1
kind = "solid"
orbit = {}

class Star(Body):
kind = "star"
absoluteM = 1
spectralType = ""

def getBodyPosition(entity, time):
# Convert to radians
M = radians(eval(entity.orbit['M'])(time))
w = radians(eval(entity.orbit['w'])(time))
i = radians(eval(entity.orbit['i'])(time))
N = radians(eval(entity.orbit['N'])(time))
a = entity.orbit['a']
e = eval(entity.orbit['e'])(time)

# Compute eccentric anomaly
E = M + e * sin(M) * (1.0 + e * cos(M))
if degrees(E) > 0.05:
E = computeE(E, M, e)
# http:#stjarnhimlen.se/comp/tutorial.html
# Compute distance and true anomaly
xv = a * (cos(E) - e)
yv = a * (sqrt(1.0- e*e)* sin(E))

v = atan2(yv, xv)
r = sqrt(xv*xv + yv*yv)

xh = r * ( cos(N) * cos(v+w) - sin(N) * sin(v+w) * cos(i) )
yh = r * ( sin(N) * cos(v+w) + cos(N) * sin(v+w) * cos(i) )
zh = r * ( sin(v+w) * sin(i) )
position = Point3(xh, yh, zh)
# If we are not a moon then our orbits are done in au. We need to convert to km
# FIXME: Add moon body type
if entity.type != 'moon':
position = position*149598000
return position


def computeE(E0, M, e):
'''Iterative function for a higher accuracy of E'''
E1 = E0 - (E0 - e * sin(E0) - M) / (1 - e * cos(E0))
if abs(abs(degrees(E1)) - abs(degrees(E0))) > 0.001:
E1 = computeE(E1, M, e)
return E1

class SolarSystemSystem(SandBox.EntitySystem):
def process(self, entity):
'''Gets the xyz position of the body, relative to its parent, on the given day before/after the date of element. Units will be in AU'''
component = 0
try:
component = entity.getComponent(BaryCenter)
except:
try:
component = entity.getComponent(Body)
except:
component = entity.getComponent(Star)
finally:
if component.hasOrbit:
component.setPos(getBodyPosition(component, day))


def setupBodies(name):
log.debug("Loading Solar System Bodies")
stream = file("solarsystem.yaml", "r")
solarDB = yaml.load(stream)
stream.close()
bodies = []
solarSystemRoot = NodePath(name)
for bodyName, bodyDB in solarDB[name].items():
generateNode(bodies, bodyName, bodyDB, solarSystemRoot)


def generateNode(bodies, name, DB, parentNode):
log.debug("Setting up " + name)
bodyEntity = SandBox.createEntity()
if DB['type'] == 'solid':
body = Body(name)
elif DB['type'] == 'moon':
body = Body(name)
body.kind = "moon"
elif DB['type'] == 'star':
body = Star(name)
body.absoluteM = DB['absolute magnitude']
body.spectral = DB['spectral']
elif DB['type'] == 'barycenter':
body = BaryCenter(name)

if DB['type'] != "barycenter":
body.mass = DB['mass']
body.radius = DB['radius']
body.rotation = DB['rotation']

if 'orbit' in DB:
body.hasOrbit = True
body.orbit = DB['orbit']
body.period = DB['period']
else:
body.hasOrbit = False

body.type = DB['type']
body.reparentTo(parentNode)


bodyEntity.addComponent(body)

bodies.append(body)
bods.append(body)
log.info(name + " set Up")

if 'bodies' in DB:
for bodyName, bodyDB in DB['bodies'].items():
generateNode(bodies, bodyName, bodyDB, body)


import serverNet
import ships
import solarSystem
import universals

log.info("Setting up Solar System Body Simulator")
SandBox.addSystem(SolarSystemSystem(BaryCenter, Body, Star))
setupBodies("Sol")

def simulationTask(task):
global day
day += globalClock.getDt()/86400 * TIMEFACTOR
return task.cont
sandbox.addSystem(solarSystem.SolarSystemSystem(solarSystem.BaryCenter, solarSystem.Body, solarSystem.Star))

def planetPositionDebug(task):
log.debug("===== Day: " + str(day) + " =====")
for bod in bods:
log.debug("===== Day: " + str(universals.day) + " =====")
for bod in sandbox.getSystem(solarSystem.SolarSystemSystem).bodies:
log.debug(bod.getName() + ": " + str(bod.getPos()))
return task.again

taskMgr.add(simulationTask, "Physics Simulation")
taskMgr.doMethodLater(10, planetPositionDebug, "Position Debug")

log.info("Setting up network")
SandBox.addSystem(serverNet.NetworkSystem())
log.info("Setting up dynamic physics")


class PhysicsSystem(sandbox.EntitySystem):
def init(self):
self.world = BulletWorld()

SandBox.run()
def begin(self):
dt = globalClock.getDt()
self.world.doPhysics(dt)
#world.doPhysics(dt, 10, 1.0/180.0)

sandbox.addSystem(PhysicsSystem(ships.BulletPhysicsComponent))

log.info("Setting up network")
sandbox.addSystem(serverNet.NetworkSystem())

log.info("Setting up player-ship interface system")


class PlayerShipsSystem(sandbox.EntitySystem):
#TODO: Add client --> network request
#TODO: Add automatic update
def newPlayerShip(account):
ship = sandbox.createEntity()
ship.addComponent(ships.PilotComponent())
component = ships.BulletPhysicsComponent()
component.bulletShape = BulletSphereShape(5)
component.node = BulletRigidBodyNode(account.name)
component.node.setMass(1.0)
component.node.addShape(component.bulletShape)
sandbox.getSystem(PhysicsSystem).world.attachRigidBody(component.node)
position = sandbox.getSystem(solarSystem.SolarSystemSystem).solarSystemRoot.find("Sol/Sol/Earth").getPos()
component.node.setPos(position + Point3(6671, 0, 0))
component.node.setLinearVelocity(Vec3(0, 7.72983, 0))
ship.addComponent(component)
component = ships.ThrustComponent()
ship.addComponent(component)
component = ships.HealthComponent()
ship.addComponent(component)

#TODO Transmit player's ship data
#TODO Broadcast new ship data
#TODO Prioritize updating new client of surroundings

sandbox.addSystem(PlayerShipsSystem(ships.PilotComponent))


sandbox.run()
Binary file added main.pyc
Binary file not shown.

0 comments on commit 0e28274

Please sign in to comment.