Esempio n. 1
0
    def testWaypointExtension(self):
        """
    Tests how we can use waypoint extension to move a couple of units
    along a shared path with just an initial specific segment.
    """

        self.mainLogger.info("Testing convoy movement through wpx...")

        # Set up three test characters and a shared initial waypoint.  The
        # characters need custom paths to go to the initial waypoint.
        self.generate(1)
        initialWp = self.offset
        self.moveCharactersTo({
            "domob":
            offsetCoord({
                "x": 10,
                "y": -3
            }, initialWp, False),
            "domob 2":
            offsetCoord({
                "x": 5,
                "y": 2
            }, initialWp, False),
            "domob 3":
            offsetCoord({
                "x": -1,
                "y": 8
            }, initialWp, False),
        })
        names = ["domob", "domob 2", "domob 3"]

        # Build up a single move that sends them to a target far away,
        # but sharing most of the path among them.
        target = offsetCoord({"x": -1_234, "y": 570}, self.offset, False)
        ops = []
        ids = []
        for nm in names:
            c = self.getCharacters()[nm]
            ids.append(c.getId())
            ops.append({
                "id": c.getId(),
                "wp": c.findPath(initialWp),
            })
        path = self.rpc.game.findpath(source=initialWp,
                                      target=target,
                                      faction="g",
                                      l1range=2_000,
                                      exbuildings=[])
        ops.append({
            "id": ids,
            "wpx": path["encoded"],
        })
        self.sendMove("domob", {"c": ops})

        # Let them move there and check the expected outcome (they arrive
        # all there, stacking on top of each other).
        self.generate(500)
        for nm in names:
            self.assertEqual(self.getCharacters()[nm].getPosition(), target)
Esempio n. 2
0
    def run(self):
        self.collectPremine()

        self.mainLogger.info("Creating test characters...")
        self.initAccount("target", "b")
        self.createCharacters("target")
        self.initAccount("attacker", "r")
        self.createCharacters("attacker", 2)
        self.generate(1)
        self.changeCharacterVehicle("target", "light attacker")
        self.changeCharacterVehicle("attacker", "light attacker")
        self.changeCharacterVehicle("attacker 2", "light attacker")

        # We use a known good position as offset and move the characters
        # nearby so they are attacking each other.
        self.offset = {"x": -1100, "y": 1042}
        self.moveCharactersTo({
            "target":
            self.offset,
            "attacker":
            offsetCoord({
                "x": -5,
                "y": 0
            }, self.offset, False),
            "attacker 2":
            offsetCoord({
                "x": 5,
                "y": 0
            }, self.offset, False),
        })

        # Check state after exactly one round of attacks.
        self.mainLogger.info("Attacking and testing damage lists...")
        self.generate(1)
        self.expectAttackers("target", ["attacker", "attacker 2"])
        if len(self.getAttackers("attacker")) > 0:
            self.expectAttackers("attacker", ["target"])
            self.expectAttackers("attacker 2", [])
        else:
            self.expectAttackers("attacker", [])
            self.expectAttackers("attacker 2", ["target"])

        # Move the target out of range and verify timeout of the damage list.
        # Note that the block generated during moveCharactersTo still performs
        # an attack before processing the move, so that the damage list entries
        # are refreshed.
        self.mainLogger.info("Letting damage list time out...")
        self.moveCharactersTo({
            "target":
            offsetCoord({
                "x": -100,
                "y": 0
            }, self.offset, False),
        })
        self.generate(99)
        self.expectAttackers("target", ["attacker", "attacker 2"])
        self.generate(1)
        self.expectAttackers("target", [])
Esempio n. 3
0
    def run(self):
        self.collectPremine()

        numAttackers = 5

        self.mainLogger.info("Creating test characters...")
        self.initAccount("target", "b")
        self.createCharacters("target")
        self.initAccount("attacker", "r")
        self.createCharacters("attacker", 2)
        self.generate(1)
        self.changeCharacterVehicle("attacker", "light attacker")

        # We use a known good position as offset for our test.
        self.offset = {"x": -1100, "y": 1042}
        self.inRange = offsetCoord({"x": 0, "y": 0}, self.offset, False)
        outOfRange = offsetCoord({"x": 0, "y": 20}, self.offset, False)
        self.moveCharactersTo({
            "attacker":
            offsetCoord({
                "x": 0,
                "y": 1
            }, self.offset, False),
            "attacker 2":
            offsetCoord({
                "x": 1,
                "y": 0
            }, self.offset, False),
        })
        self.getTargetHP()

        self.mainLogger.info("Taking some damage...")
        self.moveCharactersTo({"target": self.inRange})
        self.setCharactersHP({"target": {"ma": 1000, "a": 1000, "s": 2}})
        self.generate(3)
        hp, maxHP = self.getTargetHP()
        assert (hp is not None) and (maxHP is not None)
        assert hp["armour"] < maxHP["armour"]
        assert hp["shield"] < 2

        self.restoreBlock = self.rpc.xaya.getbestblockhash()

        self.mainLogger.info("Regenerating shield...")
        self.moveCharactersTo({"target": outOfRange})
        self.generate(60)
        hp, maxHP = self.getTargetHP()
        assert (hp is not None) and (maxHP is not None)
        assert hp["armour"] < maxHP["armour"]
        self.assertEqual(hp["shield"], maxHP["shield"])

        self.mainLogger.info("Killing character...")
        self.moveCharactersTo({"target": self.inRange})
        self.setCharactersHP({"target": {"a": 1, "s": 0}})
        self.generate(5)
        hp, maxHP = self.getTargetHP()
        assert (hp is None) and (maxHP is None)

        self.testReorg()
