コード例 #1
0
ファイル: MapParser.py プロジェクト: PsiOmegaDelta/ByondTools
class MapParserTest(unittest.TestCase):
    def setUp(self):
        from byond.map.format.dmm import DMMFormat
        self.dmm = DMMFormat()
    
    def test_basic_SplitAtoms_operation(self):
        testStr = '/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area'
        expectedOutput = ['/obj/effect/landmark{name = "carpspawn"}', '/obj/structure/lattice', '/turf/space', '/area']
        
        out = self.dmm.SplitAtoms(testStr)
        self.assertListEqual(out, expectedOutput)
    
    def test_basic_SplitProperties_operation(self):
        testStr = 'd1 = 1; d2 = 2; icon_state = "1-2"; tag = ""'
        expectedOutput = ['d1 = 1', ' d2 = 2', ' icon_state = "1-2"', ' tag = ""']
        
        out = self.dmm.SplitProperties(testStr)
        self.assertListEqual(out, expectedOutput)
    
    def test_basic_consumeTile_operation(self):
        from byond.map import Map, Tile
        '''
        "aaK" = (
            /obj/structure/cable{
                d1 = 1;
                d2 = 2; 
                icon_state = "1-2";
                tag = ""
            },
            /obj/machinery/atmospherics/pipe/simple/supply/hidden{
                dir = 4
            },
            /turf/simulated/floor{
                icon_state = "floorgrime"
            },
            /area/security/prison
        )
        '''
        testStr = '"aaK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison)'
        out = self.dmm.consumeTile(testStr, 0, False) # :type out: Tile
        print('IIDs: {0}'.format(repr(out.instances)))

        self.assertEquals(out.origID, 'aaK', 'origID')
        self.assertEquals(len(out.instances), 4, 'instances size')
        self.assertEquals(len(out.GetAtom(0).properties), 4, 'instances[0] properties')
        self.assertIn('d1', out.GetAtom(0).properties, 'd1 not present in properties')
        self.assertListEqual(out.GetAtom(0).mapSpecified,['d1','d2','icon_state','tag'])
        
        self.assertEquals(len(out.GetAtom(2).properties), 1, 'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}')
        self.assertIn('icon_state', out.GetAtom(2).properties, 'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}')
        
        self.assertEqual(out.MapSerialize(Tile.FLAG_USE_OLD_ID), testStr)
        
    def test_consumeTile_landmark(self):
        testStr='"aah" = (/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area)'
        out = self.dmm.consumeTile(testStr, 0)
        self.assertEqual(out.MapSerialize(Tile.FLAG_USE_OLD_ID), testStr)
