def sendActivate(self, doId, parentId, zoneId, dclass=None, fields=None): """ Activate a DBSS object, given its doId, into the specified parentId/zoneId. If both dclass and fields are specified, an ACTIVATE_WITH_DEFAULTS_OTHER will be sent instead. In other words, the specified fields will be auto-applied during the activation. """ fieldPacker = DCPacker() fieldCount = 0 if dclass and fields: for k, v in fields.items(): field = dclass.getFieldByName(k) if not field: self.notify.error( 'Activation request for %s object contains ' 'invalid field named %s' % (dclass.getName(), k)) fieldPacker.rawPackUint16(field.getNumber()) fieldPacker.beginPack(field) field.packArgs(fieldPacker, v) fieldPacker.endPack() fieldCount += 1 dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS) dg.addUint32(doId) dg.addUint32(0) dg.addUint32(0) self.send(dg) # DEFAULTS_OTHER isn't implemented yet, so we chase it with a SET_FIELDS dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, STATESERVER_OBJECT_SET_FIELDS) dg.addUint32(doId) dg.addUint16(fieldCount) dg.appendData(fieldPacker.getString()) self.send(dg) # Now slide it into the zone we expect to see it in (so it # generates onto us with all of the fields in place) dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, STATESERVER_OBJECT_SET_LOCATION) dg.addUint32(parentId) dg.addUint32(zoneId) self.send(dg) else: dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS) dg.addUint32(doId) dg.addUint32(parentId) dg.addUint32(zoneId) self.send(dg)
def sendSetLocation(self, do, parentId, zoneId): dg = PyDatagram() dg.addServerHeader(do.doId, self.ourChannel, STATESERVER_OBJECT_SET_LOCATION) dg.addUint32(parentId) dg.addUint32(zoneId) self.send(dg)
def _sendRemoveInterest(self, handle, contextId): datagram = PyDatagram() datagram.addUint16(CLIENT_REMOVE_INTEREST) datagram.addUint16(handle) if contextId != 0: datagram.addUint32(contextId) self.send(datagram)
def _sendAddInterest(self, contextId, scopeId, parentId, zoneIdList): """ Part of the new otp-server code. contextId is a client-side created number that refers to a set of interests. The same contextId number doesn't necessarily have any relationship to the same contextId on another client. """ assert self.notify.debugCall() datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_ADD_INTEREST) datagram.addUint16(contextId) datagram.addUint32(scopeId) datagram.addUint32(parentId) if isinstance(zoneIdList, types.ListType): vzl = list(zoneIdList) vzl.sort() PythonUtil.uniqueElements(vzl) for zone in vzl: datagram.addUint32(zone) else: datagram.addUint32(zoneIdList) self.send(datagram)
def sendSetLocation(self, doId, parentId, zoneId): datagram = PyDatagram() datagram.addUint16(CLIENT_OBJECT_LOCATION) datagram.addUint32(doId) datagram.addUint32(parentId) datagram.addUint32(zoneId) self.send(datagram)
def writeServerEvent(self, logtype, *args, **kwargs): """ Write an event to the central Event Logger, if one is configured. The purpose of the Event Logger is to keep a game-wide record of all interesting in-game events that take place. Therefore, this function should be used whenever such an interesting in-game event occurs. """ if self.eventSocket is None: return # No event logger configured! log = collections.OrderedDict() log['type'] = logtype log['sender'] = self.eventLogId for i, v in enumerate(args): # +1 because the logtype was _0, so we start at _1 log['_%d' % (i + 1)] = v log.update(kwargs) dg = PyDatagram() msgpack_encode(dg, log) self.eventSocket.Send(dg.getMessage())
def _sendAddInterest(self, handle, contextId, parentId, zoneIdList, description, action=None): if parentId == 0: DoInterestManager.notify.error( 'trying to set interest to invalid parent: %s' % parentId) datagram = PyDatagram() datagram.addUint16(CLIENT_ADD_INTEREST) datagram.addUint16(handle) datagram.addUint32(contextId) datagram.addUint32(parentId) if isinstance(zoneIdList, types.ListType): vzl = list(zoneIdList) vzl.sort() uniqueElements(vzl) for zone in vzl: datagram.addUint32(zone) else: datagram.addUint32(zoneIdList) self.send(datagram)
def setInterestZones(self, interestZoneIds): datagram = PyDatagram() datagram.addUint16(CLIENT_SET_INTEREST_CMU) for zoneId in interestZoneIds: datagram.addUint32(zoneId) self.send(datagram) self.interestZones = interestZoneIds[:]
def sendDisconnect(self): if self.isConnected(): datagram = PyDatagram() datagram.addUint16(CLIENT_DISCONNECT_CMU) self.send(datagram) self.notify.info('Sent disconnect message to server') self.disconnect() self.stopHeartbeat()
def sendDeleteMsg(self, doId): # This method is only used in conjunction with the CMU LAN # server. datagram = PyDatagram() datagram.addUint16(CLIENT_OBJECT_DELETE) datagram.addUint32(doId) self.send(datagram)
def sendSetShardMsg(self, shardId): datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_SET_SHARD) # Add shard id datagram.addUint32(shardId) # send the message self.send(datagram)
def getActivated(self, doId, callback): ctx = self.getContext() self.__callbacks[ctx] = callback dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, DBSS_OBJECT_GET_ACTIVATED) dg.addUint32(ctx) dg.addUint32(doId) self.send(dg)
def sendUpdateToChannel(self, distObj, channelId, fieldName, args): datagram = distObj.dclass.clientFormatUpdate(fieldName, distObj.doId, args) dgi = PyDatagramIterator(datagram) dgi.getUint16() dg = PyDatagram() dg.addUint16(CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU) dg.addUint32(channelId & 4294967295L) dg.appendData(dgi.getRemainingBytes()) self.send(dg)
def sendHeartbeat(self): datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_HEARTBEAT) # Send it! self.send(datagram) self.lastHeartbeat = globalClock.getRealTime() # This is important enough to consider flushing immediately # (particularly if we haven't run readerPollTask recently). self.considerFlush()
def setAI(self, doId, aiChannel): """ Sets the AI of the specified DistributedObjectAI to be the specified channel. Generally, you should not call this method, and instead call DistributedObjectAI.setAI. """ dg = PyDatagram() dg.addServerHeader(doId, aiChannel, STATESERVER_OBJECT_SET_AI) dg.add_uint64(aiChannel) self.send(dg)
def _sendRemoveAIInterest(self, handle): """ handle is a bare int, NOT an InterestHandle. Use this to close an AI opened interest. """ datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_REMOVE_INTEREST) datagram.addUint16((1<<15) + handle) self.send(datagram)
def eject(self, clientChannel, reasonCode, reason): """ Kicks the client residing at the specified clientChannel, using the specifed reasoning. """ dg = PyDatagram() dg.addServerHeader(clientChannel, self.ourChannel, CLIENTAGENT_EJECT) dg.add_uint16(reasonCode) dg.addString(reason) self.send(dg)
def setOwner(self, doId, newOwner): """ Sets the owner of a DistributedObject. This will enable the new owner to send "ownsend" fields, and will generate an OwnerView. """ dg = PyDatagram() dg.addServerHeader(doId, self.ourChannel, STATESERVER_OBJECT_SET_OWNER) dg.add_uint64(newOwner) self.send(dg)
def sendDisconnect(self): if self.isConnected(): # Tell the game server that we're going: datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_DISCONNECT) # Send the message self.send(datagram) self.notify.info("Sent disconnect message to server") self.disconnect() self.stopHeartbeat()
def setClientState(self, clientChannel, state): """ Sets the state of the client on the CA. Useful for logging in and logging out, and for little else. """ dg = PyDatagram() dg.addServerHeader(clientChannel, self.ourChannel, CLIENTAGENT_SET_STATE) dg.add_uint16(state) self.send(dg)
def clearPostRemove(self): """ Clear all datagrams registered with addPostRemove. This is useful if the Panda3D process is performing a clean exit. It may clear the "emergency clean-up" post-remove messages and perform a normal exit-time clean-up instead, depending on the specific design of the game. """ dg = PyDatagram() dg.addServerControlHeader(CONTROL_CLEAR_POST_REMOVE) self.send(dg)
def requestDelete(self, do): """ Request the deletion of an object that already exists on the State Server. You should probably use do.requestDelete() instead. """ dg = PyDatagram() dg.addServerHeader(do.doId, self.ourChannel, STATESERVER_OBJECT_DELETE_RAM) dg.addUint32(do.doId) self.send(dg)
def clientAddSessionObject(self, clientChannel, doId): """ Declares the specified DistributedObject to be a "session object", meaning that it is destroyed when the client disconnects. Generally used for avatars owned by the client. """ dg = PyDatagram() dg.addServerHeader(clientChannel, self.ourChannel, CLIENTAGENT_ADD_SESSION_OBJECT) dg.add_uint32(doId) self.send(dg)
def _sendRemoveInterest(self, contextId): """ contextId is a client-side created number that refers to a set of interests. The same contextId number doesn't necessarily have any relationship to the same contextId on another client. """ assert self.notify.debugCall() datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_REMOVE_INTEREST) datagram.addUint16(contextId) self.send(datagram)
def __getBarrierData(self): # Returns the barrier data formatted as a blob for sending to # the clients. This lists all of the current outstanding # barriers and the avIds waiting for them. dg = PyDatagram() for context, barrier in self.__barriers.items(): toons = barrier.pendingToons if toons: dg.addUint16(context) dg.addUint16(len(toons)) for avId in toons: dg.addUint32(avId) return dg.getMessage()
def requestDelete(self, do): """ Request the deletion of an object that already exists on the State Server. You should use do.requestDelete() instead. This is not meant to be called directly unless you really know what you are doing. """ dg = PyDatagram() dg.addServerHeader(do.doId, self.ourChannel, STATESERVER_OBJECT_DELETE_RAM) dg.addUint32(do.doId) self.send(dg)
def addPostRemove(self, dg): """ Register a datagram with the Message Director that gets sent out if the connection is ever lost. This is useful for registering cleanup messages: If the Panda3D process ever crashes unexpectedly, the Message Director will detect the socket close and automatically process any post-remove datagrams. """ dg2 = PyDatagram() dg2.addServerControlHeader(CONTROL_ADD_POST_REMOVE) dg2.addString(dg.getMessage()) self.send(dg2)
def setInterestZones(self, interestZoneIds): """ Changes the set of zones that this particular client is interested in hearing about. """ datagram = PyDatagram() # Add message type datagram.addUint16(CLIENT_SET_INTEREST_CMU) for zoneId in interestZoneIds: datagram.addUint32(zoneId) # send the message self.send(datagram) self.interestZones = interestZoneIds[:]
def clientAddInterest(self, clientChannel, interestId, parentId, zoneId): """ Opens an interest on the behalf of the client. This, used in conjunction with add_interest: visible (or preferably, disabled altogether), will mitigate possible security risks. """ dg = PyDatagram() dg.addServerHeader(clientChannel, self.ourChannel, CLIENTAGENT_ADD_INTEREST) dg.add_uint16(interestId) dg.add_uint32(parentId) dg.add_uint32(zoneId) self.send(dg)
def unregisterForChannel(self, channel): """ Unregister a channel subscription on the Message Director. The Message Director will cease to relay messages to this AIR sent on the channel. """ if channel not in self._registeredChannels: return self._registeredChannels.remove(channel) dg = PyDatagram() dg.addServerControlHeader(CONTROL_REMOVE_CHANNEL) dg.addChannel(channel) self.send(dg)