Esempio n. 4
0
    def testBlockingBuilding(self):
        """
    Tests how a new building can block the movement when it is placed
    into the path.
    """

        self.mainLogger.info("Testing blocking the path...")

        self.moveCharactersTo({
            "domob":
            offsetCoord({
                "x": 50,
                "y": 0
            }, self.offset, False),
        })
        self.build("huesli",
                   None,
                   offsetCoord({
                       "x": 30,
                       "y": 0
                   }, self.offset, False),
                   rot=0)

        # Set waypoints across a blocked path.
        self.setWaypoints("domob", [{"x": 0, "y": 0}])
        self.generate(10)

        # The character should be blocked by the obstacle.
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 31, "y": 0})
        assert mv["blockedturns"] > 0

        # Let movement stop completely.
        self.generate(10 + self.roConfig().params.blocked_step_retries)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 31, "y": 0})
        self.assertEqual(mv, None)

        # Move around the obstacle.
        self.setWaypoints("domob", [
            {
                "x": 31,
                "y": 1
            },
            {
                "x": 0,
                "y": 1
            },
            {
                "x": 0,
                "y": 0
            },
        ])
        self.generate(100)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 0, "y": 0})
        self.assertEqual(mv, None)
Esempio n. 5
0
    def moveTowards(self, owner, target):
        """
    Moves the character of the given owner towards the given target (offset
    by self.offset), using findpath rather than direct waypoints.
    """

        c = self.getCharacters()[owner]
        return c.moveTowards(offsetCoord(target, self.offset, False))
Esempio n. 6
0
def relativePos(x, y):
    """
  Returns a coordinate offset by the given (x, y) relative to a test
  starter zone's centre.  The zone's radius is 10.
  """

    centre = {"x": -2042, "y": 100}
    return offsetCoord(centre, {"x": x, "y": y}, False)
Esempio n. 7
0
    def testChosenSpeed(self):
        self.mainLogger.info("Testing chosen speed...")

        self.moveCharactersTo({
            "domob":
            offsetCoord({
                "x": 0,
                "y": 0
            }, self.offset, False),
        })

        # Move the character with reduced speed.
        self.setWaypoints("domob", [{"x": 100, "y": 0}], speed=1000)
        self.generate(10)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 10, "y": 0})
        self.assertEqual(mv["chosenspeed"], 1000)

        # Adjust the speed to be higher than the natural speed of 2'000,
        # and expect movement with the natural speed.
        self.getCharacters()["domob"].sendMove({"speed": 10000})
        self.generate(10)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 40, "y": 0})
        self.assertEqual(mv["chosenspeed"], 10000)

        # Sending another movement in-between without speed will revert it to
        # the default one.
        self.setWaypoints("domob", [{"x": 100, "y": 0}], speed=1000)
        self.generate(10)
        pos, _ = self.getMovement("domob")
        self.assertEqual(pos, {"x": 50, "y": 0})
        self.setWaypoints("domob", [{"x": 0, "y": 0}])
        self.generate(10)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 20, "y": 0})
        assert "chosenspeed" not in mv

        # Letting the movement finish and then sending a new movement will also
        # revert to intrinsic speed.
        self.setWaypoints("domob", [{"x": 100, "y": 0}], speed=1000)
        self.generate(10)
        pos, _ = self.getMovement("domob")
        self.assertEqual(pos, {"x": 30, "y": 0})
        self.generate(100)
        pos, _ = self.getMovement("domob")
        self.assertEqual(pos, {"x": 100, "y": 0})
        self.setWaypoints("domob", [{"x": 0, "y": 0}])
        self.generate(10)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 70, "y": 0})
        assert "chosenspeed" not in mv

        # Stop the character to avoid confusing later tests.
        self.setWaypoints("domob", [])
        self.generate(1)
Esempio n. 8
0
    def setWaypoints(self, owner, wp):
        """
    Sends a move to update the waypoints of the character with the given owner.
    """

        c = self.getCharacters()[owner]
        offset = [offsetCoord(p, self.offset, False) for p in wp]

        encoded = self.rpc.game.encodewaypoints(wp=offset)

        return c.sendMove({"wp": encoded})