コード例 #2
0
ファイル: dmm.py プロジェクト: Boggart/ByondTools
def patch_dmm(args):
    print(repr(args.patches))
    for i in range(len(args.patches[0])):
        patch=args.patches[0][i]
        if not os.path.isfile(patch):
            print('File {0} does not exist.'.format(patch))
            sys.exit(1)
    if not os.path.isfile(args.map):
        print('File {0} does not exist.'.format(args.mine))
        sys.exit(1)
    if not os.path.isfile(args.project):
        print('DM Environment File {0} does not exist.'.format(args.project))
        sys.exit(1)
        
    dmm = Map(forgiving_atom_lookups=True)
    dmm.Load(args.map, format='dmm')
    
    fmt = DMMFormat(dmm)

    context = None
    added = 0
    removed = 0
    
    currentpatch = ''
    
    def changeMarker(ln):
        a = Atom('/obj/effect/byondtools/changed')
        a.setProperty('tag','{}:{}'.format(currentpatch,ln),flags=PropertyFlags.MAP_SPECIFIED)
        return a
    
    def printReport(context, added, removed):
        if context is not None:
            x, y, z = context
            print(' Z={} +{} -{}'.format(z, added, removed))
    
    REG_INSTRUCTION = re.compile(r'^(?P<change>[\+\-])(?P<amount>[0-9\*]+)?\s+(?P<atom>/.*)')
    
    for i in range(len(args.patches[0])):
        patch=args.patches[0][i]
        print('* Applying {}...'.format(patch))
        currentpatch=patch
        with open(patch) as f:
            ln = 0
            lz = -1
            skip_block = False
            for line in f:
                ln += 1
                line = line.strip()
                if line == '': continue
                if line.startswith('#'): continue
                if line.startswith('<') and line.endswith('>'):
                    strcoords = line.strip('<>').split(',')
                    newcoords = []
                    for coord in strcoords:
                        newcoords += [int(coord)]
                    if context is not None and lz != context[2]:
                        printReport(context, added, removed)
                        lz = context[2]
                        added = removed = 0
                    context = newcoords
                    skip_block = False
                    continue
                if line.startswith('@') and not skip_block:
                    # @CHECK before-hash after-hash atoms-block
    
                    x, y, z = context
                    
                    if line.startswith('@CHECK'):
                        _, beforehash, afterhash, serdata = line.split(' ', 3)
                        
                        if args.clobber:
                            #print('WARNING: <{},{},{}> has changed and will be overwritten. (--clobber)'.format(x, y, z))
                            t=fmt.consumeTileChunk(serdata, cache=False)
                            t.AppendAtom(changeMarker(ln))
                            dmm.SetTileAt(x, y, z, t)
                            skip_block = True
                            continue
                        curhash = dmm.GetTileAt(x, y, z).GetHash()
                        if afterhash == curhash:
                            print('Skipping <{},{},{}> (already what we expected)'.format(x, y, z))
                            skip_block = True
                            continue
                        #else: print('PRE {} != {}: OK'.format(curhash,afterhash))
                        if beforehash != curhash:
                            print('WARNING: <{},{},{}> has changed.  Operations on this tile may not be accurate!'.format(x, y, z))
                            continue
                        #else: print('OLD {} == {}: OK'.format(curhash,beforehash))
                              
                if not skip_block and (line.startswith('+') or line.startswith('-')):
                    if line == '-ALL':
                        dmm.SetTileAt(x, y, z, dmm.CreateTile())
                        continue
                    m = REG_INSTRUCTION.match(line)
                    if m is None:
                        print('{}:{}: MALFORMED INSTRUCTION: {}'.format(args.patch, ln, line))
                        sys.exit(1)
                    amount = m.group('amount')
                    if amount == '*':
                        amount = 9999
                    else:
                        amount = int(m.group('amount') or 1)
                    change = m.group('change')
                    
                    atom = fmt.consumeAtom(m.group('atom'), ln)
                    atom.filename = args.patch
                    atom.line = ln
                    if atom is None:
                        print('{}:{}: WARNING: Unable to parse instance specified by chunk {}'.format(args.patch, ln, m.group('atom')))
                        continue
    
                    x, y, z = context
                    if x == 0 and y == 0 and z == 0:
                        print('WE AT <0,0,0> SOMEFIN WRONG')
                        
                    if z >= len(dmm.zLevels): continue
                    
                    tile = dmm.GetTileAt(x, y, z)
                    if change == '-':
                        for _ in range(amount):
                            if tile.CountAtom(atom) > 0:
                                tile.RemoveAtom(atom, hash=False)
                                removed += 1
                            else: break
                    elif change == '+':
                        for _ in range(amount):
                            tile.AppendAtom(atom, hash=False)
                        added += amount
                    tile.UpdateHash()
                    # dmm.SetTileAt(x, y, z, tile)
                    # print('{} - {}'.format((x,y,z),tile))
            printReport(context, added, removed)
    
    print('Saving...')
    dmm.Save(args.output if args.output else args.map)
コード例 #3
0
ファイル: MapParser.py プロジェクト: Boggart/ByondTools
 def setUp(self):
     from byond.map.format.dmm import DMMFormat
     from byond.map import Map
     self.map = Map()
     self.dmm = DMMFormat(self.map)
