open_toontown_panda3d/samples/networking/03-distributed-node/client.py

137 lines
4.9 KiB
Python

# all imports needed by the engine itself
from direct.showbase.ShowBase import ShowBase
# initialize the engine
base = ShowBase()
# initialize the client
from direct.distributed.ClientRepository import ClientRepository
from panda3d.core import URLSpec, ConfigVariableInt, ConfigVariableString
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import TextNode
base.accept("escape", exit)
# Function to put instructions on the screen.
def addInstructions(pos, msg):
return OnscreenText(text=msg, style=1, fg=(0, 0, 0, 1), shadow=(1, 1, 1, 1),
parent=base.a2dTopLeft, align=TextNode.ALeft,
pos=(0.08, -pos - 0.04), scale=.06)
# Function to put title on the screen.
def addTitle(text):
return OnscreenText(text=text, style=1, pos=(-0.1, 0.09), scale=.08,
parent=base.a2dBottomRight, align=TextNode.ARight,
fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1))
title = addTitle("Panda3D: Tutorial - Distributed Network (NOT CONNECTED)")
inst1 = addInstructions(0.06, "esc: Close the client")
inst2 = addInstructions(0.12, "See console output")
def setConnectedMessage():
title["text"] = "Panda3D: Tutorial - Distributed Network (CONNECTED)"
base.accept("client-ready", setConnectedMessage)
#
# CLIENT
#
class GameClientRepository(ClientRepository):
def __init__(self):
dcFileNames = ['../direct.dc']
# a distributed object of our game.
self.distributedObject = None
self.aiDGameObect = None
ClientRepository.__init__(
self,
dcFileNames = dcFileNames,
threadedNet = True)
# Set the same port as configured on the server to be able to connect
# to it
tcpPort = ConfigVariableInt('server-port', 4400).getValue()
# Set the IP or hostname of the server we want to connect to
hostname = ConfigVariableString('server-host', '127.0.0.1').getValue()
# Build the URL from the server hostname and port. If your server
# uses another protocol then http you should change it accordingly.
# Make sure to pass the connectMethod to the ClientRepository.__init__
# call too. Available connection methods are:
# self.CM_HTTP, self.CM_NET and self.CM_NATIVE
self.url = URLSpec('http://{}:{}'.format(hostname, tcpPort))
# Attempt a connection to the server
self.connect([self.url],
successCallback = self.connectSuccess,
failureCallback = self.connectFailure)
def lostConnection(self):
""" This should be overridden by a derived class to handle an
unexpectedly lost connection to the gameserver. """
# Handle the disconnection from the server. This can be a reconnect,
# simply exiting the application or anything else.
exit()
def connectFailure(self, statusCode, statusString):
""" Something went wrong """
# we could create a reconnect task to try and connect again.
exit()
def connectSuccess(self):
""" Successfully connected. But we still can't really do
anything until we've got the doID range. """
# Make sure we have interest in the by the AIRepository defined
# TimeManager zone, so we always see it even if we switch to
# another zone.
self.setInterestZones([1])
# We must wait for the TimeManager to be fully created and
# synced before we can enter another zone and wait for the
# game object. The uniqueName is important that we get the
# correct, our sync message from the TimeManager and not
# accidentaly a message from another client
self.acceptOnce(self.uniqueName('gotTimeSync'), self.syncReady)
def syncReady(self):
""" Now we've got the TimeManager manifested, and we're in
sync with the server time. Now we can enter the world. Check
to see if we've received our doIdBase yet. """
# This method checks whether we actually have a valid doID range
# to create distributed objects yet
if self.haveCreateAuthority():
# we already have one
self.gotCreateReady()
else:
# Not yet, keep waiting a bit longer.
self.accept(self.uniqueName('createReady'), self.gotCreateReady)
def gotCreateReady(self):
""" Ready to enter the world. Expand our interest to include
any other zones """
# This method checks whether we actually have a valid doID range
# to create distributed objects yet
if not self.haveCreateAuthority():
# Not ready yet.
return
# we are ready now, so ignore further createReady events
self.ignore(self.uniqueName('createReady'))
print("Client Ready")
base.messenger.send("client-ready")
# Start the client
client = GameClientRepository()
base.run()