Esempio n. 9
0
    def run(self):
        self.collectPremine()

        self.mainLogger.info("Creating test character...")
        self.initAccount("domob", "r")
        self.createCharacters("domob")
        self.generate(1)

        # Start off from a known good location to make sure all is fine and
        # not flaky depending on the randomised spawn position.
        self.offset = {"x": -1377, "y": 1263}
        self.moveCharactersTo({"domob": self.offset})

        self.mainLogger.info("Multiple movement commands in a block...")
        c = self.getCharacters()["domob"]
        c.moveTowards(offsetCoord({"x": 10, "y": 0}, self.offset, False))
        c.moveTowards(offsetCoord({"x": 0, "y": 10}, self.offset, False))
        self.generate(1)
        c = self.getCharacters()["domob"]
        expected = {"x": 0, "y": c.getSpeed() // 1000}
        self.assertEqual(offsetCoord(c.getPosition(), self.offset, True),
                         expected)
Esempio n. 10
0
    def getMovement(self, owner):
        """
    Retrieves the movement structure of the given character from the current
    game state (and None if the character is not moving).  Returns a pair
    of (position, movement).
    """

        c = self.getCharacters()[owner]
        pos = offsetCoord(c.getPosition(), self.offset, True)

        if c.isMoving():
            return pos, c.data["movement"]

        return pos, None
Esempio n. 11
0
    def testDynObstacles(self):
        """
    Tests pending "found building" moves, which in particular also
    verifies the DynObstacles instance used for pending moves.
    """

        self.mainLogger.info("Testing dynamic obstacles...")

        pos1 = {"x": 100, "y": 0}
        pos2 = offsetCoord(pos1, {"x": -1, "y": 0}, False)

        self.moveCharactersTo({
            "domob": pos1,
            "andy": pos2,
        })
        self.dropLoot(pos1, {"foo": 10})
        self.dropLoot(pos2, {"foo": 10})
        c = self.getCharacters()
        c["domob"].sendMove({"pu": {"f": {"foo": 100}}})
        c["andy"].sendMove({"pu": {"f": {"foo": 100}}})
        self.generate(1)

        # domob's huesli can be built, while andy's checkmark would overlap
        # with the dynamic obstacle presented by the domob character.
        c = self.getCharacters()
        c["domob"].sendMove({"fb": {"t": "huesli", "rot": 3}})
        c["andy"].sendMove({"fb": {"t": "checkmark", "rot": 0}})
        self.assertEqual(
            self.getPendingState(), {
                "characters": [{
                    "id": c["domob"].getId(),
                    "foundbuilding": {
                        "type": "huesli",
                        "rotationsteps": 3,
                    },
                    "pickup": False,
                    "drop": False,
                }],
                "buildings": [],
                "newcharacters": [],
                "accounts": [],
            })

        # Make sure nothing sticks around for later tests.
        self.generate(1)
Esempio n. 12
0
    def testMobileRefinery(self, bId):
        self.mainLogger.info("Testing mobile refinery...")

        self.initAccount("andy", "g")
        self.generate(1)
        # Due to the airdrop of vCHI, the new account will have 1000 coins
        # before we do the operation.
        self.dropIntoBuilding(bId, "andy", {"test ore": 6})

        self.createCharacters("andy")
        self.generate(1)
        self.changeCharacterVehicle("andy", "basetank", ["vhf refinery"])

        # We test refining with the mobile refinery inside a building, which
        # should still work (although it may not make too much sense in this
        # situation).
        b = self.getBuildings()[bId]
        self.moveCharactersTo({
            "andy":
            offsetCoord(b.getCentre(), {
                "x": -30,
                "y": 0
            }, False),
        })
        self.getCharacters()["andy"].sendMove({"eb": bId})
        self.generate(1)
        c = self.getCharacters()["andy"]
        self.assertEqual(c.getBuildingId(), bId)

        c.sendMove({"pu": {"f": {"test ore": 6}}})
        self.generate(1)
        self.getCharacters()["andy"].sendMove(
            {"ref": {
                "i": "test ore",
                "n": 6
            }})
        self.generate(1)

        self.assertEqual(self.getAccounts()["andy"].getBalance(), 990)
        self.assertEqual(self.getCharacters()["andy"].getFungibleInventory(), {
            "bar": 2,
            "zerospace": 1,
        })
Esempio n. 13
0
    def run(self):
        self.collectPremine()

        # Some well-defined position that we use, which also reflects the
        # region that will be prospected.  We use a different position and
        # region for mining.
        positionProspect = {"x": 0, "y": 0}
        regionProspect = self.rpc.game.getregionat(
            coord=positionProspect)["id"]
        positionMining = {"x": 100, "y": -100}
        regionMining = self.rpc.game.getregionat(coord=positionMining)["id"]

        positionBuilding = {"x": 200, "y": -500}

        self.mainLogger.info("Creating test characters...")
        self.initAccount("andy", "b")
        self.initAccount("domob", "r")
        self.initAccount("miner", "g")
        self.initAccount("inbuilding", "b")
        self.createCharacters("domob")
        self.createCharacters("miner")
        self.createCharacters("inbuilding", 2)
        self.generate(1)

        self.giftCoins({"domob": 100})
        self.giftCoins({"andy": 100})
        self.moveCharactersTo({
            "domob":
            positionProspect,
            "miner":
            positionMining,
            "inbuilding":
            offsetCoord(positionBuilding, {
                "x": 10,
                "y": 0
            }, False),
            "inbuilding 2":
            offsetCoord(positionBuilding, {
                "x": -10,
                "y": 0
            }, False),
        })

        self.build("b cc", "inbuilding", positionBuilding, 0)
        building = list(self.getBuildings().keys())[-1]
        self.dropIntoBuilding(building, "andy", {"foo": 100, "test ore": 10})
        self.getCharacters()["inbuilding"].sendMove({"eb": building})

        self.getCharacters()["miner"].sendMove({"prospect": {}})

        self.generate(15)
        self.syncGame()
        self.assertEqual(
            self.getPendingState(), {
                "buildings": [],
                "characters": [],
                "newcharacters": [],
                "accounts": [],
            })

        self.mainLogger.info("Performing pending updates...")
        self.createCharacters("domob")
        c1 = self.getCharacters()["domob"]
        c1.sendMove({"wp": None})

        sleepSome()
        self.assertEqual(
            self.getPendingState(), {
                "characters": [
                    {
                        "id": c1.getId(),
                        "waypoints": [],
                        "drop": False,
                        "pickup": False,
                    },
                ],
                "newcharacters": [
                    {
                        "name": "domob",
                        "creations": [{
                            "faction": "r"
                        }]
                    },
                ],
                "buildings": [],
                "accounts": [],
            })

        self.createCharacters("domob")
        self.createCharacters("andy")
        c1.sendMove(
            {"wp": self.rpc.game.encodewaypoints(wp=[{
                "x": 5,
                "y": -5
            }])})
        c1.sendMove({"pu": {"f": {"foo": 2}}})

        cb1 = self.getCharacters()["inbuilding"]
        cb1.sendMove({"xb": {}})
        cb2 = self.getCharacters()["inbuilding 2"]
        cb2.sendMove({"eb": building})

        sleepSome()
        self.assertEqual(
            self.getPendingState(), {
                "characters": [
                    {
                        "id": c1.getId(),
                        "waypoints": [{
                            "x": 5,
                            "y": -5
                        }],
                        "drop": False,
                        "pickup": True,
                    },
                    {
                        "id": cb1.getId(),
                        "exitbuilding": {
                            "building": building
                        },
                        "pickup": False,
                        "drop": False,
                    },
                    {
                        "id": cb2.getId(),
                        "enterbuilding": building,
                        "pickup": False,
                        "drop": False,
                    },
                ],
                "newcharacters": [
                    {
                        "name": "andy",
                        "creations": [{
                            "faction": "b"
                        }]
                    },
                    {
                        "name": "domob",
                        "creations": [{
                            "faction": "r"
                        }] * 2
                    },
                ],
                "buildings": [],
                "accounts": [],
            })

        c1.sendMove({"prospect": {}})
        c1.sendMove({"drop": {"f": {"foo": 2}}})
        c2 = self.getCharacters()["miner"]
        c2.sendMove({"mine": {}})
        self.getCharacters()["inbuilding 2"].sendMove({"eb": None})

        self.sendMove("domob", {
            "vc": {
                "b": 10,
                "t": {
                    "miner": 20
                },
                "m": {}
            },
        },
                      burn=0.01)
        self.sendMove(
            "andy",
            {
                "s": [{
                    "b": building,
                    "t": "ref",
                    "i": "test ore",
                    "n": 9
                }],
                "x": [
                    # The first one is invalid (insufficient balance).
                    {
                        "b": building,
                        "i": "foo",
                        "n": 1_000,
                        "bp": 10
                    },
                    {
                        "b": building,
                        "i": "foo",
                        "n": 1,
                        "bp": 0
                    },
                ],
            })

        self.getBuildings()[building].sendMove({"sf": 3})

        sleepSome()
        oldPending = self.getPendingState()
        self.assertEqual(
            oldPending, {
                "buildings": [
                    {
                        "id": building,
                        "newconfig": {
                            "servicefee": 3
                        },
                    },
                ],
                "characters": [
                    {
                        "id": c1.getId(),
                        "drop": True,
                        "pickup": True,
                        "prospecting": regionProspect,
                    },
                    {
                        "id": c2.getId(),
                        "drop": False,
                        "pickup": False,
                        "mining": regionMining,
                    },
                    {
                        "id": cb1.getId(),
                        "exitbuilding": {
                            "building": building
                        },
                        "pickup": False,
                        "drop": False,
                    },
                    {
                        "id": cb2.getId(),
                        "enterbuilding": None,
                        "pickup": False,
                        "drop": False,
                    },
                ],
                "newcharacters": [
                    {
                        "name": "andy",
                        "creations": [{
                            "faction": "b"
                        }]
                    },
                    {
                        "name": "domob",
                        "creations": [{
                            "faction": "r"
                        }, {
                            "faction": "r"
                        }]
                    },
                ],
                "accounts": [
                    {
                        "name":
                        "andy",
                        "serviceops": [{
                            "building": building,
                            "type": "refining",
                            "cost": {
                                "base": 30,
                                "fee": 0
                            },
                            "input": {
                                "test ore": 9
                            },
                            "output": {
                                "bar": 6,
                                "zerospace": 3
                            },
                        }],
                        "dexops": [
                            {
                                "op": "bid",
                                "building": building,
                                "item": "foo",
                                "num": 1,
                                "price": 0,
                            },
                        ],
                    },
                    {
                        "name": "domob",
                        "coinops": {
                            "minted": 100,
                            "burnt": 10,
                            "transfers": {
                                "miner": 20
                            }
                        },
                    },
                ],
            })

        self.mainLogger.info("Confirming the moves...")
        self.generate(1)
        self.syncGame()
        self.assertEqual(
            self.getPendingState(), {
                "buildings": [],
                "characters": [],
                "newcharacters": [],
                "accounts": [],
            })

        self.mainLogger.info("Unconfirming the moves...")
        blk = self.rpc.xaya.getbestblockhash()
        self.rpc.xaya.invalidateblock(blk)
        sleepSome()
        self.assertEqual(self.getPendingState(), oldPending)
        self.generate(50)

        self.testDynObstacles()
Esempio n. 14
0
    def run(self):
        self.collectPremine()

        self.pos = [{"x": 10, "y": 100}]
        self.pos.append(offsetCoord(self.pos[0], {"x": 1, "y": 0}, False))
        self.assertEqual(
            self.getRegionAt(self.pos[0]).getId(),
            self.getRegionAt(self.pos[1]).getId())

        self.mainLogger.info("Prospecting a test region...")
        self.initAccount("domob", "r")
        self.createCharacters("domob", 2)
        self.generate(1)
        self.changeCharacterVehicle("domob", "light attacker")
        self.changeCharacterVehicle("domob 2", "light attacker")
        self.moveCharactersTo({
            "domob": self.pos[0],
            "domob 2": self.pos[1],
        })
        self.getCharacters()["domob"].sendMove({"prospect": {}})
        self.generate(10)
        self.assertEqual(self.getCharacters()["domob"].getBusy()["blocks"], 1)

        # We need at least some of the resource in the region in order to allow
        # the remaining parts of the test to work as expected.  Thus we try
        # to re-roll prospection as needed in order to achieve that.
        while True:
            self.generate(1)
            typ, self.amount = self.getRegionAt(self.pos[0]).getResource()
            self.log.info("Found %d of %s at the region" % (self.amount, typ))

            if self.amount > 10:
                break

            self.log.warning("Too little resources, retrying...")
            self.rpc.xaya.invalidateblock(self.rpc.xaya.getbestblockhash())

        # In case we found a prospecting prize, we need to remember this for
        # the reorg test.
        self.preReorgInv = self.getCharacters()["domob"].getFungibleInventory()

        self.generate(1)
        self.reorgBlock = self.rpc.xaya.getbestblockhash()

        self.mainLogger.info("Starting to mine...")
        self.getCharacters()["domob"].sendMove({"mine": {}})
        self.generate(1)
        self.assertEqual(self.isMining("domob"), True)
        self.assertEqual(self.isMining("domob 2"), False)

        self.mainLogger.info("Movement stops mining...")
        self.getCharacters()["domob"].sendMove({"wp": None})
        self.generate(1)
        self.assertEqual(self.isMining("domob"), False)
        self.assertEqual(self.isMining("domob 2"), False)

        self.mainLogger.info("Mining with two characters...")
        for c in self.getCharacters().values():
            c.sendMove({"mine": {}})
        self.generate(1)
        self.assertEqual(self.isMining("domob"), True)
        self.assertEqual(self.isMining("domob 2"), True)

        self.mainLogger.info("Using up all resources...")
        while True:
            # Make sure we have at least a somewhat long chain, so it will
            # be longer in the reorg test.
            self.generate(50)
            _, remaining = self.getRegionAt(self.pos[0]).getResource()
            if remaining == 0:
                break
            for c in self.getCharacters().values():
                c.sendMove({
                    "drop": {
                        "f": {
                            typ: 1000
                        }
                    },
                    "mine": {},
                })
        for c in self.getCharacters().values():
            c.sendMove({
                "drop": {
                    "f": {
                        typ: 1000
                    }
                },
            })
        self.generate(1)
        self.assertEqual(self.isMining("domob"), False)
        self.assertEqual(self.isMining("domob 2"), False)

        total = 0
        for loot in self.getRpc("getgroundloot"):
            inv = loot["inventory"]["fungible"]
            self.assertEqual(len(inv), 1)
            total += inv[typ]
        self.assertEqual(total, self.amount)

        self.testReorg()
Esempio n. 15
0
    def testConvoy(self):
        """
    Tests movement of multiple characters in a "convoy", with semantics
    after the unblock-spawns fork.
    """

        self.mainLogger.info("Testing convoy movement...")

        # Set up three test characters around a common centre, and then
        # send them to move with the same path.  They will "collidate" on the
        # initial step, but due to the slowdown on entering a coordinate with
        # another vehicle on it, should just split out into a convoy over time.
        self.createCharacters("domob", 2)
        self.generate(1)
        self.moveCharactersTo({
            "domob":
            offsetCoord({
                "x": 1,
                "y": -1
            }, self.offset, False),
            "domob 2":
            offsetCoord({
                "x": 1,
                "y": 0
            }, self.offset, False),
            "domob 3":
            offsetCoord({
                "x": 0,
                "y": 1
            }, self.offset, False),
        })

        wp = [{"x": 0, "y": 0}, {"x": -10, "y": 0}]
        self.setWaypoints("domob 3", wp, speed=1000)
        self.setWaypoints("domob 2", wp, speed=1000)
        self.setWaypoints("domob", wp, speed=1000)

        self.generate(1)
        self.expectPosition("domob", {"x": 0, "y": 0})
        self.expectPosition("domob 2", {"x": 1, "y": 0})
        self.expectPosition("domob 3", {"x": 0, "y": 1})

        self.generate(1)
        self.expectPosition("domob", {"x": -1, "y": 0})
        self.expectPosition("domob 2", {"x": 0, "y": 0})
        self.expectPosition("domob 3", {"x": 0, "y": 1})

        self.generate(1)
        self.expectPosition("domob", {"x": -2, "y": 0})
        self.expectPosition("domob 2", {"x": -1, "y": 0})
        self.expectPosition("domob 3", {"x": 0, "y": 0})

        self.generate(5)
        self.expectPosition("domob", {"x": -7, "y": 0})
        self.expectPosition("domob 2", {"x": -6, "y": 0})
        self.expectPosition("domob 3", {"x": -5, "y": 0})

        # Let them move onto the target tile and collect up there together.
        # Then move back off, which should again be as a convoy.
        self.generate(20)
        self.expectPosition("domob", {"x": -10, "y": 0})
        self.expectPosition("domob 2", {"x": -10, "y": 0})
        self.expectPosition("domob 3", {"x": -10, "y": 0})

        wp = [{"x": 0, "y": 0}]
        self.setWaypoints("domob 3", wp, speed=1000)
        self.setWaypoints("domob 2", wp, speed=1000)
        self.setWaypoints("domob", wp, speed=1000)

        self.generate(1)
        self.expectPosition("domob", {"x": -9, "y": 0})
        self.expectPosition("domob 2", {"x": -10, "y": 0})
        self.expectPosition("domob 3", {"x": -10, "y": 0})

        self.generate(1)
        self.expectPosition("domob", {"x": -8, "y": 0})
        self.expectPosition("domob 2", {"x": -9, "y": 0})
        self.expectPosition("domob 3", {"x": -10, "y": 0})

        self.generate(1)
        self.expectPosition("domob", {"x": -7, "y": 0})
        self.expectPosition("domob 2", {"x": -8, "y": 0})
        self.expectPosition("domob 3", {"x": -9, "y": 0})

        self.generate(7)
        self.expectPosition("domob", {"x": 0, "y": 0})
        self.expectPosition("domob 2", {"x": -1, "y": 0})
        self.expectPosition("domob 3", {"x": -2, "y": 0})

        self.generate(20)
        self.expectPosition("domob", {"x": 0, "y": 0})
        self.expectPosition("domob 2", {"x": 0, "y": 0})
        self.expectPosition("domob 3", {"x": 0, "y": 0})
Esempio n. 16
0
    def testBlockingVehicle(self):
        """
    Tests how another vehicle can block the movement when it is placed
    into the path during the "stepping" phase.
    """

        self.mainLogger.info("Testing blocking the path...")

        self.initAccount("blocker", "g")
        self.createCharacters("blocker")
        self.generate(1)

        self.moveCharactersTo({
            "domob":
            offsetCoord({
                "x": 70,
                "y": 0
            }, self.offset, False),
            "blocker":
            offsetCoord({
                "x": 50,
                "y": 1
            }, self.offset, False),
        })

        # Set waypoints across a blocked path.
        self.setWaypoints("domob", [{"x": 0, "y": 0}])
        self.setWaypoints("blocker", [{"x": 50, "y": 0}])
        self.generate(10)

        # The character should be blocked by the obstacle.
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 51, "y": 0})
        assert mv["blockedturns"] > 0

        # Move the obstacle away and let the character continue moving.
        self.setWaypoints("blocker", [{"x": 50, "y": 1}])
        self.generate(5)
        pos, mv = self.getMovement("domob")
        assert pos["x"] < 50
        assert pos["x"] > 30
        assert "blockedturns" not in mv

        # Block the path again and let movement stop completely.
        self.moveCharactersTo({
            "blocker":
            offsetCoord({
                "x": 30,
                "y": 0
            }, self.offset, False),
        })
        self.generate(20)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 31, "y": 0})
        self.assertEqual(mv, None)

        # Move around the obstacle.
        self.setWaypoints("domob", [
            {
                "x": 31,
                "y": 1
            },
            {
                "x": 0,
                "y": 1
            },
            {
                "x": 0,
                "y": 0
            },
        ])
        self.generate(100)
        pos, mv = self.getMovement("domob")
        self.assertEqual(pos, {"x": 0, "y": 0})
        self.assertEqual(mv, None)