コード例 #4
0
ファイル: MapParser.py プロジェクト: Boggart/ByondTools
class MapParserTest(unittest.TestCase):
    def setUp(self):
        from byond.map.format.dmm import DMMFormat
        from byond.map import Map
        self.map = Map()
        self.dmm = DMMFormat(self.map)
    
    def test_basic_SplitAtoms_operation(self):
        testStr = '/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area'
        expectedOutput = ['/obj/effect/landmark{name = "carpspawn"}', '/obj/structure/lattice', '/turf/space', '/area']
        
        out = self.dmm.SplitAtoms(testStr)
        self.assertListEqual(out, expectedOutput)
    
    def test_basic_SplitProperties_operation(self):
        testStr = 'd1 = 1; d2 = 2; icon_state = "1-2"; tag = ""'
        expectedOutput = ['d1 = 1', ' d2 = 2', ' icon_state = "1-2"', ' tag = ""']
        
        out = self.dmm.SplitProperties(testStr)
        self.assertListEqual(out, expectedOutput)
    
    def test_basic_consumeTile_operation(self):
        from byond.map import Map, Tile
        '''
        "aaK" = (
            /obj/structure/cable{
                d1 = 1;
                d2 = 2; 
                icon_state = "1-2";
                tag = ""
            },
            /obj/machinery/atmospherics/pipe/simple/supply/hidden{
                dir = 4
            },
            /turf/simulated/floor{
                icon_state = "floorgrime"
            },
            /area/security/prison
        )
        '''
        testStr = '"aaK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison)'
        testSerData='/obj/structure/cable{d1=1;d2=2;icon_state="1-2";tag=""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir=4},/turf/simulated/floor{icon_state="floorgrime"},/area/security/prison{}'
        
        out = self.dmm.consumeTile(testStr, False) # :type out: Tile
        #print('IIDs: {0}'.format(repr(out.instances)))

        self.assertEquals(out.origID, 'aaK', 'origID')
        self.assertEquals(len(out.instances), 4, 'instances size')
        self.assertEquals(len(out.GetAtom(0).properties), 4, 'instances[0] properties')
        self.assertIn('d1', out.GetAtom(0).properties, 'd1 not present in properties')
        self.assertListEqual(out.GetAtom(0).mapSpecified,['d1','d2','icon_state','tag'])
        
        self.assertEquals(len(out.GetAtom(2).properties), 1, 'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}')
        self.assertIn('icon_state', out.GetAtom(2).properties, 'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}')
        
        self.assertEqual(out._serialize(), testSerData)
        
    def _show_expected_vs_actual(self,expected,actual):
        if expected != actual:
            print(' > EXPECTED: {}'.format(expected))
            print(' > ACTUAL:   {}'.format(actual))
        
    
    def test_basic_SerializeTile_operation(self):
        from byond.map import Map, Tile
        '''
        "aaK" = (
            /obj/structure/cable{
                d1 = 1;
                d2 = 2; 
                icon_state = "1-2";
                tag = ""
            },
            /obj/machinery/atmospherics/pipe/simple/supply/hidden{
                dir = 4
            },
            /turf/simulated/floor{
                icon_state = "floorgrime"
            },
            /area/security/prison
        )
        '''
        testStr = '"aaK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison)'
        expected = testStr.split('=',1)[1].strip()
        tile = self.dmm.consumeTile(testStr, False) # :type tile: Tile
        out = self.dmm.SerializeTile(tile)
        self._show_expected_vs_actual(expected, out)
        self.assertEqual(out, expected)
    def test_consumeTile_secureArea(self):
        '''
        "aai" = (
            /obj/structure/sign/securearea{
                desc = "A warning sign which reads \'HIGH VOLTAGE\'"; 
                icon_state = "shock"; 
                name = "HIGH VOLTAGE"; 
                pixel_y = -32
            },
            /turf/space,
            /area
        )
        '''
        testStr = '"aai" = (/obj/structure/sign/securearea{desc = "A warning sign which reads \'HIGH VOLTAGE\'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = -32},/turf/space,/area)'

        tile = self.dmm.consumeTile(testStr, False) # :type tile: Tile
        
        self.assertEquals(tile.origID, 'aai', 'origID')
        self.assertEquals(len(tile.instances), 3, 'instances size')
        self.assertEquals(len(tile.GetAtom(0).properties), 4, 'instances[0] properties')
        self.assertIn('desc', tile.GetAtom(0).properties, 'desc not present in properties')
        self.assertListEqual(tile.GetAtom(0).mapSpecified,['desc','icon_state','name','pixel_y'])
        
        expected = testStr.split('=',1)[1].strip()
        out = self.dmm.SerializeTile(tile)
        self._show_expected_vs_actual(expected, out)
        self.assertEqual(out, expected)

        
    def test_consumeTile_landmark(self):
        testStr='"aah" = (/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area)'
        testSerData='/obj/effect/landmark{name="carpspawn"},/obj/structure/lattice{},/turf/space{},/area{}'
        out = self.dmm.consumeTile(testStr)
        self.assertEqual(out._serialize(), testSerData)
