Ejemplo n.º 1
0
 def __init__(self):
     self.player = Player()
     self.sessionID = None  # Session ID, used to communicate between client and server
     self.ip = None
     self.gpp = None
     self.wsID = None  # World Server this user belongs to
     self.identified = False
     self.logger = logging.getLogger("cloudbox.hub.mc.protocol._default") # This will be replaced once we get a proper ID
Ejemplo n.º 2
0
class MinecraftHubServerProtocol(Protocol, CloudBoxProtocolMixin):
    """
    Main protocol class for communicating with clients.
    """

    PACKET_LIMIT_NAME = "outgoing-minecraft"

    def __init__(self):
        self.player = Player()
        self.sessionID = None  # Session ID, used to communicate between client and server
        self.ip = None
        self.gpp = None
        self.wsID = None  # World Server this user belongs to
        self.identified = False
        self.logger = logging.getLogger("cloudbox.hub.mc.protocol._default") # This will be replaced once we get a proper ID

    ### Twisted Methods ###

    def connectionMade(self):
        """
        Called when a connection is made.
        """
        self.gpp = MinecraftClassicPacketProcessor(self, self.factory.handlers, self.transport)
        self.loops.registerLoop("packets", self.gpp.packetLoop).start(self.getTickInterval("minecraft"))
        self.logger.debug("Packet sender started.")
        # Get an ID for ourselves
        self.sessionID = self.factory.claimID(self)
        if self.sessionID is None:
            self.sendError("The server is full.")
            return
        self.ip = IPAddress(self.transport.getPeer().host)
        self.player["ip"] = str(self.ip)  # Everything in self.player needs to be primitive types

        self.logger = logging.getLogger("cloudbox.hub.mc.protocol.{}".format(self.sessionID))

    def connectionLost(self, reason=_connDone):
        # Leave the world
        self.leaveWorldServer(

        )
        # Release our ID
        self.factory.releaseID(self.sessionID)
        # Stop the loops
        self.loops.stopAll()

    def dataReceived(self, data):
        """
        Called when data is received.
        """
        # Add the data we got onto our internal buffer
        self.gpp.feed(data)
        self.logger.debug(data)
        self.gpp.parseFirstPacket()

    ### Message Handling ###

    def sendError(self, error, disconnectNow=False):
        """
        Sends an error the client.
        """
        self.factory.logger.info("Sending error: %s" % error)
        self.sendPacket(TYPE_ERROR, {"error": error})
        if disconnectNow:
            self.transport.loseConnection()
        else:
            reactor.callLater(0.2, self.transport.loseConnection)

    def sendMessage(self, message):
        """
        Sends a message to the client.
        """
        self.sendPacket(TYPE_MESSAGE, {"message": message})

    def sendChanneledMessage(self, message, channel):
        """
        Sends a message that has a channel.
        """
        self.sendMessage(message)

    def sendServerMessage(self, message, channel=None):
        """
        Shortcut for sending a server-like messgae to the client (yellow messgaes)
        """
        self.sendChanneledMessage(COLOUR_YELLOW + message, channel=None)

    def sendKeepAlive(self):
        """
        Sends a ping to the client.
        """
        self.sendPacket(TYPE_KEEPALIVE, {})

    def sendBlock(self, x, y, z, block=None):
        """
        Sends a block.
        """
        if block is not None:
            self.sendPacket(TYPE_BLOCKSET, {"x": x, "y": y, "z": z, "block": block})
        else:
            # Ask the World Server to get the block, and send it.
            # TODO
            return

    ### Relay ###

    def relayClientData(self, handlerID, data):
        pass

    ### Actions  ###

    def _joinWorldFailedErrback(self, err):
        """
        Callback for when world joining failed
        """
        if "world" not in self.player.keys() or self.player["world"] is None:  # We are newbies
            self.sendError("World loading failed - {}".format(str(err)))
        else:
            self.sendServerMessage("World loading failed - {}".format(str(err)))
        # Cancel any stuff if needed to

    def joinDefaultWorld(self):
        """
        Joins the default world.
        """
        mode = self.factory.settings["main"]["entry-mode"]
        if mode == "solo":
            # Find out which WS has the default world and join it
            def afterGetDefaultWorld(res):
                hasFailed(res)
                if not res:
                    raise
                wsf = self.factory.getFactory("WorldServerCommServerFactory")
                # Get world server link
                if res[0]["worldServerID"] not in wsf.worldServers:
                    # WorldServer down, raise hell
                    self.logger.debug(str(res[0]))
                    raise WorldServerLinkException(200, "World server link not established")
                # Send the player over
                wsf.worldServers[res[0]["worldServerID"]].protoDoJoinServer(self, res[0]["id"]) # TODO World name or ID?
            return self.db.runQuery(
                *World.select(World.name, World.id, World.filePath, World.worldServerID).where(World.isDefault == 1).sql()
            ).addCallbacks(afterGetDefaultWorld, self._joinWorldFailedErrback)
        elif mode == "distributed":
            # Find out which WS has the default world and join any of them.
            self.otherThings()

    def joinWorldServer(self, wsID):
        """
        Joins a World Server given its ID.
        """
        pass

    def leaveWorldServer(self):
        """
        Leaves the current worldServer.
        """
        self.getFactory("WorldServerCommServerFactory").leaveWorldServer(self)