Esempio n. 17
0
    def run(self):
        self.collectPremine()

        self.mainLogger.info("Creating test characters...")
        self.initAccount("red", "r")
        self.createCharacters("red")
        self.initAccount("green", "g")
        self.createCharacters("green", 2)
        self.generate(1)
        self.changeCharacterVehicle("red", "light attacker")
        self.changeCharacterVehicle("green", "light attacker")
        self.changeCharacterVehicle("green 2", "light attacker")

        # We use the starting coordinate of green 1 as offset for coordinates,
        # so that the test is independent of the actual starting positions
        # of the characters.
        c = self.getCharacters()["green"]
        self.offset = c.getPosition()

        # Move all other characters in range before continuing with
        # the rest of the test.
        self.moveCharactersTo({
            "red":
            offsetCoord({
                "x": 1,
                "y": 0
            }, self.offset, False),
            "green 2":
            offsetCoord({
                "x": 0,
                "y": 1
            }, self.offset, False),
        })

        self.mainLogger.info("Testing randomised target selection...")
        cnts = {"green": 0, "green 2": 0}
        rolls = 10
        for _ in range(rolls):
            self.generate(1)
            self.assertEqual(self.getTargetCharacter("green"), "red")
            self.assertEqual(self.getTargetCharacter("green 2"), "red")
            fooTarget = self.getTargetCharacter("red")
            assert fooTarget is not None
            assert fooTarget in cnts
            cnts[fooTarget] += 1
            # Invalidate the last block so that we reroll the randomisation
            # with the next generated block.
            self.rpc.xaya.invalidateblock(self.rpc.xaya.getbestblockhash())
        for key, cnt in cnts.items():
            self.log.info("Target %s selected %d / %d times" %
                          (key, cnt, rolls))
            assert cnt > 0

        self.mainLogger.info(
            "Testing target selection when moving into range...")
        c = self.getCharacters()["red"]
        self.moveCharactersTo({
            "red":
            offsetCoord({
                "x": 13,
                "y": 0
            }, self.offset, False),
        })
        assert self.getTargetCharacter("green") is None
        # Note that we can move a directly to the offset coordinate (where also
        # b is), since a and b are of different factions.
        c.moveTowards(self.offset)
        self.generate(1)
        self.assertEqual(self.getCharacters()["red"].getPosition(),
                         offsetCoord({
                             "x": 10,
                             "y": 0
                         }, self.offset, False))
        self.assertEqual(self.getTargetCharacter("green"), "red")