コード例 #5
0
ファイル: dmm.py プロジェクト: ComicIronic/ByondToolsv3
def compare_dmm(args):
    if not os.path.isfile(args.theirs):
        print('File {0} does not exist.'.format(args.theirs))
        sys.exit(1)
    if not os.path.isfile(args.mine):
        print('File {0} does not exist.'.format(args.mine))
        sys.exit(1)
    if not os.path.isfile(args.project):
        print('DM Environment File {0} does not exist.'.format(args.project))
        sys.exit(1)

    theirs_dmm = Map(forgiving_atom_lookups=True)
    theirs_dmm.Load(args.theirs, format='dmm')

    mine_dmm = Map(forgiving_atom_lookups=True)
    mine_dmm.Load(args.mine, format='dmm')

    ttitle, _ = os.path.splitext(os.path.basename(args.theirs))
    mtitle, _ = os.path.splitext(os.path.basename(args.mine))

    format = DMMFormat(theirs_dmm)

    output = '{} - {}.dmmpatch'.format(ttitle, mtitle)

    if args.output:
        output = args.output
    with open(output, 'w') as f:
        stats = {'diffs': 0, 'tilediffs': 0, 'tiles': 0, 'atoms': 0}
        print('Comparing maps...')
        for z in range(len(theirs_dmm.zLevels)):
            t_zlev = theirs_dmm.zLevels[z]
            m_zlev = mine_dmm.zLevels[z]
            if t_zlev.height != m_zlev.height or t_zlev.width != m_zlev.width:
                print(
                    '!!! ZLEVEL {} HEIGHT/WIDTH MISMATCH: ({},{}) != ({},{})'.
                    format(z, t_zlev.height, t_zlev.width, m_zlev.height,
                           m_zlev.width))
                continue
            print(" Scanning z-level {} ({}x{})...".format(
                z, t_zlev.height, t_zlev.width))
            for y in range(t_zlev.height):
                for x in range(t_zlev.width):
                    CHANGES = {}

                    tTile = theirs_dmm.GetTileAt(x, y, z)
                    # if tTile is None:
                    #    print('!!! THEIRS <{},{},{}>: Tile object is None!'.format(x, y, z))
                    #    #return
                    mTile = mine_dmm.GetTileAt(x, y, z)
                    # if tTile is None:
                    #    print('!!! MINE <{},{},{}>: Tile object is None!'.format(x, y, z))
                    #    #return

                    theirs = {}
                    mine = {}
                    all_keys = set()

                    if tTile:
                        for A in tTile.GetAtoms():
                            key = format.SerializeAtom(A)
                            all_keys.add(key)
                            if key not in theirs:
                                theirs[key] = [A, 0]
                            theirs[key][1] += 1
                    if mTile:
                        for A in mTile.GetAtoms():
                            key = format.SerializeAtom(A)
                            all_keys.add(key)
                            if key not in mine:
                                mine[key] = [A, 0]
                            mine[key][1] += 1

                    removals = set()
                    additions = set()
                    kept = {}

                    for key in all_keys:
                        change = None
                        minecount = 0
                        if key in mine:
                            minecount = mine[key][1]
                        theircount = 0
                        if key in theirs:
                            theircount = theirs[key][1]
                        delta = minecount - theircount
                        if delta < 0:
                            change = '-'
                            removals.add(key)
                        elif delta > 0:
                            change = '+'
                            additions.add(key)
                        if minecount > 0 and delta <= 0:
                            kept[key] = minecount
                        if change is not None:
                            CHANGES[key] = [
                                change,
                                abs(delta), minecount, theircount
                            ]
                        stats['tiles'] += 1

                    def writeChanges(f, source, CHANGES):
                        for key in source:
                            change, amount, mc, tc = CHANGES[key]
                            # change, amount, _, _ = changedat
                            # f.write(' # {} vs {}\n'.format(mc, tc))
                            abs_amt = abs(amount)
                            if abs_amt > 1:
                                f.write(' {}{} {}\n'.format(
                                    change, abs_amt if mc > 0 else '*', key))
                            else:
                                f.write(' {} {}\n'.format(change, key))
                            stats['diffs'] += abs_amt

                    if len(CHANGES) > 0:
                        f.write('<{},{},{}>\n'.format(x, y, z))
                        stats['tilediffs'] += 1
                        f.write(' @CHECK {before} {after} {tiledat}\n'.format(
                            before=tTile.GetHash(),
                            after=mTile.GetHash(),
                            tiledat=format.SerializeTile(mTile)))
                        if len(kept) == 0:
                            f.write(' -ALL\n')
                        else:
                            writeChanges(f, removals, CHANGES)
                        """
                        for key,count in kept.items():
                            if count > 1:
                                f.write(' ={} {}\n'.format(count, key))
                            else:
                                f.write(' = {}\n'.format(key))
                        """
                        writeChanges(f, additions, CHANGES)
        print('Compared maps: {} differences in {} tiles.'.format(
            stats['diffs'], stats['tilediffs']))
        print('Total: {} atoms, {} tiles.'.format(stats['diffs'],
                                                  stats['tilediffs']))
