Exemple #1
0
    def __init__(self):
        super().__init__(prompt=">> ")

        self._db = None
        self._game = None
        self._gameGenerating = False
        self._deviceManager = NetworkManager()
        self._deviceManager.loadConfiguration()

        self._DefinedTypes = {}
        self._objIdToBrain = {}

        newgameCommandHandler = Command(
            "newgame", "Create a new game (erase any existing game data!)",
            self._newGameCommand)

        objectCommandHandler = Command("gameobj",
                                       "Game Object Control",
                                       self._objControl,
                                       mode=Command.SUBCMD_MODE)
        objectCreateSubcommmandHandler = Command(
            "create",
            "Create a new game object. Args: x, y, object_type, *object_args",
            self._newGameObjectCommand)
        objectListSubcommandHandler = Command(
            "list", "List all objects along with ids",
            self._listGameObjectsCommand)
        objectDestroySubcommandHandler = Command(
            "destroy", "Destroy an object by ID",
            self._destroyGameObjectCommand)
        objectMoveSubcommandHandler = Command(
            "move", "Move an object by ID. Args: object_id, new_x, new_y",
            self._moveGameObjectCommand)
        objectResetSubcommandHandler = Command(
            "reset",
            "Reset a brain controlled object. Args: object_id, *restart_args",
            self._resetBrainObjectCommand)
        objectRestartSubcommandHandler = Command(
            "restart", "Restart a brain controlled object by ID",
            self._restartBrainObjectCommand)

        objectCommandHandler.configureSubcommand(
            objectCreateSubcommmandHandler)
        objectCommandHandler.configureSubcommand(objectListSubcommandHandler)
        objectCommandHandler.configureSubcommand(
            objectDestroySubcommandHandler)
        objectCommandHandler.configureSubcommand(objectMoveSubcommandHandler)
        objectCommandHandler.configureSubcommand(objectResetSubcommandHandler)
        objectCommandHandler.configureSubcommand(
            objectRestartSubcommandHandler)

        printmapCommandHandler = Command(
            "printmap", "Print a text map of the whole board",
            self._printMapCommand)

        self.registerCommand(newgameCommandHandler)
        self.registerCommand(objectCommandHandler)
        self.registerCommand(printmapCommandHandler)
        self._reloadConfiguration()