Esempio n. 18
0
    def testWithBuildings(self):
        self.mainLogger.info("Testing with buildings...")

        # Invalid exbuildings arguments.
        a = {"x": -10, "y": 0}
        b = {"x": 10, "y": 0}
        self.expectError(-32602,
                         ".*Invalid method parameters.*",
                         self.call,
                         source=a,
                         target=b,
                         l1range=100,
                         exbuildings=42)
        for exb in [[0], ["foo"], [5, -42]]:
            self.expectError(-1,
                             "exbuildings is not valid",
                             self.call,
                             source=a,
                             target=b,
                             l1range=100,
                             exbuildings=exb)

        # Apply exbuildings to path to a building.
        self.build("checkmark", None, b, rot=0)
        buildings = self.getRpc("getbuildings")
        bId = buildings[-1]["id"]
        self.rpc.game.setpathbuildings(buildings=buildings)
        self.expectError(1,
                         "no connection",
                         self.call,
                         source=a,
                         target=b,
                         l1range=100)
        self.assertEqual(
            self.call(source=a,
                      target=b,
                      l1range=100,
                      exbuildings=[bId, bId, 123456])["dist"], 20 * 1000)

        # Invalid building specs for setpathbuildings.
        self.expectError(-32602,
                         ".*Invalid method parameters.*",
                         self.rpc.game.setpathbuildings,
                         buildings={})
        coord = {"x": 1, "y": 2}
        for specs in [
            [42],
            ["foo"],
            [{}],
            [{
                "type": "checkmark",
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": -5,
                "type": "checkmark",
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": 0,
                "type": "checkmark",
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": 10,
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": 10,
                "type": 42,
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "invalid",
                "rotationsteps": 0,
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": "0",
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": -1,
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": 6,
                "centre": coord
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": 0
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": 0,
                "centre": "(0, 0)"
            }],
            [{
                "id": 10,
                "type": "checkmark",
                "rotationsteps": 0,
                "centre": {
                    "x": 1
                }
            }],
            [
                {
                    "id": 10,
                    "type": "checkmark",
                    "rotationsteps": 0,
                    "centre": coord
                },
                {
                    "id": 10,
                    "type": "checkmark",
                    "rotationsteps": 0,
                    "centre": coord
                },
            ],
        ]:
            self.expectError(-1,
                             "buildings is invalid",
                             self.rpc.game.setpathbuildings,
                             buildings=specs)

        # This is a very long path, which takes a non-negligible amount of time
        # to compute.  We use this later to ensure that multiple calls are
        # actually done in parallel and not blocking each other.
        longA = {"x": -2000, "y": 0}
        longB = {"x": 2000, "y": 0}
        kwargs = {
            "source": longA,
            "target": longB,
            "faction": "r",
            "l1range": 8000,
            "exbuildings": [],
        }
        before = time.clock_gettime(time.CLOCK_MONOTONIC)
        path = self.call(**kwargs)
        after = time.clock_gettime(time.CLOCK_MONOTONIC)
        baseDuration = after - before
        self.log.info("Duration for single call: %.3f s" % baseDuration)
        baseLen = path["dist"]

        # This is a very long path.  Make sure its encoded form is relatively
        # small, though.
        assert len(path["wp"]) > 100
        assert len(path["encoded"]) < 750
        serialised = json.dumps(path["wp"], separators=(",", ":"))
        assert len(serialised) > 3000

        # Now place buildings in two steps on the map, which make the path from
        # longA to longB further.  We use the output of getbuildings itself, to
        # ensure that it can be passed directly back to setpathbuildings.
        buildings = [[]]
        self.build("r rt",
                   None,
                   offsetCoord(longA, {
                       "x": 1,
                       "y": 0
                   }, False),
                   rot=0)
        self.build("r rt",
                   None,
                   offsetCoord(longA, {
                       "x": 1,
                       "y": -1
                   }, False),
                   rot=0)
        self.build("r rt",
                   None,
                   offsetCoord(longA, {
                       "x": 0,
                       "y": 1
                   }, False),
                   rot=0)
        buildings.append(self.getRpc("getbuildings"))
        self.build("r rt",
                   None,
                   offsetCoord(longA, {
                       "x": 0,
                       "y": -1
                   }, False),
                   rot=0)
        self.build("r rt",
                   None,
                   offsetCoord(longA, {
                       "x": -1,
                       "y": 1
                   }, False),
                   rot=0)
        buildings.append(self.getRpc("getbuildings"))

        # We do three calls now in parallel, with different sets of buildings.
        # All should be running concurrently and not block each other.  The total
        # time should be shorter than sequential execution.
        before = time.clock_gettime(time.CLOCK_MONOTONIC)
        calls = []
        for b in buildings:
            calls.append(AsyncFindPath(self.gamenode, b, **kwargs))
        [shortLen, midLen, longLen] = [c.finish()["dist"] for c in calls]
        after = time.clock_gettime(time.CLOCK_MONOTONIC)
        threeDuration = after - before
        self.log.info("Duration for three calls: %.3f s" % threeDuration)
        self.assertEqual(shortLen, baseLen)
        assert midLen > shortLen
        assert longLen > midLen
        assert threeDuration < 2 * baseDuration