コード例 #6
0
ファイル: dmm.py プロジェクト: ComicIronic/ByondToolsv3
def main():
    dmmt = DMMFormat(None)
    opt = argparse.ArgumentParser()  # version='0.1')
    opt.add_argument('--project',
                     default='baystation12.dme',
                     type=str,
                     help='Project file.',
                     metavar='environment.dme')

    command = opt.add_subparsers(help='The command you wish to execute',
                                 dest='MODE')

    _compare = command.add_parser(
        'diff', help='Compare two map files and generate a map patch.')
    _compare.add_argument('-O',
                          '--output',
                          dest='output',
                          type=str,
                          help='The other side.',
                          metavar='mine.dmdiff',
                          nargs='?')
    _compare.add_argument('theirs',
                          type=str,
                          help='One side of the difference',
                          metavar='theirs.dmm')
    _compare.add_argument('mine',
                          type=str,
                          help='The other side.',
                          metavar='mine.dmm')

    _transcribe = command.add_parser(
        'transcribe', help='Re-write a map file (used for parser debugging).')
    _transcribe.add_argument('-O',
                             '--output',
                             dest='output',
                             type=str,
                             help='The other side.',
                             metavar='map.trans.dmm',
                             nargs='?')
    _transcribe.add_argument('subject',
                             type=str,
                             help='Map file to re-write.',
                             metavar='map.dmm')

    _patch = command.add_parser('patch', help='Apply a map patch.')
    _patch.add_argument(
        '-O',
        '--output',
        dest='output',
        type=str,
        help=
        'Where to place the patched map. (Default is to overwrite input map)',
        metavar='mine.dmdiff',
        nargs='?')
    _patch.add_argument('--clobber',
                        dest='clobber',
                        action="store_true",
                        help='Overwrite conflicts')
    _patch.add_argument('patches',
                        action='append',
                        nargs='+',
                        help='Patch(es) to apply.',
                        metavar='patch.dmmpatch')
    _patch.add_argument('map',
                        type=str,
                        help='The map to change.',
                        metavar='map.dmm')

    _analyze = command.add_parser(
        'analyze',
        help='Generate a report of each atom on a map.  WARNING: huge')
    _analyze.add_argument('map',
                          type=str,
                          help='Map to analyze.',
                          metavar='map.dmm')

    _split = command.add_parser('split', help='Split up a map by z-level.')
    #_split.add_argument('-i','--isolate', help='Isolate a given z-level', metavar='NUM')
    _split.add_argument('map',
                        type=str,
                        help='Map to split.',
                        metavar='map.dmm')

    args = opt.parse_args()
    if args.MODE == 'diff':
        compare_dmm(args)
    elif args.MODE == 'analyze':
        analyze_dmm(args)
    elif args.MODE == 'split':
        split_dmm(args)
    elif args.MODE == 'patch':
        patch_dmm(args)
    elif args.MODE == 'transcribe':
        transcribe_dmm(args)
    else:
        print('!!! Error, unknown MODE=%r' % args.MODE)