Exemple #2
0
class GameConsole(CLIShell):
    def __init__(self):
        super().__init__(prompt=">> ")

        self._db = None
        self._game = None
        self._gameGenerating = False
        self._deviceManager = NetworkManager()
        self._deviceManager.loadConfiguration()

        self._DefinedTypes = {}
        self._objIdToBrain = {}

        newgameCommandHandler = Command(
            "newgame", "Create a new game (erase any existing game data!)",
            self._newGameCommand)

        objectCommandHandler = Command("gameobj",
                                       "Game Object Control",
                                       self._objControl,
                                       mode=Command.SUBCMD_MODE)
        objectCreateSubcommmandHandler = Command(
            "create",
            "Create a new game object. Args: x, y, object_type, *object_args",
            self._newGameObjectCommand)
        objectListSubcommandHandler = Command(
            "list", "List all objects along with ids",
            self._listGameObjectsCommand)
        objectDestroySubcommandHandler = Command(
            "destroy", "Destroy an object by ID",
            self._destroyGameObjectCommand)
        objectMoveSubcommandHandler = Command(
            "move", "Move an object by ID. Args: object_id, new_x, new_y",
            self._moveGameObjectCommand)
        objectResetSubcommandHandler = Command(
            "reset",
            "Reset a brain controlled object. Args: object_id, *restart_args",
            self._resetBrainObjectCommand)
        objectRestartSubcommandHandler = Command(
            "restart", "Restart a brain controlled object by ID",
            self._restartBrainObjectCommand)

        objectCommandHandler.configureSubcommand(
            objectCreateSubcommmandHandler)
        objectCommandHandler.configureSubcommand(objectListSubcommandHandler)
        objectCommandHandler.configureSubcommand(
            objectDestroySubcommandHandler)
        objectCommandHandler.configureSubcommand(objectMoveSubcommandHandler)
        objectCommandHandler.configureSubcommand(objectResetSubcommandHandler)
        objectCommandHandler.configureSubcommand(
            objectRestartSubcommandHandler)

        printmapCommandHandler = Command(
            "printmap", "Print a text map of the whole board",
            self._printMapCommand)

        self.registerCommand(newgameCommandHandler)
        self.registerCommand(objectCommandHandler)
        self.registerCommand(printmapCommandHandler)
        self._reloadConfiguration()

    def _reloadConfiguration(self):
        if self._gameGenerating:
            raise Exception(
                "Cannot reload config until game generation is complete")
        self._gamepath = os.path.join(
            Configure.CurrentPath(),
            "cyberwar_edu")  # .playground/cyberwar_edu
        self._objectTypesFile = os.path.join(self._gamepath,
                                             "object_types.ini")
        self._templatesPath = os.path.join(self._gamepath, "templates")
        self._brainTemplatesPath = os.path.join(self._templatesPath, "brains")
        self._brainsPath = os.path.join(self._gamepath, "brains")

        switchHost, switchPort = self._deviceManager.getDevice(
            "gameswitch").tcpLocation()
        self._brainMaker = BrainMaker(self._brainsPath, switchHost, switchPort)
        self._dbFile = os.path.join(self._gamepath, "board.db")
        loadGame = os.path.exists(self._dbFile)
        self._db = sqlite3.connect(self._dbFile, isolation_level=None)
        self._objectStore = None
        #self._db.execute("PRAGMA synchronous = OFF")
        #self._db.execute("PRAGMA journal_mode = OFF")
        if loadGame:
            try:
                self._loadGame()
            except Exception as e:
                print("Could not load game", e)
                self._game = None

        not os.path.exists(self._gamepath) and os.mkdir(self._gamepath)
        not os.path.exists(self._templatesPath) and os.mkdir(
            self._templatesPath)
        not os.path.exists(self._brainTemplatesPath) and os.mkdir(
            self._brainTemplatesPath)
        not os.path.exists(self._brainsPath) and os.mkdir(self._brainsPath)

        self._playerObjectTypes = configparser.ConfigParser()
        if os.path.exists(self._objectTypesFile):
            self._playerObjectTypes.read(self._objectTypesFile)

        self._initialObjects = configparser.ConfigParser()

    def saveGame(self):
        # Two stage save. First, we commit objects to the dabase
        self._objectStore and self._objectStore.commit()
        # then we commit the database to file
        self._db and self._db.commit()

    def autosave(self):
        self.saveGame()
        asyncio.get_event_loop().call_later(30.0, self.autosave)

    def _loadGame(self):
        if self._gameGenerating:
            raise Exception(
                "Cannot reload config until game generation is complete")
        for loader in Loaders:
            loader.InitializeDatabase(self._db)

        store = ObjectStore(self._db)
        store.registerLoader(BrainObjectLoader.OBJECT_TYPE,
                             BrainObjectLoader())
        store.registerLoader(TerrainLoader.OBJECT_TYPE, TerrainLoader())
        store.initialize()
        self._objectStore = store

        self._game = BrainControlLayer(
            ControlPlaneLayer(TerrainLayer(Board(self._db, store))))

        self._game.send(StartGameRequest("game"))

    def _newGame(self, maxX, maxY):
        if self._gameGenerating:
            raise Exception(
                "Cannot reload config until game generation is complete")
        if os.path.exists(self._dbFile):
            print("Deleting old database")
            self._db.close()
            os.unlink(self._dbFile)
            print("Still exists?", os.path.exists(self._dbFile))
            self._db = sqlite3.connect(self._dbFile)
        Board.NewBoard(self._db, maxX, maxY)

        self._loadGame()

        initAlgorithm = SimpleTerrainInitialization(water=.6)
        initRequest = InitializeGameTerrainRequest("game", initAlgorithm)

        start = time.time()
        r = self._game.send(initRequest)
        if not r:
            raise Exception(r.Value)
        end = time.time()
        print("init in {} seconds".format(end - start))
        """
        
        coro = asyncio.get_event_loop().run_in_executor(None, self._game.send, initRequest)
        f = asyncio.ensure_future(coro)
        f.add_done_callback(self._newGameReady)
        self._gameGenerating = True
        
    def _newGameReady(self, result):
        self._gameGenerating = False
        r = result.result()
        if not r:
            # don't have a 'writer' fall back to transport
            self.transport.write("Could not create terrain. {}".format(r.Value))
            return
        self._
 = True
        self.transport.write("Game loaded")"""

    def _getObjectTypeAttributes(self, objectType):
        if objectType not in self._playerObjectTypes:
            raise Exception("No such type {}".format(objectType))
        typeSection = self._playerObjectTypes[objectType]
        attributes = []
        if "attributes" in typeSection:
            try:
                attributes = [
                    AttributeConstructor[attrName](typeSection)
                    for attrName in typeSection["attributes"].split("\n")
                ]
            except Exception as e:
                raise Exception("Misconfigured type. {}".format(e))

        for attr in attributes:
            # special handling section

            # handle botbuilder... requires a brain maker and design types
            if isinstance(attr, BotBuilder):
                attr.configureBrainMaker(self._brainMaker)
                for objectType in self._playerObjectTypes:
                    if objectType == "city": continue
                    attr.loadDesign(objectType,
                                    self._getObjectTypeAttributes(objectType))
        return attributes

    def _getBrain(self, brainType, **kargs):
        brainFileName = "{}.py".format(brainType)
        brainFQFileName = os.path.join(self._brainTemplatesPath, brainFileName)
        print(brainFQFileName)
        if not os.path.exists(brainFQFileName):
            raise Exception("No Such Brain {}".format(brainType))
        with open(brainFQFileName, "r") as f:
            code = ""
            templateLine = False
            for line in f.readlines():
                if line.strip().startswith("#%") and "TEMPLATE-ON" in line:
                    templateLine = True
                elif line.strip().startswith("#%") and "TEMPLATE-OFF" in line:
                    templateLine = False
                elif templateLine:
                    code += line.format(**kargs)
                else:
                    code += line
            return code

    def _initializeBrain(self, brainPath, brainType, **kargs):
        brainCode = self._getBrain(brainType, **kargs)
        print("got brainCode")
        if os.path.exists(brainPath):
            raise Exception("Path already exists")
        os.mkdir(brainPath)

        for requiredFile in BRAIN_REQUIRED_FILES:
            requiredFQFile = os.path.join(self._brainTemplatesPath,
                                          requiredFile)
            if not os.path.exists(requiredFQFile):
                raise Exception(
                    "Invalid installation. File {} not present.".format(
                        requiredFile))
            shutil.copy(requiredFQFile, brainPath)
        with open(os.path.join(brainPath, "brain.py"), "w+") as f:
            f.write(brainCode)
        ppath = os.path.join(brainPath, ".playground")
        os.mkdir(ppath)

        kargs["switch_host"], kargs[
            "switch_port"] = self._deviceManager.getDevice(
                "gameswitch").tcpLocation()
        with open(os.path.join(ppath, "networking.ini"), "w+") as f:
            f.write(brain_pnetworking_template.format(**kargs))
        os.mkdir(os.path.join(ppath, "connectors"))

    def _createPlayerObject(self, startX, startY, objectType, brainType,
                            *kargsList):
        kargs = {}
        for argpair in kargsList:
            print(argpair)
            try:
                k, v = argpair.split("=")
                kargs[k] = v
            except Exception as e:
                raise Exception(
                    "Cannot create object. Requires a list of k=v pairs to brain template. Error={}"
                    .format(e))
        brainPath = os.path.join(self._brainsPath, str(time.time()))
        print("brain path", brainPath)
        self._initializeBrain(brainPath, brainType, **kargs)

        # TODO: eventually, figure out how to use initializeBrain. But requires a zip file...
        #brainPath = self._brainMaker.initializeBrain("console_"+objectType,
        #                                             kargs["address"],
        #                                             brainType,
        #                                             **kargs)

        print("get attributes")
        attributes = self._getObjectTypeAttributes(objectType)
        print("got", attributes)
        r = self._game.send(
            CreateBrainControlledObjectRequest("game", brainPath, *attributes))
        if not r:
            raise Exception(r.Value)
        newObject = r.Value
        #self._objIdToBrain[newObject.numericIdentifier()] = brainPath

        r = self._game.send(PutRequest("game", startX, startY, newObject))
        if not r:
            raise Exception(r.Value)

    def _objControl(self, writer, *args):
        writer("Error. No sub command")

    def _newGameObjectCommand(self, writer, x, y, objectType, *objectArgs):
        if objectType in self._playerObjectTypes:
            return self._newPlayerObjectCommand(writer, x, y, objectType,
                                                objectArgs[0], *objectArgs[1:])
        # TODO: Eventually, can have NPC's and other control plane objects.
        # But for now, only have brain controlled stuff.
        writer("Unknown object type {}\n".format(objectType))

    def _newPlayerObjectCommand(self, writer, x, y, objectType, brainType,
                                *brainArgs):
        if not self._game:
            writer("Cannot create object until game starts.\n\n")
            return
        x, y = int(x), int(y)
        try:
            self._createPlayerObject(x, y, objectType, brainType, *brainArgs)
            writer("{} object created at {}\n\n.".format(objectType, (x, y)))
        except Exception as e:
            writer("{} could not be created. {}\n\n".format(objectType, e))

    def _listGameObjectsCommand(self, writer):
        for cpObject in self._objectStore:
            if not isinstance(cpObject, ControlPlaneObject): continue
            objId = cpObject.gameId()
            locateResponse = self._game.send(LocateRequest("game", cpObject))
            if not locateResponse:
                continue
            attrString = ", ".join([str(a) for a in cpObject.getAttributes()])
            writer("{}: {} at {}. Attributes = {}\n".format(
                objId, cpObject.identifier(), locateResponse.Value,
                attrString))
        writer("\n")

    """def _resetBrainCommand(self, writer, objectId, brainType, *brainArgs):
        objectId = int(objectId)
        if not objectId in self._objIdToBrain:
            writer("No such object with ID {}\n\n".format(objectId))
            return
        if not os.path.exists(self._objIdToBrain[objectId]):
            writer("No brain exists for ID {} anymore\n\n".format(objectId))
            return"""

    def _newGameCommand(self, writer, x, y):
        x, y = int(x), int(y)
        if self._game:
            yesno = input(
                "WARNING: This will over-write the current game! Are you sure [y/N]? "
            )
            if yesno.lower().strip()[0] != 'y':
                writer("New game operation cancelled.\n\n")
                return
            self._game.cleanup()
        try:
            self._newGame(x, y)
            writer("Game created.\n\n")
        except Exception as e:
            writer("Could not create new game. {}\n\n".format(e))

    def _printMapCommand(self, writer):
        if not self._game:
            writer("No map. Game not started.\n\n")
            return
        dimensionsResult = self._game.send(DimensionsRequest("game"))
        maxX, maxY = dimensionsResult.Value
        s = ""
        line = ""
        for y in range(0, maxY):
            for x in range(0, maxX):
                contentsResult = self._game.send(ContentsRequest("game", x, y))
                contents = contentsResult.Value
                symbol = "X"
                terrainType = None
                otherObj = None
                for obj in contents:
                    if isinstance(obj, Land): terrainType = Land
                    elif isinstance(obj, Water): terrainType = Water
                    elif isinstance(obj, ControlPlaneObject): otherObj = obj
                if otherObj is not None:
                    symbol = "O"
                elif terrainType == Land:
                    symbol = "#"
                elif terrainType == Water:
                    symbol = "="
                line += symbol
            s = line + "\n" + s
            line = ""
        writer(s + "\n")

    def _moveGameObjectCommand(self, writer, objectId, x, y):
        objectId = int(objectId)
        gameObject = self._objectStore.getIngameObject(objectId)
        if not gameObject:
            writer("Unknown object {}\n\n".format(objectId))
            return
        x, y = int(x), int(y)

        removeResponse = self._game.send(RemoveRequest("game", gameObject))
        if not removeResponse:
            writer("Could not remove {} from current location.\n\n".format(
                gameObject.identifier()))
            return

        putResponse = self._game.send(PutRequest("game", x, y, gameObject))
        if not putResponse:
            writer("Could not move {} to {}\n\n".format(
                gameObject.identifier(), (x, y)))
            return

        writer("{} moved to {}\n\n".format(gameObject.identifier(), (x, y)))

    def _resetBrainObjectCommand(self, writer, objectId, brainType,
                                 *brainArgs):
        objectId = int(objectId)
        gameObject = self._objectStore.getIngameObject(objectId)
        if not gameObject:
            writer("Unknown object {}\n\n".format(objectId))
            return

        brainAttr = gameObject.getAttribute(BrainEnabled)
        if not brainAttr:
            writer("{} does not have a brain.\n\n".format(
                gameObject.identifier()))
            return

        kargs = {}
        for argpair in brainArgs:
            try:
                k, v = argpair.split("=")
                kargs[k] = v
            except Exception as e:
                raise Exception(
                    "Cannot create object. Requires a list of k=v pairs to brain template. Error={}"
                    .format(e))

        writer("Rewriting {}'s brain\n".format(gameObject.identifier()))
        writer("\tStop brain.\n")
        brainAttr.stop()
        writer("\tDelete original brain {}\n".format(brainAttr.brainPath()))
        shutil.rmtree(brainAttr.brainPath())
        writer("\tRecreate brain as {} - {}\n".format(brainType, kargs))
        self._initializeBrain(brainAttr.brainPath(), brainType, **kargs)
        asyncio.get_event_loop().call_later(2.0, brainAttr.start)
        writer("{}'s brain reset. Will restart in 2.0 seconds.\n\n".format(
            gameObject.identifier()))

    def _restartBrainObjectCommand(self, writer, objectId, *restartArgs):
        objectId = int(objectId)
        gameObject = self._objectStore.getIngameObject(objId)
        if not gameObject:
            writer("Unknown object {}\n\n".format(objectId))
            return

        brainAttr = gameObject.getAttribute(BrainEnabled)
        if not brainAttr:
            writer("{} does not have a brain.\n\n".format(
                gameObject.identifier()))
            return

        brainAttr.stop()
        asyncio.get_event_loop().call_later(2.0, brainAttr.start)
        writer(
            "{}'s brain turned off. Will restart in 2.0 seconds.\n\n".format(
                gameObject.identifier()))

    def _destroyGameObjectCommand(self, writer, objectId):
        objectId = int(objectId)
        gameObject = self._objectStore.getIngameObject(objectId)
        if not gameObject:
            writer("Unknown object {}\n\n".format(objectId))
            return

        releaseResult = self._game.send(
            ReleaseObjectRequest("game", gameObject))
        if not releaseResult:
            writer("Could not release object. Reason {}\n\n".format(
                releaseResult.Value))
            return
        writer("Object destroyed\n\n")

    def start(self):
        loop = asyncio.get_event_loop()
        self.registerExitListener(
            lambda reason: loop.call_later(1.0, loop.stop))
        AdvancedStdio(self)

    def stop(self):
        try:
            print("calling save")
            self.saveGame()
            print("save done")
        except Exception as e:
            print("had exception", e)
            pass
        if self._game:
            print("game cleanup")
            self._game.cleanup()