Esempio n. 19
0
  def run (self):
    self.collectPremine ()

    self.mainLogger.info ("Setting up test characters...")
    self.initAccount ("target", "r")
    self.createCharacters ("target")
    self.initAccount ("attacker 1", "g")
    self.createCharacters ("attacker 1")
    self.initAccount ("attacker 2", "g")
    self.createCharacters ("attacker 2")
    self.generate (1)
    self.changeCharacterVehicle ("attacker 1", "light attacker")
    self.changeCharacterVehicle ("attacker 2", "light attacker")

    # Set up known positions of the characters.  We use a known good position
    # as origin and move all attackers there.  The target will be moved to a
    # point nearby (but not in range yet).
    self.offset = {"x": -1050, "y": 1272}
    self.moveCharactersTo ({
      "target": offsetCoord ({"x": 20, "y": 0}, self.offset, False),
      "attacker 1": offsetCoord ({"x": 0, "y": 1}, self.offset, False),
      "attacker 2": offsetCoord ({"x": -1, "y": 0}, self.offset, False),
    })

    # Move character and start prospecting.  This should stop the movement.
    # Further movements should be ignored.  Verify the prospection effects.
    self.mainLogger.info ("Basic prospecting and movement...")

    self.getCharacters ()["target"].moveTowards (self.offset)
    self.generate (2)
    c = self.getCharacters ()["target"]
    pos = c.getPosition ()
    assert c.isMoving ()
    region = self.getRegionAt (pos)
    assert "prospection" not in region.data
    assert region.getId () != self.getRegionAt (self.offset).getId ()

    c.sendMove ({"prospect": {}})
    self.generate (1)
    c = self.getCharacters ()["target"]
    self.assertEqual (c.getPosition (), pos)
    region = self.getRegionAt (pos)
    assert not c.isMoving ()
    self.assertEqual (c.getBusy (), {
      "blocks": 10,
      "operation": "prospecting",
    })
    self.assertEqual (region.data["prospection"], {"inprogress": c.getId ()})

    c.moveTowards (self.offset)
    self.generate (1)
    c = self.getCharacters ()["target"]
    self.assertEqual (c.getPosition (), pos)
    assert not c.isMoving ()
    self.assertEqual (c.getBusy ()["blocks"], 9)

    self.generate (9)
    c = self.getCharacters ()["target"]
    self.assertEqual (c.getPosition (), pos)
    self.assertEqual (c.getBusy (), None)
    region = self.getRegionAt (pos)
    self.assertEqual (region.data["prospection"]["name"], "target")
    self.assertEqual (region.data["prospection"]["height"],
                      self.rpc.xaya.getblockcount ())

    # Move towards attackers and prospect there, but have the character
    # killed before it is done.
    self.mainLogger.info ("Killing prospecting character...")

    pos = offsetCoord ({"x": 5, "y": 0}, self.offset, False)
    region = self.getRegionAt (pos)

    self.prospectors = ["attacker 1", "attacker 2"]
    char = self.getCharacters ()
    for p in self.prospectors:
      prospRegion = self.getRegionAt (char[p].getPosition ())
      self.assertEqual (region.getId (), prospRegion.getId ())

    self.moveCharactersTo ({
      "target": pos
    })
    self.generate (1)

    c = self.getCharacters ()["target"]
    self.assertEqual (c.getPosition (), pos)
    c.sendMove ({"prospect": {}})
    self.generate (1)
    c = self.getCharacters ()["target"]
    self.assertEqual (c.getBusy (), {
      "blocks": 10,
      "operation": "prospecting",
    })

    self.setCharactersHP ({
      "target": {"a": 1, "s": 0},
    })
    self.generate (1)
    assert "target" not in self.getCharacters ()
    region = self.getRegionAt (pos)
    assert "prospection" not in region.data

    # Start prospecting with one of the attackers and later with another one.
    # Check that the first goes through and the second is ignored.
    self.mainLogger.info ("Competing prospectors...")

    self.reorgBlock = self.rpc.xaya.getbestblockhash ()
    self.getCharacters ()[self.prospectors[0]].sendMove ({"prospect": {}})
    self.generate (1)
    self.getCharacters ()[self.prospectors[1]].sendMove ({"prospect": {}})
    self.generate (1)

    region = self.getRegionAt (self.offset)
    chars = self.getCharacters ()
    self.assertEqual (chars[self.prospectors[0]].getBusy (), {
      "blocks": 9,
      "operation": "prospecting",
    })
    self.assertEqual (chars[self.prospectors[1]].getBusy (), None)
    self.assertEqual (region.data["prospection"], {
      "inprogress": chars[self.prospectors[0]].getId ()
    })

    self.generate (9)
    self.assertEqual (self.getCharacters ()[self.prospectors[0]].getBusy (),
                      None)
    self.expectProspectedBy (self.offset, self.prospectors[0])

    # Now that the region is already prospected, further (immediate) attempts
    # should just be ignored.
    self.mainLogger.info ("Trying in already prospected region...")
    self.getCharacters ()[self.prospectors[1]].sendMove ({"prospect": {}})
    sleepSome ()
    self.assertEqual (self.getPendingState ()["characters"], [])
    self.generate (1)
    self.assertEqual (self.getCharacters ()[self.prospectors[1]].getBusy (),
                      None)
    self.expectProspectedBy (self.offset, self.prospectors[0])

    # Mine all the resources (and drop them), so that we can reprospect
    # the region in the next step.
    self.mainLogger.info ("Mining all resources...")
    miner = self.prospectors[1]
    while True:
      typ, remaining = self.getRegionAt (self.offset).getResource ()
      if remaining == 0:
        break
      self.getCharacters ()[miner].sendMove ({
        "drop": {"f": {typ: 1000}},
        "mine": {},
      })
      self.generate (50)

    # Start prospecting after the expiry, but kill the prospector.  This should
    # effectively "unprospect" the region completely.
    self.mainLogger.info ("Attempting re-prospecting...")
    self.generate (100)
    self.createCharacters ("target", 1)
    self.generate (1)
    self.setCharactersHP ({
      "target": {"a": 1000, "ma": 1000, "s": 0, "ms": 100},
    })
    self.moveCharactersTo ({
      "target": self.offset,
    })
    r = self.getRegionAt (self.offset)
    c = self.getCharacters ()["target"]
    c.sendMove ({"prospect": {}})
    self.assertEqual (self.getPendingState ()["characters"], [
      {
        "id": c.getId (),
        "drop": False,
        "pickup": False,
        "prospecting": r.getId (),
      },
    ])
    self.generate (1)
    self.assertEqual (self.getCharacters ()["target"].getBusy ()["operation"],
                      "prospecting")

    self.setCharactersHP ({
      "target": {"a": 1, "s": 0},
    })
    self.generate (1)
    assert "target" not in self.getCharacters ()
    r = self.getRegionAt (self.offset)
    assert "prospection" not  in r.data
    self.assertEqual (r.getResource (), None)

    # Actually re-prospect the region.
    self.mainLogger.info ("Finish reprospecting...")
    self.initAccount ("reprospector", "g")
    self.createCharacters ("reprospector", 1)
    self.generate (1)
    self.moveCharactersTo ({
      "reprospector": self.offset,
    })
    self.getCharacters ()["reprospector"].sendMove ({"prospect": {}})
    self.generate (15)
    self.expectProspectedBy (self.offset, "reprospector")
    assert self.getRegionAt (self.offset).getResource () is not None

    self.testReorg ()
