client.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # all imports needed by the engine itself
  2. from direct.showbase.ShowBase import ShowBase
  3. # initialize the engine
  4. base = ShowBase()
  5. # initialize the client
  6. from direct.distributed.ClientRepository import ClientRepository
  7. from panda3d.core import URLSpec, ConfigVariableInt, ConfigVariableString
  8. from direct.gui.OnscreenText import OnscreenText
  9. from panda3d.core import TextNode
  10. base.accept("escape", exit)
  11. # Function to put instructions on the screen.
  12. def addInstructions(pos, msg):
  13. return OnscreenText(text=msg, style=1, fg=(0, 0, 0, 1), shadow=(1, 1, 1, 1),
  14. parent=base.a2dTopLeft, align=TextNode.ALeft,
  15. pos=(0.08, -pos - 0.04), scale=.06)
  16. # Function to put title on the screen.
  17. def addTitle(text):
  18. return OnscreenText(text=text, style=1, pos=(-0.1, 0.09), scale=.08,
  19. parent=base.a2dBottomRight, align=TextNode.ARight,
  20. fg=(1, 1, 1, 1), shadow=(0, 0, 0, 1))
  21. title = addTitle("Panda3D: Tutorial - Distributed Network (NOT CONNECTED)")
  22. inst1 = addInstructions(0.06, "esc: Close the client")
  23. inst2 = addInstructions(0.12, "See console output")
  24. def setConnectedMessage():
  25. title["text"] = "Panda3D: Tutorial - Distributed Network (CONNECTED)"
  26. base.accept("client-ready", setConnectedMessage)
  27. #
  28. # CLIENT
  29. #
  30. class GameClientRepository(ClientRepository):
  31. def __init__(self):
  32. dcFileNames = ['../direct.dc']
  33. # a distributed object of our game.
  34. self.distributedObject = None
  35. self.aiDGameObect = None
  36. ClientRepository.__init__(
  37. self,
  38. dcFileNames = dcFileNames,
  39. threadedNet = True)
  40. # Set the same port as configured on the server to be able to connect
  41. # to it
  42. tcpPort = ConfigVariableInt('server-port', 4400).getValue()
  43. # Set the IP or hostname of the server we want to connect to
  44. hostname = ConfigVariableString('server-host', '127.0.0.1').getValue()
  45. # Build the URL from the server hostname and port. If your server
  46. # uses another protocol then http you should change it accordingly.
  47. # Make sure to pass the connectMethod to the ClientRepository.__init__
  48. # call too. Available connection methods are:
  49. # self.CM_HTTP, self.CM_NET and self.CM_NATIVE
  50. self.url = URLSpec('http://{}:{}'.format(hostname, tcpPort))
  51. # Attempt a connection to the server
  52. self.connect([self.url],
  53. successCallback = self.connectSuccess,
  54. failureCallback = self.connectFailure)
  55. def lostConnection(self):
  56. """ This should be overridden by a derived class to handle an
  57. unexpectedly lost connection to the gameserver. """
  58. # Handle the disconnection from the server. This can be a reconnect,
  59. # simply exiting the application or anything else.
  60. exit()
  61. def connectFailure(self, statusCode, statusString):
  62. """ Something went wrong """
  63. # we could create a reconnect task to try and connect again.
  64. exit()
  65. def connectSuccess(self):
  66. """ Successfully connected. But we still can't really do
  67. anything until we've got the doID range. """
  68. # Make sure we have interest in the by the AIRepository defined
  69. # TimeManager zone, so we always see it even if we switch to
  70. # another zone.
  71. self.setInterestZones([1])
  72. # We must wait for the TimeManager to be fully created and
  73. # synced before we can enter another zone and wait for the
  74. # game object. The uniqueName is important that we get the
  75. # correct, our sync message from the TimeManager and not
  76. # accidentaly a message from another client
  77. self.acceptOnce(self.uniqueName('gotTimeSync'), self.syncReady)
  78. def syncReady(self):
  79. """ Now we've got the TimeManager manifested, and we're in
  80. sync with the server time. Now we can enter the world. Check
  81. to see if we've received our doIdBase yet. """
  82. # This method checks whether we actually have a valid doID range
  83. # to create distributed objects yet
  84. if self.haveCreateAuthority():
  85. # we already have one
  86. self.gotCreateReady()
  87. else:
  88. # Not yet, keep waiting a bit longer.
  89. self.accept(self.uniqueName('createReady'), self.gotCreateReady)
  90. def gotCreateReady(self):
  91. """ Ready to enter the world. Expand our interest to include
  92. any other zones """
  93. # This method checks whether we actually have a valid doID range
  94. # to create distributed objects yet
  95. if not self.haveCreateAuthority():
  96. # Not ready yet.
  97. return
  98. # we are ready now, so ignore further createReady events
  99. self.ignore(self.uniqueName('createReady'))
  100. print("Client Ready")
  101. base.messenger.send("client-ready")
  102. # Start the client
  103. client = GameClientRepository()
  104. base.run()