コード例 #7
0
ファイル: dmm.py プロジェクト: ComicIronic/ByondToolsv3
def patch_dmm(args):
    print(repr(args.patches))
    for i in range(len(args.patches[0])):
        patch = args.patches[0][i]
        if not os.path.isfile(patch):
            print('File {0} does not exist.'.format(patch))
            sys.exit(1)
    if not os.path.isfile(args.map):
        print('File {0} does not exist.'.format(args.mine))
        sys.exit(1)
    if not os.path.isfile(args.project):
        print('DM Environment File {0} does not exist.'.format(args.project))
        sys.exit(1)

    dmm = Map(forgiving_atom_lookups=True)
    dmm.Load(args.map, format='dmm')

    fmt = DMMFormat(dmm)

    context = None
    added = 0
    removed = 0

    currentpatch = ''

    def changeMarker(ln):
        a = Atom('/obj/effect/byondtools/changed')
        a.setProperty('tag',
                      '{}:{}'.format(currentpatch, ln),
                      flags=PropertyFlags.MAP_SPECIFIED)
        return a

    def printReport(context, added, removed):
        if context is not None:
            x, y, z = context
            print(' Z={} +{} -{}'.format(z, added, removed))

    REG_INSTRUCTION = re.compile(
        r'^(?P<change>[\+\-])(?P<amount>[0-9\*]+)?\s+(?P<atom>/.*)')

    for i in range(len(args.patches[0])):
        patch = args.patches[0][i]
        print('* Applying {}...'.format(patch))
        currentpatch = patch
        with open(patch) as f:
            ln = 0
            lz = -1
            skip_block = False
            for line in f:
                ln += 1
                line = line.strip()
                if line == '': continue
                if line.startswith('#'): continue
                if line.startswith('<') and line.endswith('>'):
                    strcoords = line.strip('<>').split(',')
                    newcoords = []
                    for coord in strcoords:
                        newcoords += [int(coord)]
                    if context is not None and lz != context[2]:
                        printReport(context, added, removed)
                        lz = context[2]
                        added = removed = 0
                    context = newcoords
                    skip_block = False
                    continue
                if line.startswith('@') and not skip_block:
                    # @CHECK before-hash after-hash atoms-block

                    x, y, z = context

                    if line.startswith('@CHECK'):
                        _, beforehash, afterhash, serdata = line.split(' ', 3)

                        if args.clobber:
                            #print('WARNING: <{},{},{}> has changed and will be overwritten. (--clobber)'.format(x, y, z))
                            t = fmt.consumeTileChunk(serdata, cache=False)
                            t.AppendAtom(changeMarker(ln))
                            dmm.SetTileAt(x, y, z, t)
                            skip_block = True
                            continue
                        curhash = dmm.GetTileAt(x, y, z).GetHash()
                        if afterhash == curhash:
                            print(
                                'Skipping <{},{},{}> (already what we expected)'
                                .format(x, y, z))
                            skip_block = True
                            continue
                        #else: print('PRE {} != {}: OK'.format(curhash,afterhash))
                        if beforehash != curhash:
                            print(
                                'WARNING: <{},{},{}> has changed.  Operations on this tile may not be accurate!'
                                .format(x, y, z))
                            continue
                        #else: print('OLD {} == {}: OK'.format(curhash,beforehash))

                if not skip_block and (line.startswith('+')
                                       or line.startswith('-')):
                    if line == '-ALL':
                        dmm.SetTileAt(x, y, z, dmm.CreateTile())
                        continue
                    m = REG_INSTRUCTION.match(line)
                    if m is None:
                        print('{}:{}: MALFORMED INSTRUCTION: {}'.format(
                            args.patch, ln, line))
                        sys.exit(1)
                    amount = m.group('amount')
                    if amount == '*':
                        amount = 9999
                    else:
                        amount = int(m.group('amount') or 1)
                    change = m.group('change')

                    atom = fmt.consumeAtom(m.group('atom'), ln)
                    atom.filename = args.patch
                    atom.line = ln
                    if atom is None:
                        print(
                            '{}:{}: WARNING: Unable to parse instance specified by chunk {}'
                            .format(args.patch, ln, m.group('atom')))
                        continue

                    x, y, z = context
                    if x == 0 and y == 0 and z == 0:
                        print('WE AT <0,0,0> SOMEFIN WRONG')

                    if z >= len(dmm.zLevels): continue

                    tile = dmm.GetTileAt(x, y, z)
                    if change == '-':
                        for _ in range(amount):
                            if tile.CountAtom(atom) > 0:
                                tile.RemoveAtom(atom, hash=False)
                                removed += 1
                            else:
                                break
                    elif change == '+':
                        for _ in range(amount):
                            tile.AppendAtom(atom, hash=False)
                        added += amount
                    tile.UpdateHash()
                    # dmm.SetTileAt(x, y, z, tile)
                    # print('{} - {}'.format((x,y,z),tile))
            printReport(context, added, removed)

    print('Saving...')
    dmm.Save(args.output if args.output else args.map)