Esempio n. 20
0
    def testWithBuildingData(self):
        self.mainLogger.info("Testing with building data...")

        # This is a very long path, which takes a non-negligible amount of time
        # to compute.  We use this later to ensure that multiple calls are
        # actually done in parallel and not blocking each other.
        longA = {"x": -2000, "y": 0}
        longB = {"x": 2000, "y": 0}
        kwargs = {
            "source": longA,
            "target": longB,
            "faction": "r",
            "l1range": 8000,
            "exbuildings": [],
        }
        before = time.clock_gettime(time.CLOCK_MONOTONIC)
        path = self.call(**kwargs)
        after = time.clock_gettime(time.CLOCK_MONOTONIC)
        baseDuration = after - before
        self.log.info("Duration for single call: %.3f s" % baseDuration)
        baseLen = path["dist"]

        # This is a very long path.  Make sure its encoded form is relatively
        # small, though.
        assert len(path["wp"]) > 100
        assert len(path["encoded"]) < 750
        serialised = json.dumps(path["wp"], separators=(",", ":"))
        assert len(serialised) > 3000

        # Now place buildings in two steps on the map, which make the path from
        # longA to longB further.  We use the outputs of getbuildings itself, to
        # ensure that it can be passed directly back to setpathdata.
        buildings = [[]]

        self.build("huesli",
                   None,
                   offsetCoord(longA, {
                       "x": 1,
                       "y": 0
                   }, False),
                   rot=0)
        self.build("huesli",
                   None,
                   offsetCoord(longA, {
                       "x": 1,
                       "y": -1
                   }, False),
                   rot=0)
        self.build("huesli",
                   None,
                   offsetCoord(longA, {
                       "x": 0,
                       "y": 1
                   }, False),
                   rot=0)
        buildings.append(self.getRpc("getbuildings"))

        self.build("huesli",
                   None,
                   offsetCoord(longA, {
                       "x": 0,
                       "y": -1
                   }, False),
                   rot=0)
        self.build("huesli",
                   None,
                   offsetCoord(longA, {
                       "x": -1,
                       "y": 1
                   }, False),
                   rot=0)
        buildings.append(self.getRpc("getbuildings"))

        # We do three calls now in parallel, with different sets of buildings.
        # All should be running concurrently and not block each other.  The total
        # time should be shorter than sequential execution.
        before = time.clock_gettime(time.CLOCK_MONOTONIC)
        calls = []
        for b in buildings:
            calls.append(AsyncFindPath(self.gamenode, b, [], **kwargs))
        [shortLen, midLen, longLen] = [c.finish()["dist"] for c in calls]
        after = time.clock_gettime(time.CLOCK_MONOTONIC)
        threeDuration = after - before
        self.log.info("Duration for three calls: %.3f s" % threeDuration)
        self.assertEqual(shortLen, baseLen)
        assert midLen > shortLen
        assert longLen > midLen
        assert threeDuration < 2 * baseDuration