diff --git a/.gitignore b/.gitignore index b6e4761..00ce796 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,9 @@ venv.bak/ .spyderproject .spyproject +#VSCode project settings +.vscode + # Rope project settings .ropeproject diff --git a/examples/8_draw.py b/examples/8_draw.py new file mode 100644 index 0000000..56f1fad --- /dev/null +++ b/examples/8_draw.py @@ -0,0 +1,22 @@ +from tagilmo.utils.vereya_wrapper import MCConnector +import tagilmo.utils.mission_builder as mb + +block = mb.DrawBlock("-1", "-60", "4", "cobblestone") +it = mb.DrawItem(0, -60, 0, "diamond") +cuboid = mb.DrawCuboid("1", -60, "0", 3, -60, 3, "sandstone") +line = mb.DrawLine(5, -60, 3, 9, -55, 8, "diamond_ore") +draw = mb.DrawingDecorator([block, it, cuboid, line]) + +miss = mb.MissionXML(serverSection=mb.ServerSection(handlers=mb.ServerHandlers(drawingdecorator=draw))) +miss.setWorld(mb.flatworld("", + seed= '5', + forceReset = "true")) +miss.setObservations(mb.Observations()) +# we typically don't need this for real Minecraft agents, but this example just checks the connection to Minecraft +miss.setTimeLimit(5000) + +mc = MCConnector(miss) +# Note that we need two instances of Minecraft running +mc.safeStart() + +mc.stop() \ No newline at end of file diff --git a/tagilmo/utils/mission_builder.py b/tagilmo/utils/mission_builder.py index b28180f..acf7e7a 100755 --- a/tagilmo/utils/mission_builder.py +++ b/tagilmo/utils/mission_builder.py @@ -89,16 +89,17 @@ def fileworld(uri2save, forceReset="false"): class ServerHandlers: def __init__(self, worldgenerator_xml=defaultworld(), alldecorators_xml=None, - bQuitAnyAgent=False, timeLimitsMs_string=None): + bQuitAnyAgent=False, timeLimitsMs_string=None, drawingdecorator = None): self.worldgenerator = worldgenerator_xml self.alldecorators = alldecorators_xml self.bQuitAnyAgent = bQuitAnyAgent self.timeLimitsMs = timeLimitsMs_string - + self.drawingdecorator = drawingdecorator + def xml(self): _xml = '\n' + self.worldgenerator + '\n' - #if self.drawingdecorator: - # _xml += '\n' + self.drawingdecorator + '\n\n' + if self.drawingdecorator: + _xml += '\n' + self.drawingdecorator.xml() + '\n' # -- # -- if self.alldecorators: @@ -122,6 +123,141 @@ def xml(self): return '\n'+self.initial_conditions.xml()+self.handlers.xml()+'\n' +class DrawingDecorator: + def __init__(self, decorators = []): + """ + Draw all given Draw objects + + Parameters: + decorators (List[Union[DrawBlock, DrawCuboid, DrawItem, DrawLine]]) : a list of objects to be drawn.\nEach object can be one of the following types: + - DrawBlock: represents a block. + - DrawCuboid: represents a cuboid. + - DrawItem: represents an item. + - DrawLine: represents a line between two points. + """ + self.decorators = decorators + + def xml(self): + _xml = "" + for decorator in self.decorators: + _xml += decorator.xml() + return _xml + + +class DrawBlock: + def __init__(self, x, y, z, blockType): + """ + Draw a block in world. + + Parameters: + x (int | str): x coordinate. + y (int | str): y coordinate. + z (int | str): z coordinate. + blockType (str): block that will be used. + """ + self.x = x + self.y = y + self.z = z + self.blockType = blockType + + def xml(self): + return f'\n' + + +class DrawCuboid: + def __init__(self, x1, y1, z1, x2, y2, z2, blockType): + """ + Draw a cuboid in world. + + Parameters: + x1 (int | str): x coordinate of the first corner. + y1 (int | str): y coordinate of the first corner. + z1 (int | str): z coordinate of the first corner. + x2 (int | str): x coordinate of the second corner. + y2 (int | str): y coordinate of the second corner. + z2 (int | str): z coordinate of the second corner. + blockType (str): block that will be used. + """ + self.x1 = x1 + self.y1 = y1 + self.z1 = z1 + self.x2 = x2 + self.y2 = y2 + self.z2 = z2 + self.blockType = blockType + + def xml(self): + return f'\n' + + +class DrawLine: + def __init__(self, x1, y1, z1, x2, y2, z2, blockType): + """ + Draw a line of blocks in world. + + Parameters: + x1 (int | str): x coordinate of the first point. + y1 (int | str): y coordinate of the first point. + z1 (int | str): z coordinate of the first point. + x2 (int | str): x coordinate of the second point. + y2 (int | str): y coordinate of the second point. + z2 (int | str): z coordinate of the second point. + blockType (str): block that will be used. + """ + self.x1 = x1 + self.y1 = y1 + self.z1 = z1 + self.x2 = x2 + self.y2 = y2 + self.z2 = z2 + self.blockType = blockType + + def xml(self): + return f'\n' + + +class DrawItem: + def __init__(self, x, y, z, itemType): + """ + Draw an item in world. + + Parameters: + x (int | str): x coordinate. + y (int | str): y coordinate. + z (int | str): z coordinate. + itemType (str): item that will be used. + """ + self.x = x + self.y = y + self.z = z + self.itemType = itemType + + def xml(self): + return f'\n' + + +class DrawSphere: + def __init__(self, x, y, z, radius, blockType): + """ + Draw a block in world. + + Parameters: + x (int | str): x coordinate. + y (int | str): y coordinate. + z (int | str): z coordinate. + radius (int | str): radius. + blockType (str): block that will be used. + """ + self.x = x + self.y = y + self.z = z + self.radius = radius + self.blockType = blockType + + def xml(self): + return f'\n' + + class Commands: def __init__(self, bAll=True, bContinuous=None, bDiscrete=None, bInventory=None, diff --git a/tests/vereya/common.py b/tests/vereya/common.py index b5137c3..32b4bfb 100644 --- a/tests/vereya/common.py +++ b/tests/vereya/common.py @@ -4,12 +4,12 @@ import json import time import os +import warnings import tagilmo.utils.mission_builder as mb from tagilmo.utils.vereya_wrapper import MCConnector, RobustObserver from base_test import BaseTest - -def init_mission(mc, start_x, start_z, seed, forceReset="false", forceReuse="false", start_y=78): +def init_mission(mc, start_x, start_z, seed, forceReset="false", forceReuse="false", start_y=78, worldType = "default"): want_depth = False video_producer = mb.VideoProducer(width=320 * 4, height=240 * 4, want_depth=want_depth) @@ -34,10 +34,22 @@ def init_mission(mc, start_x, start_z, seed, forceReset="false", forceReuse="fal flat_param = "3;7,25*1,3*3,2;1;stronghold,biome_1,village,decoration,dungeon,lake,mineshaft,lava_lake" flat_json = json.dumps(flat_json).replace('"', "%ESC") - world = mb.defaultworld( - seed=seed, - forceReset=forceReset, - forceReuse=forceReuse) + match worldType: + case "default": + world = mb.defaultworld( + seed=seed, + forceReset=forceReset, + forceReuse=forceReuse) + case "flat": + world = mb.flatworld("", + seed=seed, + forceReset=forceReset) + case _: + warnings.warn("World type " + worldType + " is not supported, setting up default world") + world = mb.defaultworld( + seed=seed, + forceReset=forceReset, + forceReuse=forceReuse) miss.setWorld(world) miss.serverSection.initial_conditions.allowedmobs = "Pig Sheep Cow Chicken Ozelot Rabbit Villager" # uncomment to disable passage of time: