Distributed Networking usage

I’ve been trying to figure out the Distributed Networking system based on what’s in the documentation and the few samples I’ve been able to find. I’ve gotten the samples working fine, but I’m still puzzled as to how exactly to apply them to my project.

Right now, I’m trying to set up a very basic system with a DistributedNode object on a server. At this point, I’m having trouble getting a ServerRepository object set up - I’m not sure what I’m missing, but I’m getting

TypeError: ConnectionReader.addConnection() argument 1 must be Connection, not NoneType

This is the code I’ve got so far:

nettest.py:

from direct.directbase.DirectStart import *

from direct.distributed.DistributedNode import *
from direct.distributed.ClientRepository import *
from direct.distributed.ServerRepository import *
from direct.distributed.ServerRepository import ServerRepository
from direct.distributed.DistributedNodeAI import DistributedNodeAI

import sys

class DistributedThingy(DistributedNode):
	def __init__(self, cr):
        	DistributedNode.__init__(self, cr)

	def generate(self):
		print 'Thingy generated!'

class DistributedThingyAI(DistributedNodeAI):
    """ This is the AI-side implementation of DistributedThingy. """

    def __init__(self, cr):
        DistributedNodeAI.__init__(self, cr)
        print 'ThingyAI inited!'

class MyServerRepository(ServerRepository):
    def __init__(self):
        tcpPort = base.config.GetInt('server-port', 4288)
        dcFileNames = ['direct.dc']
        
        ServerRepository.__init__(self, tcpPort = tcpPort, serverAddress = '', dcFileNames = dcFileNames)

class Server:
	def __init__(self):
		self.sr = MyServerRepository()

print '-s to start server instance, -c to start client instance'
if len(sys.argv) > 1:
	if sys.argv[1] == '-s':
		s = Server()
		print 'Server started!'
		run()
	if sys.argv[1] == '-c':
		print 'Client not yet implemented...'

and my direct.dc file:

keyword broadcast;
keyword ram;
keyword p2p;

from direct.distributed import DistributedObject/AI
from direct.distributed import TimeManager/AI
from direct.distributed import DistributedNode/AI
from direct.distributed import DistributedSmoothNode/AI

import nettest.py

struct BarrierData {
  uint16 context;
  string name;
  uint32 avIds[];
};

// The most fundamental class
dclass DistributedObject {
  // These are used to support DistributedObjectAI.beginBarrier() and
  // the matching DistributedObject.doneBarrier().  If you don't call
  // these functions, you don't care about these distributed methods.
  // (Actually, you probably don't care anyway.)
  setBarrierData(BarrierData data[]) broadcast ram;
  setBarrierReady(uint16 context);
};

dclass DistributedNode: DistributedObject {
  setX(int16 / 10) broadcast ram;
  setY(int16 / 10) broadcast ram;
  setZ(int16 / 10) broadcast ram;
  setH(int16 % 360 / 10) broadcast ram;
  setP(int16 % 360 / 10) broadcast ram;
  setR(int16 % 360 / 10) broadcast ram;

  setPos: setX, setY, setZ;
  setHpr: setH, setP, setR;
  setPosHpr: setX, setY, setZ, setH, setP, setR;
  setXY: setX, setY;
  setXZ: setX, setZ;
  setXYH: setX, setY, setH;
  setXYZH: setX, setY, setZ, setH;
};

dclass DistributedSmoothNode: DistributedNode {
  // Component set pos and hpr functions.

  setComponentL(uint64) broadcast ram;
  setComponentX(int16 / 10) broadcast ram;
  setComponentY(int16 / 10) broadcast ram;
  setComponentZ(int16 / 10) broadcast ram;
  setComponentH(int16 % 360 / 10) broadcast ram;
  setComponentP(int16 % 360 / 10) broadcast ram;
  setComponentR(int16 % 360 / 10) broadcast ram;
  setComponentT(int16 timestamp) broadcast ram;

  // Composite set pos and hpr functions.  These map to combinations
  // of one or more of the above components.  They all include
  // setComponentT(), which must be called last.
  setSmStop: setComponentT;
  setSmH: setComponentH, setComponentT;
  setSmZ: setComponentZ, setComponentT;
  setSmXY: setComponentX, setComponentY, setComponentT;
  setSmXZ: setComponentX, setComponentZ, setComponentT;
  setSmPos: setComponentX, setComponentY, setComponentZ, setComponentT;
  setSmHpr: setComponentH, setComponentP, setComponentR, setComponentT;
  setSmXYH: setComponentX, setComponentY, setComponentH, setComponentT;
  setSmXYZH: setComponentX, setComponentY, setComponentZ, setComponentH, setComponentT;
  setSmPosHpr: setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;
  // special update if L (being location, such as zoneId) changes, send everything, intended to
  // keep position and 'location' in sync
  setSmPosHprL: setComponentL, setComponentX, setComponentY, setComponentZ, setComponentH, setComponentP, setComponentR, setComponentT;

  clearSmoothing(int8 bogus) broadcast;

  suggestResync(uint32 avId, int16 timestampA, int16 timestampB,
                int32 serverTimeSec, uint16 serverTimeUSec,
                uint16 / 100 uncertainty);
  returnResync(uint32 avId, int16 timestampB,
               int32 serverTimeSec, uint16 serverTimeUSec,
               uint16 / 100 uncertainty);
}; 

