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)
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)
def setUp(self): from byond.map.format.dmm import DMMFormat from byond.map import Map self.map = Map() self.dmm = DMMFormat(self.map)
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)
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']))
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)
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)
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)
def setUp(self): from byond.map.format.dmm import DMMFormat self.dmm = DMMFormat()