コード例 #8
0
 def setUp(self):
     from byond.map.format.dmm import DMMFormat
     from byond.map import Map
     self.map = Map()
     self.dmm = DMMFormat(self.map)
コード例 #9
0
class MapParserTest(unittest.TestCase):
    def setUp(self):
        from byond.map.format.dmm import DMMFormat
        from byond.map import Map
        self.map = Map()
        self.dmm = DMMFormat(self.map)

    def test_basic_SplitAtoms_operation(self):
        testStr = '/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area'
        expectedOutput = [
            '/obj/effect/landmark{name = "carpspawn"}',
            '/obj/structure/lattice', '/turf/space', '/area'
        ]

        out = self.dmm.SplitAtoms(testStr)
        self.assertListEqual(out, expectedOutput)

    def test_basic_SplitProperties_operation(self):
        testStr = 'd1 = 1; d2 = 2; icon_state = "1-2"; tag = ""'
        expectedOutput = [
            'd1 = 1', ' d2 = 2', ' icon_state = "1-2"', ' tag = ""'
        ]

        out = self.dmm.SplitProperties(testStr)
        self.assertListEqual(out, expectedOutput)

    def test_basic_consumeTile_operation(self):
        from byond.map import Map, Tile
        '''
        "aaK" = (
            /obj/structure/cable{
                d1 = 1;
                d2 = 2; 
                icon_state = "1-2";
                tag = ""
            },
            /obj/machinery/atmospherics/pipe/simple/supply/hidden{
                dir = 4
            },
            /turf/simulated/floor{
                icon_state = "floorgrime"
            },
            /area/security/prison
        )
        '''
        testStr = '"aaK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison)'
        testSerData = '/obj/structure/cable{d1=1;d2=2;icon_state="1-2";tag=""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir=4},/turf/simulated/floor{icon_state="floorgrime"},/area/security/prison{}'

        out = self.dmm.consumeTile(testStr, False)  # :type out: Tile
        #print('IIDs: {0}'.format(repr(out.instances)))

        self.assertEquals(out.origID, 'aaK', 'origID')
        self.assertEquals(len(out.instances), 4, 'instances size')
        self.assertEquals(len(out.GetAtom(0).properties), 4,
                          'instances[0] properties')
        self.assertIn('d1',
                      out.GetAtom(0).properties,
                      'd1 not present in properties')
        self.assertListEqual(
            out.GetAtom(0).mapSpecified, ['d1', 'd2', 'icon_state', 'tag'])

        self.assertEquals(
            len(out.GetAtom(2).properties), 1,
            'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}'
        )
        self.assertIn(
            'icon_state',
            out.GetAtom(2).properties,
            'Failure to parse /turf/simulated/floor{icon_state = "floorgrime"}'
        )

        self.assertEqual(out._serialize(), testSerData)

    def _show_expected_vs_actual(self, expected, actual):
        if expected != actual:
            print(' > EXPECTED: {}'.format(expected))
            print(' > ACTUAL:   {}'.format(actual))

    def test_basic_SerializeTile_operation(self):
        from byond.map import Map, Tile
        '''
        "aaK" = (
            /obj/structure/cable{
                d1 = 1;
                d2 = 2; 
                icon_state = "1-2";
                tag = ""
            },
            /obj/machinery/atmospherics/pipe/simple/supply/hidden{
                dir = 4
            },
            /turf/simulated/floor{
                icon_state = "floorgrime"
            },
            /area/security/prison
        )
        '''
        testStr = '"aaK" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/floor{icon_state = "floorgrime"},/area/security/prison)'
        expected = testStr.split('=', 1)[1].strip()
        tile = self.dmm.consumeTile(testStr, False)  # :type tile: Tile
        out = self.dmm.SerializeTile(tile)
        self._show_expected_vs_actual(expected, out)
        self.assertEqual(out, expected)

    def test_consumeTile_secureArea(self):
        '''
        "aai" = (
            /obj/structure/sign/securearea{
                desc = "A warning sign which reads \'HIGH VOLTAGE\'"; 
                icon_state = "shock"; 
                name = "HIGH VOLTAGE"; 
                pixel_y = -32
            },
            /turf/space,
            /area
        )
        '''
        testStr = '"aai" = (/obj/structure/sign/securearea{desc = "A warning sign which reads \'HIGH VOLTAGE\'"; icon_state = "shock"; name = "HIGH VOLTAGE"; pixel_y = -32},/turf/space,/area)'

        tile = self.dmm.consumeTile(testStr, False)  # :type tile: Tile

        self.assertEquals(tile.origID, 'aai', 'origID')
        self.assertEquals(len(tile.instances), 3, 'instances size')
        self.assertEquals(len(tile.GetAtom(0).properties), 4,
                          'instances[0] properties')
        self.assertIn('desc',
                      tile.GetAtom(0).properties,
                      'desc not present in properties')
        self.assertListEqual(
            tile.GetAtom(0).mapSpecified,
            ['desc', 'icon_state', 'name', 'pixel_y'])

        expected = testStr.split('=', 1)[1].strip()
        out = self.dmm.SerializeTile(tile)
        self._show_expected_vs_actual(expected, out)
        self.assertEqual(out, expected)

    def test_consumeTile_landmark(self):
        testStr = '"aah" = (/obj/effect/landmark{name = "carpspawn"},/obj/structure/lattice,/turf/space,/area)'
        testSerData = '/obj/effect/landmark{name="carpspawn"},/obj/structure/lattice{},/turf/space{},/area{}'
        out = self.dmm.consumeTile(testStr)
        self.assertEqual(out._serialize(), testSerData)
コード例 #10
0
ファイル: MapParser.py プロジェクト: PsiOmegaDelta/ByondTools
 def setUp(self):
     from byond.map.format.dmm import DMMFormat
     self.dmm = DMMFormat()