dclass DistributedThingy: DistributedNode {

};

I’m suspect I’m doing something out of sequence, but I can’t work out where the issue is.

Your code works fine for me when I paste it in and run it (with the minor exception of the “import nettest.py” line in your dc file, which should be “import nettest”).

Can you show the entire stack trace from your error? It might give more insight. Also, are there any error messages earlier about failing to open a connection?

David

:blush: “import nettest.py” is what I get for coding after a long workday…

But I am still getting the same error after fixing that - here’s my entire output:

DirectStart: Starting the game.
Known pipe types:
  glxGraphicsPipe
(all display modules loaded.)
:display:gsg:glgsg(error): at 1438 of panda/src/glstuff/glGraphicsStateGuardian_src.cxx : GL error 1280
-s to start server instance, -c to start client instance
DCFile::read of /home/stew/python/mnet/direct.dc
-s to start server instance, -c to start client instance
Traceback (most recent call last):
  File "nettest.py", line 88, in <module>
    s = Server()
  File "nettest.py", line 72, in __init__
    self.sr = MyServerRepository()
  File "nettest.py", line 34, in __init__
    ServerRepository.__init__(self, tcpPort = tcpPort, serverAddress = '', dcFileNames = dcFileNames)
  File "/usr/share/panda3d/direct/distributed/ServerRepository.py", line 143, in __init__
    self.readDCFile(dcFileNames)
  File "/usr/share/panda3d/direct/distributed/ServerRepository.py", line 256, in readDCFile
    self.importModule(dcImports, moduleName, importSymbols)
  File "/usr/share/panda3d/direct/distributed/ServerRepository.py", line 178, in importModule
    module = __import__(moduleName, globals(), locals(), importSymbols)
  File "/home/stew/python/mnet/nettest.py", line 88, in <module>
    s = Server()
  File "/home/stew/python/mnet/nettest.py", line 72, in __init__
    self.sr = MyServerRepository()
  File "/home/stew/python/mnet/nettest.py", line 34, in __init__
    ServerRepository.__init__(self, tcpPort = tcpPort, serverAddress = '', dcFileNames = dcFileNames)
  File "/usr/share/panda3d/direct/distributed/ServerRepository.py", line 104, in __init__
    self.qcl.addConnection(self.tcpRendezvous)
TypeError: ConnectionReader.addConnection() argument 1 must be Connection, not NoneType

Only possible error I’m seeing is the GL Error; but I’m not sure why that would be an issue.

It means that it failed to open your rendezvous port (looks like 4288 in your code, unless you have a Config.prc setting differently). Normally the port numbers below 1024 are reserved for system processes, but there should be no restriction on port 4288, unless some other process already has it open.

David

…again, it was staring me in the face - I didn’t have a __name == ‘main’ restriction, so there was some fighting for the port, and probably other contention stuff. I’m a bit out of practice with Python :stuck_out_tongue:

So, now I’m getting somewhere - I’m up to trying to populate an AIRepository. I’ve added in the following code to nettest.py:

class MyAIRepository(ClientRepository):
    def __init__(self):
        dcFileNames = ['direct.dc']
        
        ClientRepository.__init__(self, dcFileNames = dcFileNames,
                                  dcSuffix = 'AI')

        tcpPort = base.config.GetInt('server-port', 4288)
        url = URLSpec('http://127.0.0.1:%s' % (tcpPort))
        self.connect([url],
                     successCallback = self.connectSuccess,
                     failureCallback = self.connectFailure)
			print 'AI Repository starting...'
        
    def connectFailure(self, statusCode, statusString):
        raise StandardError, statusString

    def connectSuccess(self):
        """ Successfully connected.  But we still can't really do
        anything until we've got the doID range. """
        self.acceptOnce('createReady', self.createReady)
			print 'AI Repository connected!'

    def createReady(self):
        """ Now we're ready to go! """
		print 'Populating AI Repository...'
		ob = self.createDistributedObject(className = 'DistributedThingy', zoneId = 1)


class Server:
	def __init__(self):
		self.sr = MyServerRepository()
		self.air = MyAIRepository()
	

and when it gets to the ‘ob =’ line in MyAIRepository.CreateReady, it’s telling me that DistributedThingy is undefined:

  File "/usr/share/panda3d/direct/distributed/ClientRepository.py", line 205, in createDistributedObject
    dclass.getName()))
  File "/usr/share/panda3d/direct/directnotify/Notifier.py", line 132, in error
    raise exception(errorString)
StandardError: Could not create an undefined DistributedThingy object.

Is it confused because I don’t have any distributed methods defined in the .dc file? I assumed it’d inherit anything it urgently needed from DistributedNode, and I’d just have to define any new distributed methods once it was working. Or is there something else I haven’t defined yet?

It means you didn’t import DistributedThingy into your dc file.

David

Okay - I had them defined in the nettest.py file; so I assumed it’d be able to find them in the namespace. I had planned to have the different base class files (the .py files) in different directories later - is the .dc file going to be able to find them, or do I need to adjust my project structure so the distributed object base classes are all together?

Thanks for taking the time to help me out with these issues! I do have a very basic distributed “thingy” working now :stuck_out_tongue: I have a few more things I need it to do before it’s ready, but where I’m working on this in my odd evening hours, I really appreciate all the pointers. :slight_smile:

You need to explicitly import any class files you reference.