Yeah fuck this tools folder, installed BYONDtools directly into python instead.

This commit is contained in:
ZomgPonies
2014-06-21 05:33:32 -04:00
parent 3d742adb94
commit 057ed20173
92 changed files with 0 additions and 35061 deletions
-7
View File
@@ -1,7 +0,0 @@
*.pyc
/doc/_build
*.bak
/.tox
/BYONDTools.egg-info
/build
/dist
-17
View File
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ByondTools</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
-20
View File
@@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Rob "N3X15" Nelson
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-30
View File
@@ -1,30 +0,0 @@
OpenByond
=========
A set of tools for BYOND-based games.
Overview
--------
This is a toolkit for developers of BYOND-based games intended to do common, complex
tasks that the engine itself does not currently possess. It also exposes common
interfaces for developers wishing to obtain information from the BYOND object tree,
maps, and DMIs.
Requirements
------------
* Python 2.7+
* Python Imaging Library (PIL)
* numpy
Use
---
Each script has documentation in its code at the top of each file.
Support
-------
No commercial or official support is provided, but you are free to
submit bug reports or harass N3X15 in irc.rizon.net #vgstation.
-142
View File
@@ -1,142 +0,0 @@
from byond import directions
from PIL import Image
import logging
class State:
# So we don't overwrite the static state.
MovementTag = 'M'
def __init__(self, nm):
self.name = nm
self.hotspot = ''
self.frames = 0
self.dirs = 1
self.movement = 0
self.loop = 0
self.rewind = 0
self.delay = []
self.icons = []
self.positions = []
@staticmethod
def MakeKey(name,movement=False):
key = name
tags = ''
if movement:
tags += State.MovementTag
if tags != '':
key += '\t' + tags
return key
def genManifest(self):
'''
state = "void"
dirs = 4
frames = 4
delay = 2,2,2,2
'''
o = '\r\nstate = "{0}"'.format(self.name)
o += self.genManifestLine('hotspot', self.hotspot, '')
o += self.genManifestLine('frames', self.frames, -1)
o += self.genManifestLine('dirs', self.dirs, -1)
o += self.genManifestLine('movement', self.movement, 0)
o += self.genManifestLine('loop', self.loop, 0)
o += self.genManifestLine('rewind', self.rewind, 0)
o += self.genManifestLine('delay', self.delay, [])
return o
# Mostly for movement states.
def displayName(self):
tags=[]
if self.movement:
tags += self.MovementTag
if len(tags)>0:
return '{} ({})'.format(self.name,', '.join(tags))
return self.name
def genDMIH(self):
o = '\r\nstate "%s" {' % self.name
o += self.genDMIHLine('hotspot', self.hotspot, '')
o += self.genDMIHLine('frames', self.frames, -1)
tdirs = 'ONE'
if self.dirs == 4:
tdirs = 'CARDINAL'
elif self.dirs == 8:
tdirs = 'ALL'
o += self.genDMIHLine('dirs', tdirs, '')
o += self.genDMIHLine('movement', self.movement, 0)
o += self.genDMIHLine('loop', self.loop, 0)
o += self.genDMIHLine('rewind', self.rewind, 0)
o += self.genDMIHLine('delay', self.delay, [])
o += '\n\timport pngs {'
for vdir in range(self.dirs):
_dir = directions.IMAGE_INDICES[vdir]
o += '\n\t\tdirection "%s" {' % directions.getNameFromDir(_dir)
for f in range(self.frames):
o += '\n\t\t\t"%s"' % self.getFrame(_dir, f)
o += '\n\t\t}'
o += '\n\t}'
o += "\n}"
return o
def key(self):
return State.MakeKey(self.name, movement=self.movement==1)
def genDMIHLine(self, name, value, default):
if value != default:
if type(value) is list:
value = ','.join(value)
return '\n\t{0} = {1}'.format(name, value)
return ''
def genManifestLine(self, name, value, default):
if value != default:
if type(value) is list:
value = ','.join(value)
return '\n\t{0} = {1}'.format(name, value)
return ''
def ToString(self):
o = '%s: %d frames, ' % (self.name, self.frames)
o += '%d directions' % self.dirs
# o += ' icons: ' + repr(self.icons)
return o
def numIcons(self):
return self.frames * self.dirs
def getFrameIndex(self, direction, frame):
_dir = 0
if self.dirs == 4 or self.dirs == 8:
_dir = directions.IMAGE_INDICES.index(direction)
if self.dirs == 4 and _dir > 3:
_dir = 0
frame = _dir + (frame * self.dirs)
if frame > len(self.icons):
logging.warn('Only {} icons in state, args {{dir:{}, frame:{}}}: {}'.format(len(self.icons), direction, frame, self.ToString()))
return frame
def getFrame(self, direction, frame):
return self.icons[self.getFrameIndex(direction, frame)]
def setFrame(self, direction, frame, img):
fi = self.getFrameIndex(direction, frame)
if len(self.icons) < fi:
shouldBeSize = 1
if fi > 7:
logging.error('Unable to set frame: State uninitialized with that many frames.')
return
elif fi > 3:
shouldBeSize = 8
elif fi > 0:
shouldBeSize = 4
while len(self.icons) < shouldBeSize:
self.icons.append(Image.new('RGBA', (32, 32)))
logging.warn('{0} now has {1} frames.'.format(self.name, len(self.icons)))
self.icons[fi] = img
def postProcess(self):
# So old I forgot what everything did.
return
-379
View File
@@ -1,379 +0,0 @@
import sys, os, glob, string, traceback, fnmatch, math, shutil, collections
from PIL import Image, PngImagePlugin
from .State import State
from byond.DMIH import *
import logging
class DMILoadFlags:
NoImages = 1
NoPostProcessing = 2
class DMI:
MovementTag = '\t'
def __init__(self, filename):
self.filename = filename
self.version = ''
self.states = collections.OrderedDict() # {}
self.icon_width = 32
self.icon_height = 32
self.pixels = None
self.size = ()
self.statelist = 'LOLNONE'
self.max_x = -1
self.max_y = -1
self.img = None
def make(self, makefile):
print('>>> Compiling %s -> %s' % (makefile, self.filename))
h = DMIH()
h.parse(makefile)
for node in h.tokens:
if type(node) is Variable:
if node.name == 'height':
self.icon_height = node.value
elif node.name == 'weight':
self.icon_width = node.value
elif type(node) is directives.State:
self.states[node.state.key()] = node.state
elif type(node) is directives.Import:
if node.ftype == 'dmi':
dmi = DMI(node.filedef)
dmi.extractTo("_tmp/" + os.path.basename(node.filedef))
for name in dmi.states:
self.states[name] = dmi.states[name]
def save(self, to, **kwargs):
if len(self.states) == 0:
return # Nope.
# Now build the manifest
manifest = '#BEGIN DMI'
manifest += '\nversion = 4.0'
manifest += '\n\twidth = {0}'.format(self.icon_width)
manifest += '\n\theight = {0}'.format(self.icon_height)
frames = []
fdata = []
# Sort by name because I'm autistic like that.
ordered = self.states
if kwargs.get('sort', True):
ordered = sorted(self.states.keys())
for name in ordered:
if len(self.states[name].icons) > 0:
manifest += self.states[name].genManifest()
numIcons = self.states[name].numIcons()
lenIcons = len(self.states[name].icons)
if numIcons != lenIcons:
logging.warn('numIcons={0}, len(icons)={1} in state {2}!'.format(numIcons, lenIcons, name))
# frames += self.states[name].icons
# frames.extend(self.states[name].icons)
for i in range(len(self.states[name].icons)):
fdata += ['{}[{}]'.format(self.states[name].name, i)]
frames += [self.states[name].icons[i]]
else:
logging.warn('State {0} has 0 icons.'.format(name))
manifest += '\n#END DMI'
# print(manifest)
# Next bit borrowed from DMIDE.
icons_per_row = math.ceil(math.sqrt(len(frames)))
rows = icons_per_row
if len(frames) > icons_per_row * rows:
rows += 1
sheet = Image.new('RGBA', (int((icons_per_row + 1) * self.icon_width), int(rows * self.icon_height)))
x = 0
y = 0
# for frame in frames:
# print('per_row={0}, rows={1}, size={2}'.format(icons_per_row,rows,sheet.size))
for f in range(len(frames)):
frame = frames[f]
icon = frame
if isinstance(frame, str):
icon = Image.open(frame, 'r')
box = (x * self.icon_width, y * self.icon_height)
# print('{0} -> ({1},{2}) {3} {4}'.format(f,x,y,box,fdata[f]))
sheet.paste(icon, box, icon)
x += 1
if x > icons_per_row:
y += 1
x = 0
# More borrowed from DMIDE:
# undocumented class
meta = PngImagePlugin.PngInfo()
# copy metadata into new object
reserved = ('interlace', 'gamma', 'dpi', 'transparency', 'aspect')
for k, v in sheet.info.items():
if k in reserved: continue
meta.add_text(k, v, 1)
# Only need one - Rob
meta.add_text(b'Description', manifest.encode('ascii'), 1)
# and save
sheet.save(to, 'PNG', pnginfo=meta)
# with open(to+'.txt','w') as f:
# f.write(manifest)
# logging.info('>>> {0} states saved to {1}'.format(len(frames), to))
def getDMIH(self):
o = '# DMI Header 1.0 - Generated by DMI.py'
o += self.genDMIHLine('width', self.icon_width, -1)
o += self.genDMIHLine('height', self.icon_height, -1)
for s in sorted(self.states):
o += self.states[s].genDMIH()
return o
def genDMIHLine(self, name, value, default):
if value != default:
if type(value) is list:
value = ','.join(value)
return '\n{0} = {1}'.format(name, value)
return ''
def extractTo(self, dest, suppress_post_process=False):
flags = 0
if(suppress_post_process):
flags |= DMILoadFlags.NoPostProcessing
# print('>>> Loading %s...' % self.filename)
self.loadAll(flags)
# print('>>> Extracting %s...' % self.filename)
self.extractAllStates(dest, flags)
def getFrame(self, state, direction, frame, movement=False):
state = State.MakeKey(state,movement=movement)
if state not in self.states:
return None
return self.states[state].getFrame(direction, frame)
def setFrame(self, state, direction, frame, img, movement=False):
state = State.MakeKey(state,movement=movement)
if state not in self.states:
self.states[state] = State(state)
return self.states[state].setFrame(direction, frame, img)
def getHeader(self):
img = Image.open(self.filename)
if(b'Description' not in img.info):
raise Exception("DMI Description is not in the information headers!")
return img.info[b'Description'].decode('ascii')
def setHeader(self, newHeader, dest):
img = Image.open(self.filename)
# More borrowed from DMIDE:
# undocumented class
meta = PngImagePlugin.PngInfo()
# copy metadata into new object
reserved = ('interlace', 'gamma', 'dpi', 'transparency', 'aspect', 'icc_profile')
for k, v in img.info.items():
if k in reserved: continue
# print(k, v)
meta.add_text(k, v, 1)
# Only need one - Rob
meta.add_text(b'Description', newHeader.encode('ascii'), 1)
# and save
img.save(dest + '.tmp', 'PNG', pnginfo=meta)
shutil.move(dest + '.tmp', dest)
def loadMetadata(self, flags=0):
self.load(flags | DMILoadFlags.NoImages)
def loadAll(self, flags=0):
self.load(flags)
def load(self, flags):
self.img = Image.open(self.filename)
# This is a stupid hack to work around BYOND generating indexed PNGs with unspecified transparency.
# Uncorrected, this will result in PIL(low) trying to read the colors as alpha.
if self.img.mode == 'P':
# If there's no transparency, set it to black.
if 'transparency' not in self.img.info:
logging.warn('({0}): Indexed PNG does not specify transparency! Setting black as transparency. self.img.info = {1}'.format(self.filename, repr(self.img.info)))
self.img.info['transparency'] = 0
# Always use RGBA, it causes less problems.
self.img = self.img.convert('RGBA')
self.size = self.img.size
# Sanity
if(b'Description' not in self.img.info):
raise Exception("DMI Description is not in the information headers!")
# Load pixels from image
self.pixels = self.img.load()
# Load DMI header
desc = self.img.info[b'Description'].decode('ascii')
"""
version = 4.0
width = 32
height = 32
state = "fire"
dirs = 4
frames = 1
state = "fire2"
dirs = 1
frames = 1
state = "void"
dirs = 4
frames = 4
delay = 2,2,2,2
state = "void2"
dirs = 1
frames = 4
delay = 2,2,2,2
"""
state = None
x = 0
y = 0
self.statelist = desc
ii = 0
for line in desc.split("\n"):
line = line.strip()
if line.startswith("#"):
continue
if '=' in line:
(key, value) = line.split(' = ')
key = key.strip()
value = value.strip().replace('"', '')
if key == 'version':
self.version = value
elif key == 'width':
self.icon_width = int(value)
self.max_x = self.img.size[0] / self.icon_width
elif key == 'height':
self.icon_height = int(value)
self.max_y = self.img.size[1] / self.icon_height
# print(('%s: {sz: %s,h: %d, w: %d, m_x: %d, m_y: %d}'%(self.filename,repr(img.size),self.icon_height,self.icon_width,self.max_x,self.max_y)))
elif key == 'state':
if state != None:
# print(" + %s" % (state.ToString()))
if(self.icon_width == 0 or self.icon_height == 0):
if(len(self.states) > 0):
raise SystemError("Width and height for each cell are not available.")
else:
self.icon_width = self.img.size[0]
self.max_x = 1
self.icon_height = self.img.size[1]
self.max_y = 1
elif(self.max_x == -1 or self.max_y == -1):
self.max_x = self.img.size[0] / self.icon_width
self.max_y = self.img.size[1] / self.icon_width
for _ in range(state.numIcons()):
state.positions += [(x, y)]
if (flags & DMILoadFlags.NoImages) == 0:
state.icons += [self.loadIconAt(x, y)]
x += 1
# print('%s[%d:%d] x=%d, max_x=%d' % (self.filename,ii,i,x,self.max_x))
if(x >= self.max_x):
x = 0
y += 1
self.states[state.key()] = state
# if not suppress_post_process:
# self.states[state.name].postProcess()
ii += 1
state = State(value)
elif key == 'dirs':
state.dirs = int(value)
elif key == 'frames':
state.frames = int(value)
elif key == 'loop':
state.loop = int(value)
elif key == 'rewind':
state.rewind = int(value)
elif key == 'movement':
state.movement = int(value)
elif key == 'delay':
state.delay = value.split(',')
elif key == 'hotspot':
state.hotspot = value
else:
logging.critical('Unknown key ' + key + ' (value=' + value + ')!')
sys.exit()
self.states[state.name] = state
for _ in range(state.numIcons()):
self.states[state.name].icons += [self.loadIconAt(x, y)]
x += 1
if(x >= self.max_x):
x = 0
y += 1
def extractAllStates(self, dest, flags=0):
for _, state in self.states.iteritems():
# state = State()
for i in xrange(len(state.positions)):
x, y = state.positions[i]
self.extractIconAt(state, dest, x, y, i)
if (flags & DMILoadFlags.NoPostProcessing) == 0:
self.states[state.name].postProcess()
if dest is not None:
outfolder = os.path.join(dest, os.path.basename(self.filename))
nfn = self.filename.replace('.dmi', '.dmih')
valid_chars = "-_.()[] %s%s" % (string.ascii_letters, string.digits)
nfn = ''.join(c for c in nfn if c in valid_chars)
nfn = os.path.join(outfolder, nfn)
with open(nfn, 'w') as dmih:
dmih.write(self.getDMIH())
def loadIconAt(self, sx, sy):
if(self.icon_width == 0 or self.icon_height == 0):
raise SystemError('Image is {}x{}, an invalid size.'.format(self.icon_height, self.icon_width))
# print(" X (%d,%d)"%(sx*self.icon_width,sy*self.icon_height))
icon = Image.new(self.img.mode, (self.icon_width, self.icon_height))
newpix = icon.load()
for y in range(self.icon_height):
for x in range(self.icon_width):
_x = x + (sx * self.icon_width)
_y = y + (sy * self.icon_height)
try:
pixel = self.pixels[_x, _y]
if pixel[3] == 0: continue
newpix[x, y] = pixel
except IndexError:
print("!!! Received IndexError in %s <%d,%d> = <%d,%d> + (<%d,%d> * <%d,%d>), max=<%d,%d> halting." % (self.filename, _x, _y, x, y, sx, sy, self.icon_width, self.icon_height, self.max_x, self.max_y))
print('%s: {sz: %s,h: %d, w: %d, m_x: %d, m_y: %d}' % (self.filename, repr(self.img.size), self.icon_height, self.icon_width, self.max_x, self.max_y))
print('# of cells: %d' % len(self.states))
print('Image h/w: %s' % repr(self.size))
print('--STATES:--')
print(self.statelist)
sys.exit(1)
return icon
def extractIconAt(self, state, dest, sx, sy, i=0):
icon = self.loadIconAt(sx, sy)
outfolder = os.path.join(dest, os.path.basename(self.filename))
if not os.path.isdir(outfolder):
os.makedirs(outfolder)
nfn = "{}[{}].png".format(state.name, i)
valid_chars = "-_.()[] %s%s" % (string.ascii_letters, string.digits)
nfn = ''.join(c for c in nfn if c in valid_chars)
nfn = os.path.join(outfolder, nfn)
if os.path.isfile(nfn):
os.remove(nfn)
try:
icon.save(nfn)
except SystemError as e:
print("Received SystemError, halting: %s" % traceback.format_exc(e))
print('{ih=%d,iw=%d,state=%s,dest=%s,sx=%d,sy=%d,i=%d}' % (self.icon_height, self.icon_width, state.ToString(), dest, sx, sy, i))
sys.exit(1)
return nfn
-9
View File
@@ -1,9 +0,0 @@
class Variable(object):
name=''
value=None
def __init__(self,name,value):
self.name=name
self.value=value
-135
View File
@@ -1,135 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
from . import directives, Variable
valid_symbol_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
class DMIH(object):
"""
# DMI Header 1.0
# ------------------------
height = 32
width = 32
state "AMAZIN' RAISINS" {
dirtype=CARDINAL
frames=5
import pngs {
direction NORTH {
"amazinraisin-N-0.png"
"amazinraisin-N-1.png"
"amazinraisin-N-2.png"
"amazinraisin-N-3.png"
"amazinraisin-N-4.png"
}
direction EAST {
"amazinraisin-E-0.png"
"amazinraisin-E-1.png"
"amazinraisin-E-2.png"
"amazinraisin-E-3.png"
"amazinraisin-E-4.png"
}
direction WEST {
"amazinraisin-W-0.png"
"amazinraisin-W-1.png"
"amazinraisin-W-2.png"
"amazinraisin-W-3.png"
"amazinraisin-W-4.png"
}
direction SOUTH {
"amazinraisin-S-0.png"
"amazinraisin-S-1.png"
"amazinraisin-S-2.png"
"amazinraisin-S-3.png"
"amazinraisin-S-4.png"
}
}
}
# File State orig State new
import dmi "import/ohgodwhy.dmi" "Oh god why" "metroid5"
"""
tokens = []
'''
directive arg1 {block}
'''
directives = {
'direction': directives.Direction.Direction,
'import': directives.Import.Import,
'state': directives.State.State
}
def parse(self, file):
with open(file) as f:
self.tokens = self.parseBlockContents(f)
def readSymbol(self, f):
f.seek(f.tell() - 1) # Back up one char
o = ''
while True:
c = f.read(1)
if c in valid_symbol_chars:
o += c
else:
return o
def readString(self, f, b):
# f.seek(f.tell()-1) # Back up one char
o = ''
while True:
c = f.read(1)
if c == b:
return o
else:
o += c
def parseBlockContents(self, f):
buf = ''
currentBlock = []
memory = []
_in = None
memchanged = False
while True:
b = f.read(1) # .decode('utf-8')
if b in ('"', "'"):
memory += [self.readString(f, b)]
memchanged = True
if b in valid_symbol_chars:
memory += [self.readSymbol(f)]
f.seek(f.tell() - 1) # Back up one char in case we have to deal with a block.
memchanged = True
if b == '=':
memory += ['=']
memchanged = True
if b == '{':
memory += [self.parseBlockContents(f)]
memchanged = True
if b == '}' or b == '': # End of block or end of file.
return currentBlock
if memchanged:
token = None
if len(memory) == 3:
if memory[2] == '=':
token = Variable(memory[0], memory[1])
if len(memory) > 0:
if memory[0] in self.directives:
token = self.directives[memory[0]](memory[0], memory[1:])
if token:
currentBlock += [token]
memory = []
memchanged = False
@@ -1,28 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
from .Directive import Directive
from byond import directions
class Direction(Directive):
'''
Tells the compiler which frames will be used for this direction.
'''
'''
Which direction?
'''
dir=0
'''
List of files.
'''
frames=[]
def __init__(self,name,frames):
Directive.__init__(self, name, [name,frames])
_dir = directions.getDirFromName(name)
if _dir:
self.dir=_dir
self.frames=frames
@@ -1,14 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
class Directive(object):
'''
Base type for directives.
'''
name = ''
def __init__(self,name,args):
self.name=name
@@ -1,50 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
from .Directive import Directive
class Import(Directive):
'''
Tells the compiler to import a file into the DMI.
'''
'''
pngs or dmi.
'''
ftype=''
'''
The file(s) to import into the DMI.
'''
filedef=None
'''
State(s) to import (DMIs)
'''
states={}
def __init__(self,name,params):
Directive.__init__(self,name,params)
self.ftype=params[0]
if self.ftype=='pngs':
self.filedef=params[1]
elif self.ftype=='dmi':
self.filedef=str(params[1])
if type(params[2]) is list:
for sn in params[2]:
self.addState(sn)
elif type(params[2]) is str:
self.addState(params[2])
def addState(self,sn):
oldname=None
newname=None
snp=sn.split('->')
if snp.len == 2:
(oldname, newname)=snp
elif snp.len == 1:
oldname=newname=snp[0]
if oldname and newname:
self.states[oldname]=newname
@@ -1,51 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
from .Directive import Directive
from .Import import Import
from byond.DMI import State
from .. import Variable
directly_assignable={
'hotspot':tuple,
'dirs':int,
'frames':int,
'movement':int,
'loop':int,
'rewind':int,
'delay':tuple
}
class State(Directive):
'''
Tells the compiler to create a state with the specified variables and frames.
'''
'''
The actual state
'''
state = None
imports = []
def __init__(self,name,params):
Directive.__init__(self,name,params)
self.state=State()
if params.len != 2:
raise Exception('state directive requires 2 parameters. state "name" { }')
self.state.name=params[0]
for o in params[1]:
if type(o) is Variable and o.name in directly_assignable:
if o.name == 'dirs':
if o.value == 'CARDINAL':
o.value = 4
elif o.value == 'ALL':
o.value = 8
else:
o.value = 1
setattr(self.state,o.name,directly_assignable[o.name](o.value))
if type(o) is Import:
if o.ftype == 'pngs':
for dirblock in o.filedef:
for i in range(dirblock.frames.len):
self.state.setFrame(dirblock.dir, i, dirblock.frames[i])
@@ -1,4 +0,0 @@
from . import Direction, Directive, Import, State
__all__ = [
Direction, Directive, Import, State
]
-41
View File
@@ -1,41 +0,0 @@
'''
Created on Sep 21, 2013
@author: Rob
'''
import os
from .map import Map, Tile, MapRenderFlags
from .objtree import ObjectTree
def GetFilesFromDME(dmefile='baystation12.dme', ext='.dm'):
filesInDME=[]
rootdir = os.path.dirname(dmefile)
with open(dmefile, 'r') as dmeh:
for line in dmeh:
if line.startswith('#include'):
inString = False
# escaped=False
filename = ''
for c in line:
"""
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
if
escaped = False
continue
"""
if c == '"':
inString = not inString
if not inString:
filepath = os.path.join(rootdir, filename)
if filepath.endswith(ext):
filesInDME += [filepath]
filename = ''
continue
else:
if inString:
filename += c
return filesInDME
-454
View File
@@ -1,454 +0,0 @@
'''
Created on Nov 6, 2013
@author: Rob
'''
# import logging
AREA_LAYER = 1
TURF_LAYER = 2
OBJ_LAYER = 3
MOB_LAYER = 4
FLY_LAYER = 5
import re
from .utils import eval_expr
REGEX_TABS = re.compile('^(?P<tabs>\t*)')
class BYONDValue:
"""
Handles numbers and unhandled types like lists.
"""
def __init__(self, string, filename='', line=0, typepath='/', **kwargs):
#: The actual value.
self.value = string
#: Filename this was found in
self.filename = filename
#: Line of the originating file.
self.line = line
#: Typepath of the value.
self.type = typepath
#: Has this value been inherited?
self.inherited = kwargs.get('inherited', False)
#: Is this a declaration? (/var)
self.declaration = kwargs.get('declaration', False)
#: Anything special? (global, const, etc.)
self.special = kwargs.get('special', None)
#: If a list, what's the size?
self.size = kwargs.get('size', None)
def copy(self):
'''Make a clone of this without dangling references.'''
return BYONDValue(self.value, self.filename, self.line, self.type, declaration=self.declaration, inherited=self.inherited, special=self.special)
def __str__(self):
return '{0}'.format(self.value)
def __repr__(self):
return '<BYONDValue value="{}" filename="{}" line={}>'.format(self.value, self.filename, self.line)
def DumpCode(self, name):
'''
Try to dump valid BYOND code for this variable.
.. :param name: The name of this variable.
'''
decl = []
if self.declaration:
decl += ['var']
if self.type != '/' and self.declaration:
decl += self.type.split('/')[1:]
decl += [name]
constructed = '/'.join(decl)
if self.value is not None:
constructed += ' = {0}'.format(str(self))
return constructed
class BYONDFileRef(BYONDValue):
"""
Just to format file references differently.
"""
def __init__(self, string, filename='', line=0, **kwargs):
BYONDValue.__init__(self, string, filename, line, '/icon', **kwargs)
def copy(self):
return BYONDFileRef(self.value, self.filename, self.line, declaration=self.declaration, inherited=self.inherited, special=self.special)
def __str__(self):
return "'{0}'".format(self.value)
def __repr__(self):
return '<BYONDFileRef value="{}" filename="{}" line={}>'.format(self.value, self.filename, self.line)
class BYONDString(BYONDValue):
"""
Correctly formats strings.
"""
def __init__(self, string, filename='', line=0, **kwargs):
BYONDValue.__init__(self, string, filename, line, '/', **kwargs)
def copy(self):
return BYONDString(self.value, self.filename, self.line, declaration=self.declaration, inherited=self.inherited, special=self.special)
def __str__(self):
return '"{0}"'.format(self.value)
def __repr__(self):
return '<BYONDString value="{}" filename="{}" line={}>'.format(self.value, self.filename, self.line)
class PropertyFlags:
'''Collection of flags that affect :func:`Atom.setProperty` behavior.'''
#: Property being set should be saved to the map
MAP_SPECIFIED = 1
#: Property being set should be handled as a string
STRING = 2
#: Property being set should be handled as a file reference
FILEREF = 4
#: Property being set should be handled as a value
VALUE = 8
class Atom:
'''
An atom is, in simple terms, what BYOND considers a class.
:param string path:
The absolute path of this atom. ex: */obj/item/weapon/gun*
:param string filename:
The file this atom originated from.
:param int line:
The line in the aforementioned file.
'''
#: Prints all inherited properties, not just the ones that are mapSpecified.
FLAG_INHERITED_PROPERTIES = 1
#: writeMap2 prints old_ids instead of the actual IID.
FLAG_USE_OLD_ID = 2
def __init__(self, path, filename='', line=0, **kwargs):
global TURF_LAYER, AREA_LAYER, OBJ_LAYER, MOB_LAYER
#: Absolute path of this atom
self.path = path
#: Vars of this atom, including inherited vars.
self.properties = {}
#: List of var names that were specified by the map, if atom was loaded from a :class:`byond.map.Map`.
self.mapSpecified = []
#: Child atoms and procs.
self.children = {}
#: The parent of this atom.
self.parent = None
#: The file this atom originated from.
self.filename = filename
#: Line from the originating file.
self.line = line
#: Instance ID (maps only). Used internally, do NOT change.
self.id = None
#: Instance ID that was read from the map.
self.old_id = None
#: Used internally.
self.ob_inherited=False
#: Loaded from map, but missing in the code. (Maps only)
self.missing=kwargs.get('missing',False)
#if not self.missing and path == '/area/engine/engineering':
# raise Exception('God damnit')
def copy(self):
'''
Make a copy of this atom, without dangling references.
:returns byond.basetypes.Atom
'''
new_node = Atom(self.path,self.filename,self.line,missing=self.missing)
new_node.properties = self.properties.copy()
new_node.mapSpecified = self.mapSpecified
new_node.id = self.id
new_node.old_id = self.old_id
# new_node.parent = self.parent
return new_node
def getProperty(self, index, default=None):
'''
Get the value of the specified property.
:param string index:
The name of the var we want.
:param mixed default:
Default value, if the var cannot be found.
:returns:
The desired value.
'''
prop = self.properties.get(index, None)
if prop == None:
return default
elif prop == 'null':
return None
return prop.value
def setProperty(self, index, value, flags=0):
'''
Set the value of a property.
In the event the property cannot be found, a new property is added.
This function will attempt to convert python types to BYOND types.
Hints can be provided in the form of PropertyFlags given to *flags*.
:param string index:
The name of the var desired.
:param mixed value:
The new value.
:param int flags:
Changes value assignment behavior.
+------------------------------------+------------------------------------------------+
| Flag | Effect |
+====================================+================================================+
| :attr:`PropertyFlag.MAP_SPECIFIED` | Adds the property to *mapSpecified*, if needed.|
+------------------------------------+------------------------------------------------+
| :attr:`PropertyFlag.STRING` | Forces conversion of value to a BYONDString. |
+------------------------------------+------------------------------------------------+
| :attr:`PropertyFlag.FILEREF` | Forces conversion of value to a BYONDFileRef. |
+------------------------------------+------------------------------------------------+
| :attr:`PropertyFlag.VALUE` | Forces conversion of value to a BYONDValue. |
+------------------------------------+------------------------------------------------+
:returns:
The desired value.
'''
if flags & PropertyFlags.MAP_SPECIFIED:
if index not in self.mapSpecified:
self.mapSpecified += [index]
if flags & PropertyFlags.VALUE:
self.properties[index] = BYONDValue(value)
elif isinstance(value, str) or flags & PropertyFlags.STRING:
if flags & PropertyFlags.STRING:
value = str(value)
self.properties[index] = BYONDString(value)
elif flags & PropertyFlags.FILEREF:
if flags & PropertyFlags.FILEREF:
value = str(value)
self.properties[index] = BYONDFileRef(value)
else:
self.properties[index] = BYONDValue(value)
def InheritProperties(self):
if self.ob_inherited: return
#debugInheritance=self.path in ('/area','/obj','/mob','/atom/movable','/atom')
if self.parent:
if not self.parent.ob_inherited:
self.parent.InheritProperties()
for key in sorted(self.parent.properties.keys()):
value = self.parent.properties[key].copy()
if key not in self.properties:
self.properties[key] = value
self.properties[key].inherited = True
#if debugInheritance:print(' {0}[{2}] -> {1}'.format(self.parent.path,self.path,key))
#assert 'name' in self.properties
self.ob_inherited=True
for k in self.children.iterkeys():
self.children[k].InheritProperties()
def __ne__(self, atom):
return not self.__eq__(atom)
def __eq__(self, atom):
if atom == None:
return False
if self.mapSpecified != atom.mapSpecified:
return False
if self.path != atom.path:
return False
return self.properties == atom.properties
def handle_math(self,expr):
if isinstance(expr,str):
return eval_expr(expr)
return expr
def __lt__(self, other):
if 'layer' not in self.properties or 'layer' not in other.properties:
return False
myLayer = 0
otherLayer = 0
try:
myLayer = self.handle_math(self.getProperty('layer',myLayer))
except ValueError:
print('Failed to parse {0} as float.'.format(self.properties['layer'].value))
pass
try:
otherLayer = self.handle_math(other.getProperty('layer',otherLayer))
except ValueError:
print('Failed to parse {0} as float.'.format(other.properties['layer'].value))
pass
return myLayer > otherLayer
def __gt__(self, other):
if 'layer' not in self.properties or 'layer' not in other.properties:
return False
myLayer = 0
otherLayer = 0
try:
myLayer = self.handle_math(self.getProperty('layer',myLayer))
except ValueError:
print('Failed to parse {0} as float.'.format(self.properties['layer'].value))
pass
try:
otherLayer = self.handle_math(other.getProperty('layer',otherLayer))
except ValueError:
print('Failed to parse {0} as float.'.format(other.properties['layer'].value))
pass
return myLayer < otherLayer
def MapSerialize(self, flags=0):
atomContents = []
# print(repr(self.mapSpecified))
if (flags & Atom.FLAG_INHERITED_PROPERTIES):
for key, val in self.properties.items():
atomContents += ['{0} = {1}'.format(key, val)]
else:
for i in range(len(self.mapSpecified)):
key = self.mapSpecified[i]
if key in self.properties:
val = self.properties[key]
atomContents += ['{0} = {1}'.format(key, val)]
if len(atomContents) > 0:
return self.path + '{' + '; '.join(atomContents) + '}'
else:
return self.path
def dumpPropInfo(self, name):
o = '{0}: '.format(name)
if name not in self.properties:
return o + 'None'
return o + repr(self.properties[name])
def _DumpCode(self):
divider = '//' + ((len(self.path) + 2) * '/') + '\n'
o = divider
o += '// ' + self.path + '\n'
o += divider
o += self.path + '\n'
# o += '\t//{0} properties total\n'.format(len(self.properties))
for name in sorted(self.properties.keys()):
prop = self.properties[name]
if prop.inherited: continue
_type = prop.type
if not _type.endswith('/'):
_type += '/'
prefix = ''
if prop.declaration:
prefix = 'var'
if not prop.declaration: # and _type == '/':
_type = ''
o += '\t{prefix}{type}{name}'.format(prefix=prefix, type=_type, name=name)
if prop.value is not None:
o += ' = {value}'.format(value=str(prop))
o += '\n'
# o += '\n'
# o += '\t//{0} children total\n'.format(len(self.children))
procs = ''
children = ''
for ck in sorted(self.children.keys()):
co = '\n'
co += self.children[ck]._DumpCode()
if isinstance(self.children[ck], Proc):
procs += co
else:
children += co
o += procs + children
return o
def DumpCode(self):
return self._DumpCode()
class Proc(Atom):
def __init__(self, path, arguments, filename='', line=0):
Atom.__init__(self, path, filename, line)
self.name = self.figureOutName(self.path)
self.arguments = arguments
self.code = [] # (indent, line)
self.definition = False
self.origpath = ''
def figureOutName(self,path):
name = path.split('(')[0]
return name.split('/')[-1]
def CountTabs(self, line):
m = REGEX_TABS.match(line)
if m is not None:
return len(m.group('tabs'))
return 0
def AddCode(self, indentLevel, line):
self.code += [(indentLevel, line)]
def AddBlankLine(self):
if len(self.code) > 0 and self.code[-1][1] == '':
return
self.code += [(0, '')]
def MapSerialize(self, flags=0):
return None
def InheritProperties(self):
return
def getMinimumIndent(self):
# Find minimum indent level
for i in range(len(self.code)):
indent, _ = self.code[i]
if indent == 0: continue
return indent
return 0
def _DumpCode(self):
args = self.path[self.path.index('('):]
true_path = self.path[:self.path.index('(')].split('/')
name = true_path[-1]
true_path = true_path[:-1]
if self.definition:
true_path += ['proc']
true_path += [name + args]
o = '\n' + '/'.join(true_path) + '\n'
min_indent = self.getMinimumIndent()
# Should be 1, so find the difference.
indent_delta = 1 - min_indent
# o += '\t// true_path = {0}\n'.format(repr(true_path))
# o += '\t// name = {0}\n'.format(name)
# o += '\t// args = {0}\n'.format(args)
# o += '\t// definition = {0}\n'.format(self.definition)
# o += '\t// path = {0}\n'.format(self.path[:self.path.index('(')])
# o += '\t// origpath = {0}\n'.format(self.origpath)
# o += '\t// min_indent = {0}\n'.format(min_indent)
# o += '\t// indent_delta = {0}\n'.format(indent_delta)
for i in range(len(self.code)):
indent, code = self.code[i]
indent = max(1, indent + indent_delta)
if code == '' and i == len(self.code) - 1:
continue
if code.strip() == '':
o += '\n'
else:
o += (indent * '\t') + code.strip() + '\n'
return o
-47
View File
@@ -1,47 +0,0 @@
'''
Created on Feb 23, 2013
@author: Rob
'''
import sys
# NORTH, SOUTH, EAST, and WEST are just #define statements built in DM.
# They represent 1, 2, 4, and 8
NORTH = 1
SOUTH = 2
EAST = 4
WEST = 8
IMAGE_INDICES=[
SOUTH,
NORTH,
EAST,
WEST,
(SOUTH|EAST),
(SOUTH|WEST),
(NORTH|EAST),
(NORTH|WEST)
]
def getDirFromName(name):
return getattr(sys.modules[__name__],name,None)
def getNameFromDir(_dir):
if _dir == NORTH:
return 'NORTH'
elif _dir == SOUTH:
return 'SOUTH'
elif _dir == EAST:
return 'EAST'
elif _dir == WEST:
return 'WEST'
elif _dir == (NORTH|WEST):
return 'NORTHWEST'
elif _dir == (NORTH|EAST):
return 'NORTHEAST'
elif _dir == (SOUTH|EAST):
return 'SOUTHEAST'
elif _dir == (SOUTH|WEST):
return 'SOUTHWEST'
else:
return 'UNKNOWN (%d)' %_dir
File diff suppressed because it is too large Load Diff
@@ -1,35 +0,0 @@
import logging, glob, os, sys
from .base import MapFix, GetDependencies
def Load():
print('Loading MapFix Modules...')
for f in glob.glob(os.path.dirname(__file__) + "/*.py"):
modName = 'mapfixes.' + os.path.basename(f)[:-3]
print(' Loading module ' + modName)
mod = __import__(modName)
for attr in dir(mod):
if not attr.startswith('_'):
#print(' {} = {}'.format(attr,getattr(mod, attr)))
globals()[attr] = getattr(mod, attr)
def GetFixesForNS(namespaces, load_dependencies=True):
selected = [None] + namespaces
depends = GetDependencies()
if load_dependencies:
changed = True
while changed:
changed = False
for cat in selected:
if cat is None: continue # Global namespace is always needed.
print('Checking dependencies for {}...'.format(cat))
if cat in depends:
for newcat in depends[cat]:
if newcat not in selected:
print('Selected dependency {} (required by {})'.format(newcat,cat))
selected += [newcat]
changed = True
o = []
for cat in selected:
for _, val in MapFix.all[cat].items():
o += [val()]
return o
-150
View File
@@ -1,150 +0,0 @@
'''
Global BYOND fixes and matchers
@author: Rob
'''
import logging
from byond.basetypes import BYONDString, BYONDValue
# from byond.directions import *
# Decorator
class MapFix(object):
all = {}
def __init__(self, category, _id=None):
self.id = _id
self.category = category
def __call__(self, c):
if self.id is None:
fname_p = c.__name__
self.id = fname_p
print('Adding MapFix {0}-{1}.'.format(self.category, self.id))
if self.category not in MapFix.all:
MapFix.all[self.category] = {}
MapFix.all[self.category][self.id] = c
return c
_dependencies = {}
def DeclareDependencies(dependee, dependencies):
if dependee not in _dependencies:
_dependencies[dependee] = []
_dependencies[dependee] += dependencies
print(' Dependencies: {}'.format(dependencies))
def GetDependencies():
return _dependencies
class Matcher:
def Matches(self, atom):
return False
def Fix(self, atom):
return atom
def SetTree(self, tree):
self.tree = tree
@MapFix(None)
class NukeTags(Matcher):
def __init__(self):
pass
def Matches(self, atom):
return 'tag' in atom.properties and 'tag' in atom.mapSpecified
def Fix(self, atom):
atom.mapSpecified.remove('tag')
return atom
def __str__(self):
return 'Removed tag'
class RenameProperty(Matcher):
'''
Generic property renamer.
'''
def __init__(self, old, new):
self.old = old
self.new = new
self.removed = False
def Matches(self, atom):
if self.old in atom.properties and self.old in atom.mapSpecified:
return True
return False
def Fix(self, atom):
if self.new not in atom.properties: # Defer to the correct one if both exist.
atom.properties[self.new] = atom.properties[self.old]
if self.old in atom.mapSpecified:
if self.new not in atom.mapSpecified:
atom.mapSpecified += [self.new]
else:
self.removed = True
atom.mapSpecified.remove(self.old)
del atom.properties[self.old]
return atom
def __str__(self):
if self.removed:
return 'Removed {0}'.format(self.old)
else:
return 'Renamed {0} to {1}'.format(self.old, self.new)
class ChangeType(Matcher):
def __init__(self, old, new, forcetype=False, fuzzy=False):
self.old = old
self.new = new
self.forcetype = forcetype
self.fuzzy = fuzzy
def Matches(self, atom):
matches = False
if self.fuzzy:
matches = atom.path.startswith(self.old)
if matches:
self.new += atom.path[len(self.old):]
self.old = atom.path
#print('{} -> {}'.format(self.old,self.new))
else:
matches = self.old == atom.path
if matches:
if atom.missing:
return True
else:
logging.warn('[{}] Found type, but marked not missing: {}'.format(self.__class__.__name__,atom.path))
logging.warn('{}:{}: Target type found here'.format(atom.filename, atom.line))
return False
def Fix(self, atom):
atom.path = self.new
return atom
def __str__(self):
return 'Change type from {0} to {1}'.format(self.old, self.new)
@MapFix(None)
class FixStepX(RenameProperty):
def __init__(self):
RenameProperty.__init__(self, 'step_x', 'pixel_x')
@MapFix(None)
class FixStepY(RenameProperty):
def __init__(self):
RenameProperty.__init__(self, 'step_y', 'pixel_y'),
@MapFix(None)
class RepairDirections(Matcher):
def __init__(self):
pass
def Matches(self, atom):
return 'dir' in atom.properties and 'dir' in atom.mapSpecified and isinstance(atom.properties['dir'], BYONDString)
def Fix(self, atom):
atom.setProperty('dir', int(atom.getProperty('dir')))
return atom
def __str__(self):
return 'Repaired direction type'
-66
View File
@@ -1,66 +0,0 @@
from .base import Matcher,MapFix
from byond.basetypes import BYONDString, BYONDValue, Atom, PropertyFlags
from byond.directions import *
@MapFix('ss13')
class StandardizeAPCs(Matcher):
ACT_CLEAR_NAME = 1
ACT_FIX_OFFSET = 2
def __init__(self):
self.actions = 0
self.pixel_x = 0
self.pixel_y = 0
def Matches(self, atom):
self.actions = 0
if atom.path == '/obj/machinery/power/apc':
# Determine if this APC is pretty close to standard-issue (no weird permissions, etc).
nonstandard_settings = []
for setting in atom.mapSpecified:
if setting not in ('name', 'pixel_x', 'pixel_y', 'tag', 'dir'):
nonstandard_settings += [setting]
if len(nonstandard_settings) > 0:
print('Non-standard APC #{}: Has strange settings - {}'.format(atom.id,', '.join(nonstandard_settings)))
else:
if 'name' in atom.properties and 'name' in atom.mapSpecified:
self.actions |= self.ACT_CLEAR_NAME
direction = int(atom.getProperty('dir', 2))
self.pixel_x = 0
self.pixel_y = 0
c_pixel_x = atom.getProperty('pixel_x', 0)
c_pixel_y = atom.getProperty('pixel_y', 0)
if (direction & 3):
self.pixel_x = 0
if(direction == 1):
self.pixel_y = 24
else:
self.pixel_y = -24
else:
self.pixel_y = 0
if(direction == 4):
self.pixel_x = 24
else:
self.pixel_x = -24
if self.pixel_x != c_pixel_x or self.pixel_y != c_pixel_y:
self.actions |= self.ACT_FIX_OFFSET
return self.actions != 0
def Fix(self, atom):
if self.actions & self.ACT_CLEAR_NAME:
atom.mapSpecified.remove('name')
if self.actions & self.ACT_FIX_OFFSET:
atom.setProperty('pixel_x', self.pixel_x, PropertyFlags.MAP_SPECIFIED)
atom.setProperty('pixel_y', self.pixel_y, PropertyFlags.MAP_SPECIFIED)
return atom
def __str__(self):
if self.actions == 0:
return 'APC Standardization'
descr = []
if self.actions & self.ACT_CLEAR_NAME:
descr += ['Cleared name property']
if self.actions & self.ACT_FIX_OFFSET:
descr += ['Set pixel offset to {0},{1}'.format(self.pixel_x, self.pixel_y)]
return 'Standardized APC: ' + ', '.join(descr)
@@ -1,311 +0,0 @@
'''
/vg/station-specific fixes.
'''
from .base import Matcher,MapFix,RenameProperty,DeclareDependencies,ChangeType
from byond.basetypes import BYONDString, BYONDValue, Atom, PropertyFlags
from byond.directions import *
DeclareDependencies('vgstation',['ss13'])
@MapFix('vgstation')
class FixNetwork(Matcher):
def __init__(self):
pass
def Matches(self, atom):
if atom.path.startswith('/obj/machinery/camera') and 'network' in atom.properties:
return isinstance(atom.properties['network'], BYONDString) and not atom.properties['network'].value.startswith('list(')
return False
def Fix(self, atom):
fix = atom.properties['network'].value
atom.properties['network'] = BYONDValue('list("{0}")'.format(fix))
return atom
def __str__(self):
return 'Changed network property to list'
@MapFix('vgstation')
class NetworkingChangeAtmos(ChangeType):
def __init__(self):
ChangeType.__init__(self,'/obj/machinery/atmospherics','/obj/machinery/networked/atmos', fuzzy = True)
@MapFix('vgstation')
class NetworkingChangePower(ChangeType):
def __init__(self):
ChangeType.__init__(self,'/obj/machinery/power','/obj/machinery/networked/power', fuzzy = True)
@MapFix('vgstation')
class NetworkingChangeFiber(ChangeType):
def __init__(self):
ChangeType.__init__(self,'/obj/machinery/fiber','/obj/machinery/networked/fiber', fuzzy = True)
class FixIDTags(Matcher):
atomsToFix={}
def __init__(self):
pass
def Matches(self, atom):
global atomsToFix
if 'id_tag' in atom.properties:
compiled_atom = self.tree.GetAtom(atom.path)
if compiled_atom is None: return False
if 'id_tag' not in compiled_atom.properties:
FixIDTags.atomsToFix[atom.path] = True
return 'id' in atom.properties and 'id' in atom.mapSpecified
# return False
def Fix(self, atom):
_id = atom.properties['id']
id_idx = atom.mapSpecified.index('id')
atom.properties['id_tag'] = _id
del atom.properties['id']
atom.mapSpecified[id_idx] = 'id_tag'
return atom
def __str__(self):
return 'Renamed id to id_tag'
@MapFix('vgstation')
class StandardizeManifolds(Matcher):
STATE_TO_TYPE = {
'manifold-b' :'/obj/machinery/networked/atmos/pipe/manifold/supply/visible',
'manifold-b-f':'/obj/machinery/networked/atmos/pipe/manifold/supply/hidden',
'manifold-r' :'/obj/machinery/networked/atmos/pipe/manifold/scrubbers/visible',
'manifold-r-f':'/obj/machinery/networked/atmos/pipe/manifold/scrubbers/hidden',
'manifold-c' :'/obj/machinery/networked/atmos/pipe/manifold/cyan/visible',
'manifold-c-f':'/obj/machinery/networked/atmos/pipe/manifold/cyan/hidden',
'manifold-y' :'/obj/machinery/networked/atmos/pipe/manifold/yellow/visible',
'manifold-y-f':'/obj/machinery/networked/atmos/pipe/manifold/yellow/hidden',
'manifold-g' :'/obj/machinery/networked/atmos/pipe/manifold/filtering/visible',
'manifold-g-f':'/obj/machinery/networked/atmos/pipe/manifold/filtering/hidden',
'manifold' :'/obj/machinery/networked/atmos/pipe/manifold/general/visible',
'manifold-f' :'/obj/machinery/networked/atmos/pipe/manifold/general/hidden',
}
def __init__(self):
return
def Matches(self, atom):
if atom.path == '/obj/machinery/networked/atmos/pipe/manifold' and 'icon_state' in atom.mapSpecified:
return atom.getProperty('icon_state') in self.STATE_TO_TYPE
return False
def Fix(self, atom):
icon_state = atom.properties['icon_state'].value
new_atom = Atom(self.STATE_TO_TYPE[icon_state])
if 'dir' in atom.mapSpecified:
new_atom.setProperty('dir', atom.getProperty('dir'), PropertyFlags.MAP_SPECIFIED)
return new_atom
def __str__(self):
return 'Standardized pipe manifold'
@MapFix('vgstation')
class StandardizePiping(Matcher):
TYPE_TRANSLATIONS = {
'/obj/machinery/networked/atmos/pipe/simple': 'simple',
'/obj/machinery/networked/atmos/pipe/manifold': 'manifold',
'/obj/machinery/networked/atmos/pipe/manifold4w': 'manifold4w',
}
COLOR_CODES = {
'b':'supply',
'r':'scrubbers',
'g':'filtering',
'c':'cyan',
'y':'yellow',
'': 'general'
}
def __init__(self):
self.before = None
self.after = None
return
def trans_simple(self, atom):
type_tmpl = '/obj/machinery/networked/atmos/pipe/simple/{color}/{visibility}'
color_code, visible = self.parseIconState(atom.getProperty('icon_state', ''))
return self.getNewType(type_tmpl, color_code, visible)
def trans_manifold(self, atom):
type_tmpl = '/obj/machinery/networked/atmos/pipe/manifold/{color}/{visibility}'
color_code, visible = self.parseIconState(atom.getProperty('icon_state', ''))
return self.getNewType(type_tmpl, color_code, visible)
def trans_manifold4w(self, atom):
type_tmpl = '/obj/machinery/networked/atmos/pipe/manifold4w/{color}/{visibility}'
color_code, visible = self.parseIconState(atom.getProperty('icon_state', ''))
return self.getNewType(type_tmpl, color_code, visible)
def parseIconState(self, state):
parts = state.split('-')
if len(parts) <= 1:
return ('', True)
elif len(parts) == 2:
if parts[1] == 'f':
return ('', True)
return (parts[1], True)
return (parts[1], parts[2] != 'f')
def getNewType(self, tmpl, color_code, visible, color_wheel=COLOR_CODES):
visibility = 'visible'
if not visible:
visibility = 'hidden'
color = color_wheel[color_code]
return Atom(tmpl.format(color=color, visibility=visibility))
def Matches(self, atom):
return atom.path in self.TYPE_TRANSLATIONS
def Fix(self, atom):
self.before = atom.MapSerialize()
old_dir = None
if 'dir' in atom.mapSpecified:
old_dir = int(atom.getProperty('dir', 2))
atom = getattr(self, 'trans_{0}'.format(self.TYPE_TRANSLATIONS[atom.path]))(atom)
if old_dir is not None and old_dir != 2:
atom.setProperty('dir', old_dir, PropertyFlags.MAP_SPECIFIED)
self.after = atom.MapSerialize()
return atom
def __str__(self):
if self.before is not None and self.after is not None:
return 'Standardized pipe: {0} -> {1}'.format(self.before, self.after)
else:
return 'Standardize pipes'
@MapFix('vgstation')
class StandardizeInsulatedPipes(Matcher):
STATE_TO_TYPE = {
'intact' :'/obj/machinery/networked/atmos/pipe/simple/insulated/visible',
'intact-f':'/obj/machinery/networked/atmos/pipe/simple/insulated/hidden'
}
def __init__(self):
return
def Matches(self, atom):
if atom.path == '/obj/machinery/networked/atmos/pipe/simple/insulated':
return True
if atom.path.startswith('/obj/machinery/networked/atmos/pipe/simple/insulated') and int(atom.getProperty('dir', 0)) in (3, 8, 12):
# print(atom.MapSerialize())
return True
return False
def Fix(self, atom):
newtype = atom.path
if atom.path == '/obj/machinery/networked/atmos/pipe/simple/insulated':
icon_state = ''
if 'icon_state' in atom.properties:
icon_state = atom.properties['icon_state'].value
newtype = self.STATE_TO_TYPE.get(icon_state, '/obj/machinery/networked/atmos/pipe/simple/insulated/visible')
new_atom = Atom(newtype)
if 'dir' in atom.mapSpecified:
# Normalize dir
direction = int(atom.getProperty('dir', 2))
if direction == 3:
direction = 1
elif direction == 8: # Breaks things, for some reason
direction = 4
elif direction == 12:
direction = 4
new_atom.setProperty('dir', direction, PropertyFlags.MAP_SPECIFIED)
return new_atom
def __str__(self):
return 'Standardized insulated pipe'
@MapFix('vgstation')
class FixWindows(Matcher):
def __init__(self):
return
def Matches(self, atom):
if atom.path.startswith('/obj/structure/window/full'):
return False
if atom.path.startswith('/obj/structure/window') and int(atom.getProperty('dir', SOUTH)) in (NORTH | WEST, SOUTH | WEST, NORTH | EAST, SOUTH | EAST):
# print(atom.MapSerialize())
return True
return False
def Fix(self, atom):
newtype = atom.path.replace('/obj/structure/window', '/obj/structure/window/full')
atom.path = newtype
atom.properties = {}
atom.mapSpecified = []
return atom
def __str__(self):
return 'Standardized full windows'
@MapFix('vgstation')
class FixVaultFloors(Matcher):
"""
Changes flooring icons to use /vg/'s standardized vault icons.
"""
# state:1
ICON_STATE_CHANGES = {
'vault:1' :{'icon_state':'dark-markings', 'dir':2},
'vault:2' :{'icon_state':'dark vault stripe', 'dir':2},
'vault:4' :{'icon_state':'dark-markings', 'dir':1},
'vault:8' :{'icon_state':'dark-markings', 'dir':8},
'vault:6' :{'icon_state':'dark vault corner', 'dir':2},
'vault:10':{'icon_state':'dark vault corner', 'dir':8},
'vault:5' :{'icon_state':'dark vault full', 'dir':2},
'vault:9' :{'icon_state':'dark loading', 'dir':4},
'vault-border:1' :{'icon_state':'dark vault stripe', 'dir':2},
'vault-border:2' :{'icon_state':'dark vault stripe', 'dir':1},
'vault-border:4' :{'icon_state':'dark vault stripe', 'dir':4},
'vault-border:8' :{'icon_state':'dark vault stripe', 'dir':8},
'vault-border:6' :{'icon_state':'dark vault corner', 'dir':2},
'vault-border:10':{'icon_state':'dark vault stripe', 'dir':5},
'vault-border:5' :{'icon_state':'dark vault stripe', 'dir':5},
'vault-border:9' :{'icon_state':'dark vault stripe', 'dir':6},
}
def __init__(self):
self.stateKey = ''
self.changesMade = []
return
def GetStateKey(self, atom):
icon_state = ''
_dir = '2'
if 'dir' in atom.properties:
_dir = str(atom.getProperty('dir'))
if 'icon_state' in atom.properties:
icon_state = atom.getProperty('icon_state')
return icon_state + ":" + _dir
def Matches(self, atom):
if atom.path.startswith('/turf/') and 'icon_state' in atom.mapSpecified:
sk = self.GetStateKey(atom)
if sk in self.ICON_STATE_CHANGES:
self.stateKey = sk
return True
return False
def Fix(self, atom):
self.changesMade = []
propChanges = self.ICON_STATE_CHANGES[self.stateKey]
if 'tag' in atom.mapSpecified:
atom.mapSpecified.remove('tag')
for key, newval in propChanges.items():
if key not in atom.mapSpecified:
atom.mapSpecified += [key]
oldval = 'NONE'
if key in atom.properties:
oldval = str(atom.properties[key])
if isinstance(newval, str):
atom.properties[key] = BYONDString(newval)
elif isinstance(newval, int):
atom.properties[key] = BYONDValue(newval)
self.changesMade += ['{0}: {1} -> {2}'.format(key, oldval, atom.properties[key])]
return atom
def __str__(self):
return 'Standardized vault flooring (' + ', '.join(self.changesMade) + ')'
@MapFix('vgstation')
class RenameColorVG(RenameProperty):
def __init__(self):
RenameProperty.__init__(self, "color", "_color")
@@ -1,91 +0,0 @@
"""
BYOND Base Packet Class
Created with help from tobba.
"""
import logging, struct
class NetTypes:
BYTE = 0
SHORT = 1
LONG = 2
STRING = 3
min_lens = [1, 2, 4, None]
@staticmethod
def GetMinLength(t):
return NetTypes.min_lens[t]
PacketTypes = {}
class Packet:
ID = 0
Name = ''
def __init__(self):
self.__field_data = {}
self.header = {}
self.min_length = 0
self.length = 0
self.sequence = 0
def LinkField(self, datatype, propname, **kwargs):
'''
Associate a part of a packet to a field in this class
'''
kwargs['type'] = datatype
kwargs['name'] = propname
self.__field_data[len(self.__field_data)] = kwargs
self.min_length += NetTypes.GetMinLength(datatype)
def Deserialize(self, msg):
if len(msg) < self.min_length:
logging.error('Received truncated packet {0}: min_length={1}, msg.len={2}'.format(self.Name, self.min_length, len(msg)))
# TIME FOR ASSUMPTIONS!
pos = 0
for idx, fieldinfo in self.__field_data.items():
dtype = fieldinfo['type']
propname = fieldinfo['name']
unpacked = None
if dtype == NetTypes.BYTE:
dat = msg[pos:pos + 1]
unpacked = struct.unpack('B', dat) # Unsigned char
pos += 1
elif dtype == NetTypes.SHORT:
dat = msg[pos:pos + 2]
unpacked = struct.unpack('h', dat) # short (maybe H?)
pos += 2
elif dtype == NetTypes.LONG:
dat = msg[pos:pos + 4]
unpacked = struct.unpack('l', dat) # short (maybe L?)
pos += 4
elif dtype == NetTypes.STRING:
dat = msg[pos:]
unpacked = dat.split('\x00', 1)
pos += len(unpacked) + 1 # NUL byte stripped
else:
logging.error('Unable to unpack {0} packet at field {1}: Unknown datatype {2}'.format(self.Name, idx, dtype))
logging.error('Packet __field_data:'.repr(self.__field_data))
raise SystemError()
setattr(self, propname, unpacked)
def Serialize(self):
msg = b''
for idx, fieldinfo in self.__field_data.items():
dtype = fieldinfo['type']
dat = getattr(self, fieldinfo['name'])
if dtype == NetTypes.BYTE:
msg += struct.pack('B', dat) # Unsigned char
elif dtype == NetTypes.SHORT:
msg += struct.pack('h', dat) # short (maybe H?)
elif dtype == NetTypes.LONG:
msg += struct.pack('l', dat) # short (maybe L?)
elif dtype == NetTypes.STRING:
msg += dat + b'\x00'
else:
logging.error('Unable to pack {0} packet at field {1}: Unknown datatype {2}'.format(self.Name, idx, dtype))
logging.error('Packet __field_data:'.repr(self.__field_data))
raise SystemError()
return msg
-709
View File
@@ -1,709 +0,0 @@
'''
Superficially generate an object/property tree.
'''
import re, logging, os
try:
import cPickle as pickle
except:
import pickle
from .basetypes import Atom, Proc, BYONDValue, BYONDString, BYONDFileRef
from .utils import md5sum, get_stdlib
REGEX_TABS = re.compile('^(?P<tabs>[\t\s]*)')
REGEX_ATOMDEF = re.compile('^(?P<tabs>\t*)(?P<atom>[a-zA-Z0-9_/]+)\\{?\\s*$')
REGEX_ABSOLUTE_PROCDEF = re.compile('^(?P<tabs>\t*)(?P<atom>[a-zA-Z0-9_/]+)/(?P<proc>[a-zA-Z0-9_]+)\((?P<args>.*)\)\\{?\s*$')
REGEX_RELATIVE_PROCDEF = re.compile('^(?P<tabs>\t*)(?P<proc>[a-zA-Z0-9_]+)\((?P<args>.*)\)\\{?\\s*$')
REGEX_LINE_COMMENT = re.compile('//.*?$')
def debug(filename, line, path, message):
print('{0}:{1}: {2} - {3}'.format(filename, line, '/'.join(path), message))
class OTRCache:
# : Only used for obliterating outdated data.
VERSION = [28, 4, 2014]
def __init__(self, filename):
self.filename = filename
self.files = {}
self.atoms = None
self.handle = None
def StartReading(self):
if self.handle:
self.handle.close()
self.handle = None
if os.path.isfile(self.filename):
self.handle = open(self.filename, 'r')
def StopReading(self):
if self.handle is not None:
self.handle.close()
def CheckVersion(self):
# print('READ VERSION')
# Block 1: Version
if pickle.load(self.handle) != self.VERSION:
print('!!! Outdated OTR data, rebuilding.')
return False
return True
def ReadFiles(self):
# print('READ FILES')
# Block 2: Files
self.files = pickle.load(self.handle)
def ReadAtoms(self):
# print('READ ATOMS')
return pickle.load(self.handle)
def CheckFileHash(self, fn, md5):
# print('{0}: {1}'.format(fn,md5))
if fn not in self.files:
print(' + {0}'.format(fn))
return False
if self.files[fn] != md5:
print(' * {0}'.format(fn))
return False
return True
def PruneFiles(self, file_list):
for fn in self.files.keys():
if fn not in file_list:
self.files -= [fn]
print(' - {0}'.format(fn))
def SetFileMD5(self, fn, md5):
self.files[fn] = md5
def GetFiles(self):
return self.files.keys()
def Save(self, atoms):
with open(self.filename, 'w') as f:
pickle.dump(self.VERSION, f)
pickle.dump(self.files, f)
pickle.dump(atoms, f)
class ObjectTree:
reserved_words = ('else', 'break', 'return', 'continue', 'spawn') # , 'proc')
stdlib_files = (
'dm_std.dm',
'atom_defaults.dm'
)
def __init__(self, **options):
#: All atoms, in a list.
self.Atoms = {}
#: All atoms, in a tree-node structure.
self.Tree = Atom('')
#: Skip loading from .OTR?
self.skip_otr = False
self.LoadedStdLib = False
self.cpath = []
self.popLevels = []
self.InProc = []
self.pindent = 0 # Previous Indent
self.ignoreLevel = [] # Block Comments
self.ignoreStartIndent = -1
self.debugOn = True
self.ignoreDebugOn = False
self.ignoreTokens = {
'/*':'*/',
'{"':'"}'
}
self.defines = {}
self.defineMatchers = {}
self.comments = []
self.fileLayouts = {}
self.LeavePreprocessorDirectives = options.get('preprocessor_directives', False)
nit = self.ignoreTokens.copy()
for _, stop in self.ignoreTokens.iteritems():
nit[stop] = None
self.ignoreTokens = nit
self.defines['__OBJTREE'] = BYONDValue('1')
def ProcessMultiString(self, filename, line, ignoreLevels, current_buffer):
return '"{0}"'.format(current_buffer)
def SplitPath(self, string):
o = []
buf = []
inProc = False
for chunk in string.split('/'):
if not inProc:
if '(' in chunk and ')' not in chunk:
inProc = True
buf += [chunk]
else:
o += [chunk]
else:
if ')' in chunk:
o += ['/'.join(buf + [chunk])]
inProc = False
else:
buf += [chunk]
return o
def ProcessFilesFromDME(self, dmefile='baystation12.dme', ext='.dm', **kwargs):
changed_files = 0
rootdir = os.path.dirname(dmefile)
projectfile = os.path.join(rootdir, os.path.basename(dmefile).replace('.dme', '.otr'))
cache = OTRCache(projectfile)
invalid = False
if not self.skip_otr:
if os.path.isfile(projectfile):
print('--- Loading pickled object tree...')
cache.StartReading()
if cache.CheckVersion():
cache.ReadFiles()
else:
invalid = True
else:
invalid = True
ToRead = []
if not self.LoadedStdLib and kwargs.get('load_stdlib', True):
stdlib_dir = get_stdlib()
for filename in self.stdlib_files:
# self.ProcessFile(os.path.join(stdlib_dir, filename))
ToRead += [os.path.join(stdlib_dir, filename)]
with open(dmefile, 'r') as dmeh:
for line in dmeh:
if line.startswith('#include'):
inString = False
# escaped=False
filename = ''
for c in line:
"""
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
if
escaped = False
continue
"""
if c == '"':
inString = not inString
if not inString:
filepath = os.path.join(rootdir, filename)
if filepath.endswith(ext):
ToRead += [filepath]
filename = ''
continue
else:
if inString:
filename += c
for filepath in ToRead:
md5 = md5sum(filepath)
if invalid or not cache.CheckFileHash(filepath, md5):
changed_files += 1
cache.SetFileMD5(filepath, md5)
if invalid or self.skip_otr or changed_files > 0:
if invalid:
print('--- Rebuilding object tree - Parsing DM files...'.format(changed_files))
else:
print('--- {0} changed files. Parsing DM files...'.format(changed_files))
for f in ToRead:
self.ProcessFile(f)
print('--- Saving atoms...')
cache.StopReading()
cache.Save(self.Atoms)
self.MakeTree()
else:
print('--- No changes detected, using pickled atoms...')
self.Atoms = cache.ReadAtoms()
cache.StopReading()
self.MakeTree()
def DetermineContext(self, filename, ln, line, numtabs, atom_prefix=[]):
'''
Spit out the full path of the atom we're currently in.
Does NOT update internal positioning. Think peek.
'''
if numtabs == 0:
return None # Global context
elif numtabs > self.pindent:
return '/'.join(self.cpath + atom_prefix)
elif numtabs < self.pindent:
cpath_copy = list(self.cpath)
for _ in range(self.pindent - numtabs + 1):
popsToDo = self.popLevels.pop()
for _ in range(popsToDo):
cpath_copy.pop()
cpath_copy += atom_prefix
return '/'.join(cpath_copy)
elif numtabs == self.pindent:
cpath_copy = list(self.cpath)
levelsToPop = self.popLevels.pop()
for _ in range(levelsToPop):
cpath_copy.pop()
cpath_copy += atom_prefix
return '/'.join(cpath_copy)
def ProcessAtom(self, filename, ln, line, atom, atom_path, numtabs, procArgs=None):
# Reserved words that show up on their own
if atom in ObjectTree.reserved_words:
return
# Other things to ignore (false positives, comments)
if atom.startswith('var/') or atom.startswith('//'):
return
# Things part of a string or list.
if numtabs > 0 and atom.strip().startswith('/'):
return
if self.debugOn: print('{} > {}'.format(numtabs, line.rstrip()))
if numtabs == 0:
self.cpath = atom_path
if len(self.cpath) == 0:
self.cpath += ['']
elif self.cpath[0] != '':
self.cpath.insert(0, '')
self.popLevels = [len(self.cpath)]
if self.debugOn: debug(filename, ln, self.cpath, '0 - ' + repr(atom_path))
elif numtabs > self.pindent:
self.cpath += atom_path
self.popLevels += [len(atom_path)]
if self.debugOn: debug(filename, ln, self.cpath, '>')
elif numtabs < self.pindent:
if self.debugOn: print('({} - {})={}: {}'.format(self.pindent, numtabs, self.pindent - numtabs, repr(self.cpath)))
for _ in range(self.pindent - numtabs + 1):
popsToDo = self.popLevels.pop()
if self.debugOn: print(' pop {} {}'.format(popsToDo, self.popLevels))
for i in range(popsToDo):
self.cpath.pop()
if self.debugOn: print(' pop {}/{}: {}'.format(i + 1, popsToDo, repr(self.cpath)))
self.cpath += atom_path
self.popLevels += [len(atom_path)]
if self.debugOn: debug(filename, ln, self.cpath, '<')
elif numtabs == self.pindent:
levelsToPop = self.popLevels.pop()
for i in range(levelsToPop):
self.cpath.pop()
self.cpath += atom_path
self.popLevels += [len(atom_path)]
if self.debugOn: print('popLevels: ' + repr(self.popLevels))
if self.debugOn: debug(filename, ln, self.cpath, '==')
origpath = '/'.join(self.cpath)
# print(npath)
# definition?
defs = []
# Trim off /proc or /var, if needed.
prep_path = list(self.cpath)
for special in ['proc']:
if special in prep_path:
defs += [special]
prep_path.remove(special)
npath = '/'.join(prep_path)
if npath not in self.Atoms:
if procArgs is not None:
assert npath.endswith(')')
# if origpath != npath:
# print(origpath,proc_def)
proc = Proc(npath, procArgs, filename, ln)
proc.origpath = origpath
proc.definition = 'proc' in defs
self.Atoms[npath] = proc
else:
self.Atoms[npath] = Atom(npath, filename, ln)
# if self.debugOn: print('Added ' + npath)
self.pindent = numtabs
return self.Atoms[npath]
def AddCodeToProc(self, startIndent, code):
if '\n' in code:
for line in code.split('\n'):
self.AddCodeToProc(startIndent, line)
else:
m = REGEX_TABS.match(code)
if m is not None:
numtabs = len(m.group('tabs'))
i = max(1, numtabs - startIndent)
# self.loadingProc.AddCode(i, '/* {0} */ {1}'.format(i,code.strip()))
self.loadingProc.AddCode(i, code.rstrip())
def finishComment(self, line, **args):
self.comments += [self.comment]
self.fileLayout += [('COMMENT', len(self.comments) - 1)]
if self.ignoreDebugOn: print('finishComment({}): {}'.format(line, self.comment))
if self.loadingProc is not None and (args.get('cleansed_line', '') == '' and not self.comment.strip().startswith('//')):
self.AddCodeToProc(self.ignoreStartIndent, self.comment)
self.comment = ''
def handleOBToken(self, name, context, params):
if context is not None:
context = self.Atoms[context]
name = 'ob_{0}'.format(name.lower())
getattr(self, name)(context, *params)
def ProcessFile(self, filename):
self.cpath = []
self.popLevels = []
self.pindent = 0 # Previous Indent
self.ignoreLevel = []
self.debugOn = False
self.ignoreDebugOn = False
self.ignoreStartIndent = -1
self.loadingProc = None
self.comment = ''
self.fileLayout = []
self.lineBeforePreprocessing = ''
self.current_filename = filename
with open(filename, 'r') as f:
ln = 0
ignoreLevel = []
for line in f:
ln += 1
skipNextChar = False
nl = ''
line = line.rstrip()
self.lineBeforePreprocessing = line
line_len = len(line)
for i in xrange(line_len):
c = line[i]
nc = ''
if line_len > i + 1:
nc = line[i + 1]
tok = c + nc
# print(tok)
if skipNextChar:
if self.ignoreDebugOn: print('Skipping {}.'.format(repr(tok)))
skipNextChar = False
# self.comment += c
if self.ignoreDebugOn: print('self.comment = {}.'.format(repr(self.comment)))
continue
if tok == '//':
# if self.ignoreDebugOn: debug(filename,ln,self.cpath,'{} ({})'.format(tok,len(ignoreLevel)))
if len(ignoreLevel) == 0:
self.comment = line[i:]
# if self.ignoreDebugOn: print('self.comment = {}.'.format(repr(self.comment)))
# print('Found '+self.comment)
self.finishComment('243', cleaned_line=nl)
break
if tok in self.ignoreTokens:
pc = ''
if i > 0:
pc = line[i - 1]
if tok == '{"' and pc == '"':
self.comment += c
continue
# if self.ignoreDebugOn: print(repr(self.ignoreTokens[tok]))
stop = self.ignoreTokens[tok]
if stop == None: # End comment
if len(ignoreLevel) > 0:
if ignoreLevel[-1] == tok:
skipNextChar = True
self.comment += tok
ignoreLevel.pop()
if len(ignoreLevel) == 0:
self.finishComment('261')
continue
else:
self.comment += c
continue
else: # Start comment
skipNextChar = True
ignoreLevel += [stop]
self.comment = tok
continue
if self.ignoreDebugOn: debug(filename, ln, self.cpath, '{} ({})'.format(tok, len(ignoreLevel)))
if len(ignoreLevel) == 0:
nl += c
else:
self.comment += c
if line != nl:
if self.ignoreDebugOn: print('IN : ' + line)
line = nl
if self.ignoreDebugOn: print('OUT: ' + line)
if self.ignoreDebugOn: print('self.comment = {}.'.format(repr(self.comment)))
if len(ignoreLevel) > 0:
self.comment += "\n"
continue
line = REGEX_LINE_COMMENT.sub('', line)
if line.strip() == '':
if self.loadingProc is not None:
self.loadingProc.AddBlankLine()
continue
# Preprocessing defines.
if line.strip().startswith("#"):
if line.endswith('\\'): continue
tokenChunks = line.split('#')
tokenChunks = tokenChunks[1].split()
directive = tokenChunks[0]
if directive == 'define':
# #define SOMETHING Value
defineChunks = line.split(None, 3)
if len(defineChunks) == 2:
defineChunks += [1]
elif len(defineChunks) == 3:
defineChunks[2] = self.PreprocessLine(defineChunks[2])
# print(repr(defineChunks))
try:
if '.' in defineChunks[2]:
self.defines[defineChunks[1]] = BYONDValue(float(defineChunks[2]), filename, ln)
else:
self.defines[defineChunks[1]] = BYONDValue(int(defineChunks[2]), filename, ln)
except:
self.defines[defineChunks[1]] = BYONDString(defineChunks[2], filename, ln)
self.fileLayout += [('DEFINE', defineChunks[1], defineChunks[2])]
elif directive == 'undef':
undefChunks = line.split(' ', 2)
if undefChunks[1] in self.defines:
del self.defines[undefChunks[1]]
self.fileLayout += [('UNDEF', undefChunks[1])]
# OpenBYOND tokens.
elif directive.startswith('__OB_'):
numtabs = 0
m = REGEX_TABS.match(line)
if m is not None:
numtabs = len(m.group('tabs'))
atom = self.DetermineContext(filename, ln, line, numtabs)
# if atom is None: continue
# print('OBTOK {0}'.format(repr(tokenChunks)))
self.handleOBToken(tokenChunks[0].replace('__OB_', ''), atom, tokenChunks[1:])
# self.fileLayout += [('OBTOK', atom.path)]
continue
else:
chunks = line.split(' ')
self.fileLayout += [('PP_TOKEN', line)]
print('BUG: Unhandled preprocessor directive #{} in {}:{}'.format(directive, filename, ln))
continue
# Preprocessing
line = self.PreprocessLine(line)
m = REGEX_TABS.match(self.lineBeforePreprocessing)
if m is not None:
numtabs = len(m.group('tabs'))
if self.ignoreStartIndent > -1 and self.ignoreStartIndent < numtabs:
if self.loadingProc is not None:
# self.loadingProc.AddCode(numtabs - self.ignoreStartIndent, self.lineBeforePreprocessing.strip())
self.AddCodeToProc(self.ignoreStartIndent, self.lineBeforePreprocessing)
if self.debugOn: print('TABS: {} ? {} - {}: {}'.format(numtabs, self.ignoreStartIndent, self.loadingProc, line))
continue
else:
if self.debugOn and self.ignoreStartIndent > -1: print('BREAK ({} -> {}): {}'.format(self.ignoreStartIndent, numtabs, line))
self.ignoreStartIndent = -1
self.loadingProc = None
else:
if self.debugOn and self.ignoreStartIndent > -1: print('BREAK ' + line)
self.ignoreStartIndent = -1
self.loadingProc = None
if not line.strip().startswith('var/'):
m = REGEX_ATOMDEF.match(line)
if m is not None:
numtabs = len(m.group('tabs'))
atom = m.group('atom')
atom_path = self.SplitPath(atom)
atom = self.ProcessAtom(filename, ln, line, atom, atom_path, numtabs)
if atom is None: continue
self.fileLayout += [('ATOMDEF', atom.path)]
continue
m = REGEX_ABSOLUTE_PROCDEF.match(line)
if m is not None:
numtabs = len(m.group('tabs'))
atom = '{0}/{1}({2})'.format(m.group('atom'), m.group("proc"), m.group('args'))
atom_path = self.SplitPath(atom)
# print('PROCESSING ABS PROC AT INDENT > ' + str(numtabs) + " " + atom+" -> "+repr(atom_path))
proc = self.ProcessAtom(filename, ln, line, atom, atom_path, numtabs, m.group('args').split(','))
if proc is None: continue
self.ignoreStartIndent = numtabs
self.loadingProc = proc
self.fileLayout += [('PROCDEF', proc.path)]
continue
m = REGEX_RELATIVE_PROCDEF.match(line)
if m is not None:
numtabs = len(m.group('tabs'))
atom = '{}({})'.format(m.group("proc"), m.group('args'))
atom_path = self.SplitPath(atom)
# print('IGNORING RELATIVE PROC AT INDENT > ' + str(numtabs) + " " + line)
proc = self.ProcessAtom(filename, ln, line, atom, atom_path, numtabs, m.group('args').split(','))
if proc is None: continue
self.ignoreStartIndent = numtabs
self.loadingProc = proc
self.fileLayout += [('PROCDEF', proc.path)]
continue
path = '/'.join(self.cpath)
# if len(self.cpath) > 0 and 'proc' in self.cpath:
# continue
# if 'proc' in self.cpath:
# continue
if '=' in line or line.strip().startswith('var/'):
if path not in self.Atoms:
self.Atoms[path] = Atom(path)
name, prop = self.consumeVariable(line, filename, ln)
self.Atoms[path].properties[name] = prop
self.fileLayout += [('VAR', path, name)]
self.fileLayouts[filename] = self.fileLayout
def consumeVariable(self, line, filename, ln):
declaration = False
value = None
size = None
decl = ''
if self.LeavePreprocessorDirectives:
line = decl = self.lineBeforePreprocessing.strip()
else:
decl = line.strip()
if '[' in line:
line_split, arr_decl = line.split('[', 1)
str_size = arr_decl[:arr_decl.index(']')]
size = -1
if str_size != '':
try:
size = int(str_size)
except ValueError:
pass
# print(repr({'size':size,'line':line_split}))
line = line_split
if '=' in line:
decl, value = line.split('=', 1)
decl = decl.strip()
value = value.strip()
else:
decl = line.strip()
value = None
# print(repr({'decl':decl,'value':value}))
# (var)(/global|const|tmp)(/type/fragment)name
if decl.startswith('var/'):
declaration = True
decl = decl[4:]
pathchunks = decl.split('/')
name = pathchunks[-1]
special = None
typepath = '/'
if declaration:
if pathchunks[0] in ('tmp', 'global', 'const'):
special = pathchunks[0]
pathchunks = pathchunks[1:]
if 'list' not in pathchunks and size is not None:
pathchunks = ['list'] + pathchunks
typepath = '/' + '/'.join(pathchunks[:-1])
kwargs = {
'declaration':declaration,
'special':special,
'size':size
}
if typepath != '/':
return (name, BYONDValue(value, filename, ln, typepath, **kwargs))
elif value and value[0] == '"':
return (name, BYONDString(value[1:-1], filename, ln, **kwargs))
elif value and value[0] == "'":
return (name, BYONDFileRef(value[1:-1], filename, ln, **kwargs))
elif value and '.' in value:
try:
return (name, BYONDValue(float(value), filename, ln, typepath, **kwargs))
except ValueError:
pass
return (name, BYONDValue(value, filename, ln, typepath, **kwargs))
def MakeTree(self):
print('Generating Tree...')
self.Tree = Atom('/')
with open('objtree.txt', 'w') as f:
for key in sorted(self.Atoms):
f.write("{0}\n".format(key))
atom = self.Atoms[key]
cpath = []
cNode = self.Tree
fullpath = self.SplitPath(atom.path)
truncatedPath = fullpath[1:]
for path_item in truncatedPath:
cpath += [path_item]
cpath_str = '/'.join([''] + cpath)
# if path_item == 'var':
# if path_item not in cNode.properties:
# cNode.properties[fullpath[-1]]='???'
if path_item not in cNode.children:
if cpath_str in self.Atoms:
cNode.children[path_item] = self.Atoms[cpath_str]
else:
if '(' in path_item:
cNode.children[path_item] = Proc('/'.join([''] + cpath), [])
else:
cNode.children[path_item] = Atom('/'.join([''] + cpath),atom.filename,atom.line)
cNode.children[path_item].parent = cNode
parent_type = cNode.children[path_item].getProperty('parent_type')
if parent_type is not None:
print(' - Parent of {0} forced to be {1}'.format(cNode.children[path_item].path, repr(parent_type)))
cNode.children[path_item].parent = self.Atoms[parent_type]
cNode = cNode.children[path_item]
self.Tree.InheritProperties()
print('Processed {0} atoms.'.format(len(self.Atoms)))
# self.Atoms = {}
def GetAtom(self, path):
if path in self.Atoms:
return self.Atoms[path]
cpath = []
cNode = self.Tree
fullpath = path.split('/')
truncatedPath = fullpath[1:]
for path_item in truncatedPath:
cpath += [path_item]
if path_item not in cNode.children:
print('Unable to find {0} (lost at {1})'.format(path, cNode.path))
print(repr(cNode.children.keys()))
return None
cNode = cNode.children[path_item]
# print('Found {0}!'.format(path))
self.Atoms[path] = cNode
return cNode
def PreprocessLine(self, line):
for key, define in self.defines.items():
if key in line:
if key not in self.defineMatchers:
self.defineMatchers[key] = re.compile(r'\b' + key + r'\b')
newline = self.defineMatchers[key].sub(str(define.value), line)
if newline != line:
'''
if filename.endswith('pipes.dm'):
print('OLD: {}'.format(line))
print('PPD: {}'.format(newline))
'''
line = newline
return line
-48
View File
@@ -1,48 +0,0 @@
import hashlib, ast, os
import operator as op
def md5sum(filename):
with open(filename, mode='rb') as f:
d = hashlib.md5()
while True:
buf = f.read(4096) # 128 is smaller than the typical filesystem block
if not buf:
break
d.update(buf)
return d.hexdigest().upper()
# supported operators
operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,
ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor}
def eval_expr(expr):
"""
>>> eval_expr('2^6')
4
>>> eval_expr('2**6')
64
>>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')
-5.0
"""
return eval_(ast.parse(expr).body[0].value) # Module(body=[Expr(value=...)])
def eval_(node):
if isinstance(node, ast.Num): # <number>
return node.n
elif isinstance(node, ast.operator): # <operator>
return operators[type(node)]
elif isinstance(node, ast.BinOp): # <left> <operator> <right>
return eval_(node.op)(eval_(node.left), eval_(node.right))
else:
raise TypeError(node)
_ROOT = os.path.abspath(os.path.dirname(__file__))
def get_data(path):
return os.path.join(_ROOT, 'data', path)
def get_stdlib(path=''):
if path != '':
return os.path.join(get_data('stdlib'), path)
return get_data('stdlib')
-177
View File
@@ -1,177 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenBYOND.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenBYOND.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OpenBYOND"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenBYOND"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
-3
View File
@@ -1,3 +0,0 @@
rm -rf _build
call make html
pause
-28
View File
@@ -1,28 +0,0 @@
.. module:: com.byond.basetypes
:mod:`com.byond.basetypes` -- Basic BYOND Types
===============================================
Basic Types
-----------
.. autoclass:: BYONDValue
:members:
.. autoclass:: BYONDFileRef
:members:
.. autoclass:: BYONDString
:members:
Atoms and Procs
---------------
.. autoclass:: PropertyFlags
:members:
.. autoclass:: Atom
:members:
.. autoclass:: Proc
:members:
-266
View File
@@ -1,266 +0,0 @@
# -*- coding: utf-8 -*-
#
# OpenBYOND documentation build configuration file, created by
# sphinx-quickstart on Fri Feb 07 20:03:28 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('../src'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.pngmath',
'sphinx.ext.viewcode',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'BYONDTools'
copyright = u'2013-2014 BYONDTools Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenBYONDdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'OpenBYOND.tex', u'OpenBYOND Documentation',
u'OpenBYOND Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'openbyond', u'OpenBYOND Documentation',
[u'OpenBYOND Team'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'OpenBYOND', u'OpenBYOND Documentation',
u'OpenBYOND Team', 'OpenBYOND', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
primary_domain = 'py'
-18
View File
@@ -1,18 +0,0 @@
OpenBYOND
=========
Contents:
.. toctree::
:maxdepth: 2
byond/basetypes
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
-242
View File
@@ -1,242 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenBYOND.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenBYOND.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end
@@ -1,50 +0,0 @@
#------------------------------------------------------------------------------
# Originally cxfreeze-postinstall
# Script run after installation on Windows to fix up the Python location in
# the script as well as create batch files.
#------------------------------------------------------------------------------
import distutils.sysconfig
import glob
import os
vars = distutils.sysconfig.get_config_vars()
prefix = vars["prefix"]
python = os.path.join(prefix, "python.exe")
scriptDir = os.path.join(prefix, "Scripts")
# Keep in-sync with setup.py.
scripts = [
'dmm',
'dmi',
'dmindent',
'dmmrender',
'dmmfix',
'ss13_makeinhands'
]
for fileName in glob.glob(os.path.join(scriptDir, "*.py")):
# skip already created batch files if they exist
name, ext = os.path.splitext(os.path.basename(fileName))
if name not in scripts:
continue
print('Running post-install for {}.'.format(name))
# copy the file with the first line replaced with the correct python
fullName = os.path.join(scriptDir, fileName)
strippedName = os.path.join(scriptDir, name)
lines = open(fullName).readlines()
startidx=1
if not lines[0].strip().startswith('#!'):
print('WARNING: {} does not have a shebang.'.format(lines[0]))
startidx=0
outFile = open(fullName, "w")
outFile.write("#!%s\n" % python)
outFile.writelines(lines[startidx:])
outFile.close()
# create the batch file
batchFileName = strippedName + ".bat"
command = "%s %s %%*" % (python, fullName)
open(batchFileName, "w").write("@echo off\n\n%s" % command)
@@ -1,107 +0,0 @@
#!/usr/bin/env python
"""
Usage:
$ python calculateMaxTechLevels.py path/to/your.dme .dm
calculateMaxTechLevels.py - Get techlevels of all objects and generate reports.
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import os, sys, re
from byond.objtree import ObjectTree
from byond.basetypes import Atom, Proc
# Calculated Max Tech Levels.
CMTLs = {}
# All known atoms with tech origins.
AtomTechOrigins = {}
def ProcessTechLevels(atom, path=''):
global CMTLs, AtomTechOrigins
if path.endswith(')'):
# print('ignoring '+path)
return
for key, val in atom.properties.iteritems():
# if 'obj' in path: print('{}: {}'.format(path,key))
if key == 'origin_tech':
tech_origin = {}
# materials=9;bluespace=10;magnets=3
text_origin_tech = atom.getProperty('origin_tech', 'null')
if text_origin_tech == 'null' or text_origin_tech == '':
continue
techchunks = text_origin_tech.split(';')
for techchunk in techchunks:
parts = techchunk.split('=')
if len(parts) != 2:
print('Improperly formed origin_tech in {0}: {1}'.format(atom.path, val.value))
continue
tech = parts[0]
level = int(parts[1])
tech_origin[tech] = level
if tech not in CMTLs:
CMTLs[tech] = level
if CMTLs[tech] < level:
CMTLs[tech] = level
AtomTechOrigins[path] = tech_origin
break
for key, child in atom.children.iteritems():
ProcessTechLevels(child, path + '/' + key)
def prettify(tree, indent=0):
prefix = ' ' * indent
for key in tree.iterkeys():
atom = tree[key]
print('{}{}/'.format(prefix, key))
prettify(atom.children, indent + len(key))
for propkey, value in atom.properties.iteritems():
print('{}var/{} = {}'.format(' ' * (indent + len(key)), propkey, repr(value)))
if os.path.isfile(sys.argv[1]):
tree = ObjectTree()
tree.ProcessFilesFromDME(sys.argv[1])
ProcessTechLevels(tree.Tree)
with open(os.path.join(os.path.dirname(sys.argv[1]), 'tech_origin_list.csv'), 'w') as w:
with open(os.path.join(os.path.dirname(sys.argv[1]), 'max_tech_origins.txt'), 'w') as mto:
tech_columns = []
mto.write('Calculated Max Tech Levels:\n These tech levels have been determined by parsing ALL origin_tech variables in code included by {0}.\n'.format(sys.argv[1]))
for tech in sorted(CMTLs.keys()):
tech_columns.append(tech)
mto.write('{:>15}: {}\n'.format(tech, CMTLs[tech]))
w.write(','.join(['Atom', 'Name'] + tech_columns) + "\n")
for path in sorted(AtomTechOrigins.keys()):
row = []
row.append(path)
atom = tree.GetAtom(path)
name = atom.properties.get('name', None)
if name is None:
name = ''
else:
name = name.value
row.append('"' + name.replace('"', '""') + '"')
for tech in tech_columns:
if tech in AtomTechOrigins[path]:
row.append(str(AtomTechOrigins[path][tech]))
else:
row.append('')
w.write(','.join(row) + "\n")
# prettify(tree.Tree.children)
@@ -1,163 +0,0 @@
#!/usr/bin/env python
import os, sys, re
"""
Usage:
$ python fix_string_idiocy.py path/to/your.dme .dm
NOTE: NOT PERFECT, CREATES code-fixed DIRECTORY.
*** MERGE THIS MANUALLY OR YOU WILL BREAK SHIT. ***
fix_string_idiocy.py - Combines multiple string append operations in DreamMaker code
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
REGEX_TO_COMBINE_AS_BLOCK = re.compile('^(?P<tabs>\t+)(?P<declaration>var/)?(?P<identifier>[A-Za-z\.]+)\s*(?P<operator>\+?)=\s*"(?P<content>.+)"\s*$')
def ProcessFile(filename):
fuckups = []
with open(filename, 'r') as f:
lastID = ''
declaring = False
lastLevel = 0
lastWasAlert = False
buffa = ''
tempbuffa = ''
tempfuckup = ''
tempBackup = ''
origIndentLevel = 0
ln = 0
for line in f:
ln += 1
m = REGEX_TO_COMBINE_AS_BLOCK.match(line)
if m is not None:
level = m.group('tabs').count('\t')
ID = m.group('identifier')
content = m.group('content').strip()
indent = '\t' * level
# indentMore = '\t' * (level + 1)
if ID == lastID and level == lastLevel:
if not lastWasAlert:
buffa += '\n' + indent + '// AUTOFIXED BY fix_string_idiocy.py'
buffa += '\n' + indent + '// ' + tempfuckup
buffa += '\n' + tempbuffa
print(tempfuckup)
fuckups.append(tempfuckup)
msg = '{0}:{1}: {2}'.format(filename, ln, line.strip())
print(msg)
fuckups.append(msg)
buffa += '\n'
# buffa += indentMore
buffa += content
lastWasAlert = True
else:
if lastWasAlert:
buffa += '"}'
buffa += '\n' + ('\t' * origIndentLevel) + '// END AUTOFIX'
buffa += '\n'
lastWasAlert = False
if tempBackup != '':
buffa += tempBackup
tempBackup = line
tempbuffa = indent
origIndentLevel = level
if m.group('declaration') is None:
tempbuffa += '{0} {2}= {{"{1}'.format(ID, content, m.group('operator'))
else:
tempbuffa += 'var/{0} {2}= {{"{1}'.format(ID, content, m.group('operator'))
tempfuckup = '{0}:{1}: {2}'.format(filename, ln, line.strip())
lastID = ID
lastLevel = level
else:
if line.strip() == '':
tempBackup += line
continue
if lastWasAlert:
buffa += '"}'
buffa += '\n' + indent + '// END AUTOFIX'
buffa += '\n'
lastWasAlert = False
tempBackup = ''
if tempBackup != '':
buffa += tempBackup
tempBackup = ''
lastID = ''
lastLevel = ''
buffa += line
fixpaths = ['code', 'interface', 'RandomZLevels', '_maps']
fixpath=filename
for fp in fixpaths:
fixpath = fixpath.replace(fp + os.sep, fp + '-fixed' + os.sep)
if len(fuckups) > 0:
if not os.path.isdir(os.path.dirname(fixpath)):
os.makedirs(os.path.dirname(fixpath))
with open(fixpath, 'w') as fixes:
fixes.write(buffa)
else:
if os.path.isfile(fixpath):
print('RM {0} ({1})'.format(fixpath,os.sep))
os.remove(fixpath)
# print(' Processed - {0} lines.'.format(ln))
return fuckups
def ProcessFilesFromDME(dmefile='baystation12.dme', ext='.dm'):
numFilesTotal = 0
fileFuckups = {}
rootdir = os.path.dirname(dmefile)
with open(os.path.join(rootdir, 'stringcounts.csv'), 'w') as csv:
with open(dmefile, 'r') as dmeh:
for line in dmeh:
if line.startswith('#include'):
inString = False
# escaped=False
filename = ''
for c in line:
"""
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
if
escaped = False
continue
"""
if c == '"':
inString = not inString
if not inString:
filepath = os.path.join(rootdir, filename)
if filepath.endswith(ext):
# print('Processing {0}...'.format(filepath))
fileFuckups[filepath] = ProcessFile(filepath)
numFilesTotal += 1
filename = ''
continue
else:
if inString:
filename += c
if os.path.isdir(sys.argv[1]):
for root, _, files in os.walk(sys.argv[1]):
for filename in files:
filepath = os.path.join(root, filename)
if filepath.endswith('.dme'):
ProcessFilesFromDME(filepath, sys.argv[2])
sys.exit(0)
if os.path.isfile(sys.argv[1]):
ProcessFilesFromDME(sys.argv[1], sys.argv[2])
-278
View File
@@ -1,278 +0,0 @@
#!/usr/bin/env python
"""
DMI SPLITTER-UPPER THING
Makes merging sprites a hell of a lot easier.
by N3X15 <nexis@7chan.org>
Requires PIL
Written for Python 2.7.
"""
import sys, os, traceback, fnmatch, argparse
from byond.DMI import DMI
args = ()
def main():
opt = argparse.ArgumentParser() # version='0.1')
opt.add_argument('-p', '--suppress-post-processing', dest='suppress_post_process', default=False, action='store_true')
command = opt.add_subparsers(help='The command you wish to execute', dest='MODE')
_disassemble = command.add_parser('disassemble', help='Disassemble a single DMI file to a destination directory')
_disassemble.add_argument('file', type=str, help='The DMI file to disassemble.', metavar='file.dmi')
_disassemble.add_argument('destination', type=str, help='The directory in which to dump the resulting images.', metavar='dest/')
_disassemble_all = command.add_parser('disassemble-all', help='Disassemble a directory of DMI files to a destination directory')
_disassemble_all.add_argument('source', type=str, help='The DMI files to disassemble.', metavar='source/')
_disassemble_all.add_argument('destination', type=str, help='The directory in which to dump the resulting images.', metavar='dest/')
_compile = command.add_parser('compile', help='Compile a .dmi.mak file')
_compile.add_argument('makefile', type=str, help='The .dmi.mak file to compile.', metavar='file.dmi.mak')
_compile.add_argument('destination', type=str, help='The location of the resulting .dmi file.', metavar='file.dmi')
_compare = command.add_parser('compare', help='Compare two DMI files and note the differences')
_compare.add_argument('theirs', type=str, help='One side of the difference', metavar='theirs.dmi')
_compare.add_argument('mine', type=str, help='The other side.', metavar='mine.dmi')
_compare_all = command.add_parser('compare-all', help='Compare two DMI file directories and note the differences')
_compare_all.add_argument('theirs', type=str, help='One side of the difference', metavar='theirs/')
_compare_all.add_argument('mine', type=str, help='The other side.', metavar='mine/')
_compare_all.add_argument('report', type=str, help='The file the report is saved to', metavar='report.txt')
_get_dmi_data = command.add_parser('get-dmi-data', help='Extract DMI header')
_get_dmi_data.add_argument('file', type=str, help='DMI file', metavar='file.dmi')
_get_dmi_data.add_argument('dest', type=str, help='The file where the DMI header will be saved', metavar='dest.txt')
_set_dmi_data = command.add_parser('set-dmi-data', help='Set DMI header')
_set_dmi_data.add_argument('file', type=str, help='One side of the difference', metavar='file.dmi')
_set_dmi_data.add_argument('metadata', type=str, help='DMI header file', metavar='metadata.txt')
_set_dmi_data = command.add_parser('clean', help='Clean up temporary files and *.new.dmi files.')
_set_dmi_data.add_argument('basedir', type=str, help='Starting directory', metavar='vgstation/')
args = opt.parse_args()
#print(args)
if args.MODE == 'compile':
make_dmi(args.makefile, args.destination, args)
if args.MODE == 'compare':
compare(args.theirs, args.mine, args, sys.stdout)
if args.MODE == 'compare-all':
compare_all(args.theirs, args.mine, args.report, args)
elif args.MODE == 'disassemble':
disassemble(args.file, args.destination, args)
elif args.MODE == 'disassemble-all':
disassemble_all(args.source, args.destination, args)
elif args.MODE == 'get-dmi-data':
get_dmi_data(args.file, args.dest, args)
elif args.MODE == 'set-dmi-data':
set_dmi_data(args.file, args.metadata, args)
elif args.MODE == 'cleanup':
cleanup(args.basedir, args)
else:
print('!!! Error, unknown MODE=%r' % args.MODE)
class ModeAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
# print('%s %s %s' % (namespace, values, option_string))
namespace.MODE = self.dest
namespace.args = values
def get_dmi_data(path, dest, parser):
if(os.path.isfile(path)):
dmi = DMI(path)
with open(dest, 'w') as f:
f.write(dmi.getHeader())
def set_dmi_data(path, headerFile, parser):
if(os.path.isfile(path)):
dmi = DMI(path)
with open(headerFile, 'r') as f:
dmi.setHeader(f.read(), path)
def make_dmi(path, dest, parser):
if(os.path.isfile(path)):
dmi = None
try:
dmi = DMI(dest)
dmi.make(path)
dmi.save(dest)
except SystemError as e:
print("!!! Received SystemError in %s, halting: %s" % (dmi.filename, traceback.format_exc(e)))
print('# of cells: %d' % len(dmi.states))
print('Image h/w: %s' % repr(dmi.size))
sys.exit(1)
except Exception as e:
print("Received error, continuing: %s" % traceback.format_exc())
def disassemble(path, to, parser):
print('\tD %s -> %s' % (path, to))
if(os.path.isfile(path)):
dmi = None
try:
dmi = DMI(path)
dmi.extractTo(to, parser.suppress_post_process)
except SystemError as e:
print("!!! Received SystemError in %s, halting: %s" % (dmi.filename, traceback.format_exc(e)))
print('# of cells: %d' % len(dmi.states))
print('Image h/w: %s' % repr(dmi.size))
sys.exit(1)
except Exception as e:
print("Received error, continuing: %s" % traceback.format_exc())
def compare(theirsfile, minefile, parser, reportstream, **kwargs):
# print('\tD %s -> %s' % (theirsfile, minefile))
theirs = []
theirsDMI = None
mine = []
mineDMI = None
states = []
new2mineFilename = minefile.replace('.dmi', '.new.dmi')
new2theirsFilename = theirsfile.replace('.dmi', '.new.dmi')
new2mine=None
if os.path.isfile(new2mineFilename):
os.remove(new2mineFilename)
if kwargs.get('newfile_mine',True):
new2mine = DMI(new2mineFilename)
new2theirs=None
if os.path.isfile(new2theirsFilename):
os.remove(new2theirsFilename)
if kwargs.get('newfile_theirs',False):
new2theirs = DMI(new2theirsFilename)
o = ''
if(os.path.isfile(theirsfile)):
try:
theirsDMI = DMI(theirsfile)
theirsDMI.loadAll()
theirs = theirsDMI.states
except SystemError as e:
print("!!! Received SystemError in %s, halting: %s" % (theirs.filename, traceback.format_exc(e)))
print('# of cells: %d' % len(theirs.states))
print('Image h/w: %s' % repr(theirs.size))
sys.exit(1)
except Exception as e:
print("Received error, continuing: %s" % traceback.format_exc())
o += "\n {0}: Received error, continuing: {1}".format(theirsfile, traceback.format_exc())
for stateName in theirs:
if stateName not in states:
states.append(stateName)
if(os.path.isfile(minefile)):
try:
mineDMI = DMI(minefile)
mineDMI.loadAll()
mine = mineDMI.states
except SystemError as e:
print("!!! Received SystemError in %s, halting: %s" % (mine.filename, traceback.format_exc(e)))
print('# of cells: %d' % len(mine.states))
print('Image h/w: %s' % repr(mine.size))
sys.exit(1)
except Exception as e:
print("Received error, continuing: %s" % traceback.format_exc())
o += "\n {0}: Received error, continuing: {1}".format(minefile, traceback.format_exc())
for stateName in mine:
if stateName not in states:
states.append(stateName)
for state in sorted(states):
inTheirs = state in theirs
inMine = state in mine
if inTheirs and not inMine:
o += '\n + {1}'.format(minefile, state)
if new2mine is not None:
new2mine.states[state] = theirsDMI.states[state]
elif not inTheirs and inMine:
o += '\n - {1}'.format(theirsfile, state)
if new2theirs is not None:
new2theirs.states[state] = mineDMI.states[state]
elif inTheirs and inMine:
if theirs[state].ToString() != mine[state].ToString():
o += '\n - {0}: {1}'.format(mine[state].displayName(), mine[state].ToString())
o += '\n + {0}: {1}'.format(theirs[state].displayName(), theirs[state].ToString())
elif kwargs.get('check_changed',True):
diff_count=0
for i in xrange(len(theirs[state].icons)):
theirF = theirs[state].icons[i]
myF = theirs[state].icons[i]
theirData = list(theirF.getdata())
myData = list(myF.getdata())
#diff = []
for i in xrange(len(theirData)):
dr = theirData[i][0] - myData[i][0]
dg = theirData[i][1] - myData[i][1]
db = theirData[i][2] - myData[i][2]
#diff[idx] = (abs(dr), abs(dg), abs(db))
if((dr != 0) or (dg != 0) or (db != 0)):
diff_count += 1
break
if diff_count > 0:
o += '\n ! {0}: {1} frames differ'.format(theirs[state].displayName(), diff_count)
if new2mine is not None:
new2mine.states[state] = theirsDMI.states[state]
if new2theirs is not None:
new2theirs.states[state] = mineDMI.states[state]
if o != '':
reportstream.write('\n--- {0}'.format(theirsfile))
reportstream.write('\n+++ {0}'.format(minefile))
reportstream.write(o)
if new2mine is not None:
if len(new2mine.states) > 0:
new2mine.save(new2mineFilename)
else:
if os.path.isfile(new2mineFilename):
os.remove(new2mineFilename)
#print('RM {0}'.format(new2mineFilename))
if new2theirs is not None:
if len(new2theirs.states) > 0:
new2theirs.save(new2theirsFilename)
else:
if os.path.isfile(new2theirsFilename):
os.remove(new2theirsFilename)
#print('RM {0}'.format(new2theirsFilename))
def cleanup(subject):
print('Cleaning...')
for root, _, filenames in os.walk(subject):
for filename in fnmatch.filter(filenames, '*.new.dmi'):
path = os.path.join(root, filename)
print('RM {0}'.format(path))
os.remove(path)
def disassemble_all(in_dir, out_dir, parser):
print('D_A %s -> %s' % (in_dir, out_dir))
for root, dirnames, filenames in os.walk(out_dir):
for filename in fnmatch.filter(filenames, '*.new.dmi'):
path = os.path.join(root, filename)
print('RM {0}'.format(path))
os.remove(path)
for root, dirnames, filenames in os.walk(in_dir):
for filename in fnmatch.filter(filenames, '*.dmi'):
path = os.path.join(root, filename)
to = os.path.join(out_dir, path.replace(in_dir, '').replace(os.path.basename(path), ''))
disassemble(path, to, parser)
def compare_all(in_dir, out_dir, report, parser, **kwargs):
with open(report, 'w') as report:
report.write('# DMITool Difference Report: {0} {1}'.format(os.path.abspath(in_dir), os.path.abspath(out_dir)))
for root, dirnames, filenames in os.walk(in_dir):
for filename in fnmatch.filter(filenames, '*.dmi'):
path = os.path.join(root, filename)
to = os.path.join(out_dir, path.replace(in_dir, '').replace(os.path.basename(path), ''))
to = os.path.join(to, filename)
path = os.path.abspath(path)
to = os.path.abspath(to)
compare(path, to, parser, report, **kwargs)
if __name__ == '__main__':
main()
-77
View File
@@ -1,77 +0,0 @@
#!/usr/bin/env python
'''
Created on Jan 5, 2014
@author: Rob
'''
import os, sys, argparse
from byond.basetypes import Atom, Proc
from byond import objtree, GetFilesFromDME
def processFile(tree, origin, destination, args):
atomsWritten=[]
origin = os.path.relpath(origin)
with open(destination, 'w') as f:
print('>>> {0}'.format(destination))
if args.reorganize:
for ak in sorted(tree.Atoms.keys()):
atom = tree.Atoms[ak]
for a in atomsWritten:
if atom.path.startswith(a): continue
#if atom.filename.replace(os.sep,'/') == sys.argv[2]:
if atom.filename == origin:
f.write(atom.DumpCode())
atomsWritten+=[atom.path]
else:
for thing in tree.fileLayouts[origin]:
ttype = thing[0]
if ttype == 'ATOMDEF':
f.write(thing[1] + '\n')
elif ttype == 'PROCDEF':
proc = tree.GetAtom(thing[1])
f.write(proc.DumpCode() + '\n')
elif ttype == 'VAR':
atom = tree.GetAtom(thing[1])
var = atom.properties[thing[2]]
f.write('\t{}\n'.format(var.DumpCode(thing[2])))
elif ttype == 'DEFINE':
name = thing[1]
value = thing[2]
f.write('#define {} {}\n'.format(name, value))
elif ttype == 'UNDEF':
name = thing[1]
f.write('#undef {}\n'.format(name))
elif ttype == 'COMMENT':
continue
else:
print('wot is ' + ttype + '?')
if __name__ == '__main__':
opt = argparse.ArgumentParser()
opt.add_argument('project', metavar="project.dme")
opt.add_argument('file', metavar="file.dm", default=None, nargs='?')
opt.add_argument('--reorganize', dest='reorganize', default=False, action='store_true', help="Reorganize the file's contents, instead of keeping current structure.")
opt.add_argument('--output','-o', dest='output', default='', help="Where to put the output (default: <file>.fixed)")
args = opt.parse_args()
tree = objtree.ObjectTree(preprocessor_directives=True)
tree.ProcessFilesFromDME(args.project)
atomsWritten = []
if args.file is not None and os.path.isfile(args.file):
output=args.output
if output=='':
output=args.file+'.fixed'
processFile(tree, args.file, output, args)
else:
for filename in GetFilesFromDME(args.project):
fixpath = filename.replace('code' + os.sep, 'code-indented' + os.sep)
fixpath = fixpath.replace('interface' + os.sep, 'interface-indented' + os.sep)
fixpath = fixpath.replace('RandomZLevels' + os.sep, 'RandomZLevels-indented' + os.sep)
fixdir = os.path.dirname(fixpath)
if not os.path.isdir(fixdir):
os.makedirs(fixdir)
fixpath = fixpath.replace('/', os.sep)
processFile(tree, filename, fixpath,args)
-229
View File
@@ -1,229 +0,0 @@
#!/usr/bin/env python
"""
dmm.py - Collection of map tools.
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import sys, argparse, os
from byond import ObjectTree, Map, MapRenderFlags
def main():
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('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')
_compare.add_argument('-O', '--output', dest='output', type=str, help='The other side.', metavar='mine.dmm')
#_compare = command.add_parser('patch', help='Apply a map patch.')
#_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')
_compare = command.add_parser('analyze', help='Generate a report of each atom on a map. WARNING: huge')
_compare.add_argument('map', type=str, help='Map to analyze.', metavar='map.dmm')
opt.add_argument('map', type=str, help='Map to fix.', metavar='map.dmm')
args = opt.parse_args()
if args.MODE == 'compare':
compare_dmm(args)
elif args.MODE == 'analyze':
analyze_dmm(args)
#elif args.MODE == 'patch':
# patch_dmm(args)
else:
print('!!! Error, unknown MODE=%r' % args.MODE)
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.readMap(args.theirs)
mine_dmm = Map(forgiving_atom_lookups=True)
mine_dmm.readMap(args.mine)
if theirs_dmm.width != mine_dmm.width:
print('Width is not equal: {} != {}.'.format(theirs_dmm.width, mine_dmm.width))
sys.exit(1)
if theirs_dmm.height != mine_dmm.height:
print('Height is not equal: {} != {}.'.format(theirs_dmm.height, mine_dmm.height))
sys.exit(1)
ttitle, _ = os.path.splitext(os.path.basename(args.theirs))
mtitle, _ = os.path.splitext(os.path.basename(args.mine))
output = '{} - {}.dmmpatch'.format(ttitle, mtitle)
if args.output:
output = args.output
with open(output, 'w') as f:
stats = {
'diffs':0,
'tilediffs':0
}
print('Comparing maps...')
for z in range(len(theirs_dmm.zLevels)):
for y in range(theirs_dmm.height):
for x in range(theirs_dmm.width):
CHANGES = {}
tTile = theirs_dmm.GetTileAt(x, y, z)
mTile = mine_dmm.GetTileAt(x, y, z)
theirs = tTile.GetAtoms()
mine = mTile.GetAtoms()
for atom in theirs + mine:
key = atom.MapSerialize()
change = None
if atom not in mine:
change = '-'
if atom not in theirs:
change = '+'
if change is not None:
CHANGES[key] = change
if len(CHANGES) > 0:
f.write('<{},{},{}>\n'.format(x, y, z))
stats['tilediffs'] += 1
for key, change in CHANGES.items():
f.write(' {} {}\n'.format(change, key))
stats['diffs'] += 1
print('Compared maps: {} differences in {} tiles.'.format(stats['diffs'],stats['tilediffs']))
def analyze_dmm(args):
tmpl_head = '''
<html>
<head>
<title>BYONDTools Map Analysis :: {TITLE}</title>
</head>
<body>
<h1>{TITLE}</h1>
<ul>
<li><a href="{ROOT}/instances/index.html">Instances</a></li>
<li><a href="{ROOT}/index.html">Tiles</a></li>
</ul>'''
tmpl_footer = '''
</body>
</html>
'''
presentable_attributes=[
'path',
'id',
'filename',
'line'
]
def MakePage(**kwargs):
rewt = '.'
depth = kwargs.get('depth', 0)
if depth > 0:
rewt = '/'.join(['..'] * depth)
title = kwargs.get('title', 'LOL NO TITLE')
body = kwargs.get('body', '')
return (tmpl_head + body + tmpl_footer).replace('{TITLE}', title).replace('{ROOT}', rewt)
if not os.path.isfile(args.project):
print('DM Environment file {0} does not exist.'.format(args.theirs))
sys.exit(1)
if not os.path.isfile(args.map):
print('Map {0} does not exist.'.format(args.theirs))
sys.exit(1)
tree = ObjectTree()
tree.ProcessFilesFromDME(args.project)
dmm = Map(tree)
dmm.readMap(args.map)
basedir = os.path.join(os.path.dirname(args.project), 'analysis', os.path.basename(args.map))
if not os.path.isdir(basedir):
os.makedirs(os.path.join(basedir,'instances'))
os.makedirs(os.path.join(basedir,'tiles'))
# Dump instances
instance_info = {}
for atom in dmm.instances:
if atom.path not in instance_info:
instance_info[atom.path] = []
instance_info[atom.path] += [atom.id]
with open(os.path.join(basedir, 'instances', str(atom.id) + '.html'), 'w') as f:
body = '<h2>Atom Data:</h2><table class="prettytable"><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody>'
for attr in presentable_attributes:
body += '<tr><th>{0}</th><td>{1}</td></tr>'.format(attr, getattr(atom, attr, None))
body += '</tbody></table>'
body += '<h2>Map-Specified Properties:</h2><table class="prettytable"><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody>'
for attr_name in atom.mapSpecified:
body += '<tr><th>{0}</th><td>{1}</td></tr>'.format(attr_name, atom.getProperty(attr_name, None))
body += '</tbody></table>'
body += '<h2>All Properties:</h2><table class="prettytable"><thead><tr><th>Name</th><th>Value</th><th>File/Line</th></tr></thead><tbody>'
for attr_name in sorted(atom.properties.keys()):
attr = atom.properties[attr_name]
body += '<tr><th>{0}</th><td>{1}</td><td>{2}:{3}</td></tr>'.format(attr_name, attr.value, attr.filename, attr.line)
body += '</tbody></table>'
f.write(MakePage(title='Instance #{0}'.format(atom.id), depth=1, body=body))
with open(os.path.join(basedir, 'instances', 'index.html'), 'w') as idx:
body = '<ul>'
for atype, instances in instance_info.items():
body += '<li><b>{0}</b><ul>'.format(atype)
for iid in instances:
body += '<li><a href="{{ROOT}}/instances/{0}.html">#{0}</a></li>'.format(iid)
body += '</ul></li>'
body += "</ul>"
idx.write(MakePage(title='Instance Index'.format(atom.id), depth=1, body=body))
# Tiles
with open(os.path.join(basedir, 'index.html'), 'w') as f:
body = '<table class="prettytable"><thead><tr><th>Icon</th><th>ID</th><th>Instances</th></tr></thead><tbody>'
for tile in dmm.tileTypes:
body += '<tr><td><img src="tiles/{0}.png" height="96" width="96" /></td><th>{0}</th><td><ul>'.format(tile.ID)
for atom in tile.SortAtoms():
body += '<li><a href="{{ROOT}}/instances/{0}.html">#{0}</a> - {1}</li>'.format(atom.id,atom.path)
body += '</ul></td></tr>'
img = tile.RenderToMapTile(0, os.path.dirname(sys.argv[1]), MapRenderFlags.RENDER_STARS)
if img is None: continue
pass_2 = tile.RenderToMapTile(1, os.path.dirname(sys.argv[1]), 0)
if pass_2 is not None:
img.paste(pass_2,(0,0,96,96),pass_2)
img.save(os.path.join(basedir, 'tiles', '{0}.png'.format(tile.ID)), 'PNG')
body += '</tbody></table>'
f.write(MakePage(title='Tile Index'.format(atom.id), depth=0, body=body))
if __name__ == '__main__':
main()
-120
View File
@@ -1,120 +0,0 @@
#!/usr/bin/env python
"""
fixMap.py - Apply various fixes to a map.
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import sys, argparse
from byond.map import Map
from byond.objtree import ObjectTree
#from byond.basetypes import BYONDString, BYONDValue, Atom, PropertyFlags
#from byond.directions import *
from byond import mapfixes
opt = argparse.ArgumentParser() # version='0.1')
opt.add_argument('-n', '--namespace', dest='namespaces', type=str, nargs='*', default=[], help='MapFix namespace to load (ss13, vgstation).')
opt.add_argument('-N', '--no-deps', dest='no_dependencies', action='store_true', help='Stop loading of namespace dependencies.')
opt.add_argument('-f', '--fix-script', dest='fixscripts', type=str, nargs='*', help='A script that specifies property and type replacements.')
opt.add_argument('dme', nargs='?', default='baystation12.dme', type=str,help='Project file.', metavar='environment.dme')
opt.add_argument('map', type=str,help='Map to fix.', metavar='map.dmm')
args = opt.parse_args()
actions = []
mapfixes.Load()
actions += mapfixes.GetFixesForNS(args.namespaces, not args.no_dependencies)
tree = ObjectTree()
tree.ProcessFilesFromDME(args.dme)
for fixscript in args.fixscripts:
with open(fixscript, 'r') as repl:
ln = 0
errors = 0
for line in repl:
ln += 1
if line.startswith('#'):
continue
if line.strip() == '':
continue
# PROPERTY: step_x > pixel_x
# TYPE: /obj/item/key > /obj/item/weapon/key/janicart
subject, action = line.split(':')
subject = subject.lower()
if subject == 'property':
old, new = action.split('>')
actions += [mapfixes.base.RenameProperty(old.strip(), new.strip())]
if subject == 'type' or subject == 'type!':
force = subject == 'type!'
old, new = action.split('>')
newtype = new.strip()
if tree.GetAtom(newtype) is None:
print('{0}:{1}: {2}'.format(sys.argv[2], ln, line.strip('\r\n')))
print(' ERROR: Unable to find replacement type "{0}".'.format(newtype))
errors += 1
actions += [mapfixes.base.ChangeType(old.strip(), newtype, force)]
if errors > 0:
print('!!! {0} errors, please fix them.'.format(errors))
sys.exit(1)
print('Changes to make:')
for action in actions:
print(' * ' + str(action))
dmm = Map(tree, forgiving_atom_lookups=1)
dmm.readMap(args.map)
dmm.writeMap2(args.map.replace('.dmm', '.dmm2'))
for iid in xrange(len(dmm.instances)):
atom = dmm.getInstance(iid)
changes = []
for action in actions:
action.SetTree(tree)
if action.Matches(atom):
atom = action.Fix(atom)
changes += [str(action)]
atom.id = iid
'''
compiled_atom = tree.GetAtom(atom.path)
if compiled_atom is not None:
for propname in list(atom.properties.keys()):
if propname not in compiled_atom.properties and propname not in ('req_access_txt','req_one_access_txt'):
del atom.properties[propname]
if propname in atom.mapSpecified:
atom.mapSpecified.remove(propname)
changes += ['Dropped property {0} (not found in compiled atom)'.format(propname)]
'''
dmm.setInstance(iid, atom)
if len(changes) > 0:
print('{0} (#{1}):'.format(atom.path, atom.id))
for change in changes:
print(' * ' + change)
#for atom, _ in atomsToFix.items():
# print('Atom {0} needs id_tag.'.format(atom))
with open(args.map + '.missing', 'w') as f:
for atom in sorted(dmm.missing_atoms):
f.write(atom + "\n")
print('--- Saving...')
dmm.writeMap(args.map + '.fixed', Map.WRITE_OLD_IDS)
dmm.writeMap2(args.map.replace('.dmm', '.dmm2') + '.fixed')
-96
View File
@@ -1,96 +0,0 @@
#!/usr/bin/env python
import os, argparse, logging, sys
# Tell Python where to find BYONDTools.
# Assuming we're in icons/mob/in-hand
sys.path.append('../../../tools/BYONDTools') # For byond
sys.path.append('../../../tools/BYONDTools/scripts') # For dmi
from byond.objtree import ObjectTree
from byond.basetypes import Atom
from byond.map import Map, MapRenderFlags
"""
Usage:
$ python dmmrender.py path/to/your/project.dme path/to/your/map.dmm
generateMap.py - Creates an image of a DMM map.
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
def renderMap(args):
outfile = args.map + '.{z}.png'
if args.area:
kwargs['area'] = args.area
outfile = args.area[0].replace('/', '_') + '.png'
if args.render_types:
print(repr(args.render_types))
kwargs['render_types'] = args.render_types
if args.outfile:
outfile = args.outfile
if os.path.isdir(outfile):
title, _ = os.path.splitext(os.path.basename(args.map))
outfile = os.path.join(outfile, '{}.{{z}}.png'.format(title))
dmm.generateImage(outfile, os.path.dirname(args.project), renderflags, **kwargs)
logging.basicConfig(
format='%(asctime)s [%(levelname)-8s]: %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p',
level=logging.INFO # ,
# filename='logs/main.log',
# filemode='w'
)
opt = argparse.ArgumentParser()
opt.add_argument('project', metavar="project.dme")
opt.add_argument('map', metavar="map.dmm")
opt.add_argument('--render-stars', dest='render_stars', default=False, action='store_true', help="Render space. Normally off to prevent ballooning the image size.")
opt.add_argument('--render-areas', dest='render_areas', default=False, action='store_true', help="Render area overlays.")
opt.add_argument('--render-only', dest='render_types', action='append', help="Render ONLY these types. Can be used multiple times to specify more types.")
opt.add_argument('--area', dest='area', type=list, nargs='*', default=None, help="Specify an area to restrict rendering to.")
opt.add_argument('-O', '--out', dest='outfile', type=str, default=None, help="What to name the file ({z} will be replaced with z-level)")
opt.add_argument('--area-list', dest='areas', type=str, default=None, help="A file with area_file.png = /area/path on each line")
args = opt.parse_args()
if os.path.isfile(args.project):
tree = ObjectTree()
tree.ProcessFilesFromDME(args.project)
dmm = Map(tree)
dmm.readMap(args.map)
renderflags = 0
if args.render_stars:
renderflags |= MapRenderFlags.RENDER_STARS
if args.render_areas:
renderflags |= MapRenderFlags.RENDER_AREAS
kwargs = {}
if args.areas:
with open(args.areas) as f:
for line in f:
if line.startswith("#"):
continue
if '=' not in line:
continue
outfile, area = line.split('=')
args.area = area.strip().split(',')
args.outfile = outfile.strip()
renderMap(args)
else:
renderMap(args)
-210
View File
@@ -1,210 +0,0 @@
#!/usr/bin/env python
from byond.DMI import DMI,State
from byond import directions
import os, sys, shutil
import ImageChops
import math, operator
from PIL import Image
def rmsdiff(im1, im2):
"Calculate the root-mean-square difference between two images"
diff = ImageChops.difference(im1, im2)
h = diff.histogram()
sq = (value * (idx ** 2) for idx, value in enumerate(h))
sum_of_squares = sum(sq)
rms = math.sqrt(sum_of_squares / float(im1.size[0] * im1.size[1]))
return rms
def equal(im1, im2):
return ImageChops.difference(im1, im2).getbbox() is None
quadDefs = [
# x1,y1,x2,y2
[0, 0, 15, 15],
[16, 0, 31, 15],
[0, 16, 15, 31],
[16, 16, 31, 31]
]
extract = [
'floor',
# 'redcorner',
'white',
'dark',
'bar',
'cafeteria',
'redfull',
'whiteredfull',
'bluefull',
'whitebluefull',
'greenfull',
'whitegreenfull',
'yellowfull',
'whiteyellowfull',
'neutralfull',
'orangefull',
'purplefull',
'whitepurplefull',
'floorgrime',
'brown',
'vaultfull'
]
colors = [
'red',
'whitered',
'blue',
'whiteblue',
'green',
'whitegreen',
'yellow',
'whiteyellow',
'neutral',
'orange',
'purple',
'whitepurple',
'grime',
'brown',
'vault'
]
arrangements={
'stripe': [
[False,False,True,True], # S
[True,True,False,False], # N
[False,True,False,True], # E
[True,False,True,False], # W
[False,True,True,True], # SE
[True,False,True,True], # SW
[True,True,False,True], # NE
[True,True,True,False], # NW
],
'corner': [
[False,False,False,True], # S
[True,False,False,False], # N
[False,True,False,False], # E
[False,False,True,False], # W
],
'full': [
[True,True,True,True]
]
}
tileDefs={
'white':{
'base':'white',
'arrangements':['stripe','corner','full'],
'colors':['whitered','whiteblue','whitegreen','whitegreen','whiteyellow','whitepurple']
},
'grey':{
'base':'floor',
'arrangements':['stripe','corner','full'],
'colors':[
'red',
'blue',
'green',
'yellow',
'neutral',
'orange',
'purple',
'brown',
'white'
]
},
'dark':{
'base':'dark',
'arrangements':['stripe','corner','full'],
'colors':[
'floor',
'red',
'blue',
'green',
'yellow',
'neutral',
'orange',
'purple',
'brown',
'vault'
]
}
}
knownQuads = [
{}, {}, {}, {}
]
def isKnownQuad(i, im, icon_state):
for name, kq in knownQuads[i].items():
if equal(kq, im):
return True
return False
floors = DMI(sys.argv[1])
floors.loadAll()
basedir = 'floor_quads'
if os.path.isdir('floor_quads'):
shutil.rmtree(basedir)
os.makedirs('floor_quads')
for icon_state in extract:
if icon_state not in floors.states:
print('Can\'t find state {0}!'.format(icon_state))
continue
for d in range(floors.states[icon_state].dirs):
dirf = 0
dirn = 'SOUTH'
if floors.states[icon_state].dirs > 1:
dirf = directions.IMAGE_INDICES[d]
dirn = directions.getNameFromDir(dirf)
print('{0} {1} {2}'.format(icon_state, dirn, floors.states[icon_state].dirs))
img = floors.getFrame(icon_state, dirf, 0)
for i in range(len(quadDefs)):
quad = img.crop(quadDefs[i])
if isKnownQuad(i, quad, icon_state):
print(' Skipping quad #{}'.format(i + 1))
continue
color = icon_state
if color.endswith('full'):
color = color[:-4]
qpath = os.path.join(basedir, str(i))
qfile = os.path.join(qpath, '{0}.png'.format(color))
if not os.path.isdir(qpath):
os.makedirs(qpath)
quad.save(qfile, 'PNG')
knownQuads[i][color] = quad
nfloors = DMI('nfloors.dmi')
for tileName,tileDef in tileDefs.items():
base = floors.getFrame(tileDef['base'],directions.SOUTH,0)
for color in tileDef['colors']:
for arrangement in tileDef['arrangements']:
arrname=''
arrange=[False,False,False,False]
if isinstance(arrangement,str):
arrange=arrangements[arrangement]
arrname=arrangement
elif isinstance(arrangement,list):
arrange=arrangement[1:]
arrname=arrangement[0]
state='{base} {color} {arrangement}'.format(base=tileDef['base'],color=color,arrangement=arrname)
nstate=State(state)
nstate.dirs=len(arrange)
nstate.frames=1
nstate.icons=[None for _ in range(nstate.dirs)]
#statedebug = DMI(state+'.dmi')
nfloors.states[state]=nstate
for d in range(len(arrange)):
cmap = arrange[d]
dirf = 0
dirn = 'SOUTH'
if len(arrange) > 1:
dirf = directions.IMAGE_INDICES[d]
dirn = directions.getNameFromDir(dirf)
print(' Generating state {0} ({1})...'.format(repr(state),dirn))
#print(repr(arrange))
img=Image.new('RGBA',(32,32))
img.paste(base)
for i in range(len(cmap)):
bbox=quadDefs[i]
if cmap[i]:
img.paste(knownQuads[i][color],bbox)
nfloors.setFrame(state, dirf, 0, img)
#statedebug.states[state]=nfloors.states[state]
#statedebug.save(state+'.dmi')
nfloors.save('nfloors.dmi')
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env python
'''
Created on Feb 28, 2014 to test a bug in DreamMaker.
Requires arial font.
'''
from byond.DMI import DMI, State
from PIL import Image, ImageDraw, ImageFont
def makeDMI():
dmi = DMI('state_limit.dmi')
#
for i in range(513):
# Make a new tile
img = Image.new('RGBA', (32, 32))
# Set up PIL's drawing stuff
draw = ImageDraw.Draw(img)
# Define a font.
font = ImageFont.truetype('arial.ttf', 10)
# Draw the tile number
draw.text((10, 0), str(i + 1), (0, 0, 0), font=font)
# Make state
state_name='state {0}'.format(i+1)
state=State(state_name)
state.dirs=1
state.frames=1
state.icons=[img]
# Add state to DMI
dmi.states[state_name]=state
#save
dmi.save('state_limit.dmi', sort=False)
if __name__ == '__main__':
makeDMI()
File diff suppressed because it is too large Load Diff
@@ -1,28 +0,0 @@
#!/usr/bin/env python
'''
Created on Apr 29, 2014
@author: Rob
'''
import argparse,os
from byond.objtree import ObjectTree
from byond.basetypes import Proc
def dumpSubTypes(atom):
print('{}:{}: {}'.format(atom.filename,atom.line,atom.path))
for rpath,catom in atom.children.items():
if not isinstance(catom,Proc):
dumpSubTypes(catom)
if __name__ == '__main__':
opt = argparse.ArgumentParser()
opt.add_argument('project', metavar="project.dme")
opt.add_argument('--subtypes',type=str,help="List all subtypes of the given type")
args = opt.parse_args()
if os.path.isfile(args.project):
tree = ObjectTree()
tree.ProcessFilesFromDME(args.project)
if args.subtypes:
atom = tree.GetAtom(args.subtypes)
dumpSubTypes(atom)
-121
View File
@@ -1,121 +0,0 @@
#!/usr/bin/env python
import sys, re
from byond.basetypes import Proc
from byond.objtree import ObjectTree
class CodeScan:
def __init__(self, id):
self.id = id
self.atom = None
self.proc = None
def SetContext(self, atom, proc):
self.atom = atom
self.proc = proc
def MatchAtom(self, atom):
return True
def MatchProc(self, atom, proc):
return True
def ScanLine(self, line):
return []
class RegexScanner(CodeScan):
def __init__(self, id, regex, warning, in_procnames=()):
CodeScan.__init__(self, id)
self.regex = regex
self.warning = warning
self.in_procnames = in_procnames
def MatchProc(self, atom, proc):
# print(proc.path)
return self.in_procnames == () or proc.name in self.in_procnames
def ScanLine(self, line):
m = self.regex.search(line)
if m is not None:
return [self.warning]
return []
rules = [
RegexScanner(
id='sleep-in-process',
warning='sleep() should not be used in process().',
regex=re.compile(r'\bsleep\(([0-9]+)\)\b'),
in_procnames=('process')
),
RegexScanner(
id='spawn-in-process',
warning='spawn() should not be used in process().',
regex=re.compile(r'\bspawn(\(([0-9]*)\))?\b'),
in_procnames=('process')
),
RegexScanner(
id='del-in-ex_act',
warning='del() should not be used in ex_act(). Consider replacing with qdel.',
regex=re.compile(r'\bdel(\(.*\))?\b'),
in_procnames=('ex_act')
),
]
otr = ObjectTree()
otr.ProcessFilesFromDME(sys.argv[1], '.dm')
procs = 0
alerts = 0
for path in otr.Atoms:
atom = otr.GetAtom(path)
if isinstance(atom,Proc): continue
proceed = False
skipping = []
for rule in rules:
if rule.MatchAtom(atom):
proceed = True
else:
skipping += [rule]
if not proceed: continue
for childName in atom.children:
warnings = {}
child = atom.children[childName]
if isinstance(child, Proc):
proceed = False
for rule in rules:
if rule not in skipping and rule.MatchProc(atom, child):
proceed = True
else:
skipping += [rule]
if not proceed: continue
'''
if 'process' in path + ' - ' + childName:
print(path + ' - ' + childName)
'''
# print(path + ' - ' + childName)
procs += 1
min_indent = child.getMinimumIndent()
# Should be 1, so find the difference.
indent_delta = 1 - min_indent
for i in range(len(child.code)):
line_warnings = []
indent, code = child.code[i]
indent = max(1, indent + indent_delta)
if code.strip() == '':
o = '\n'
else:
o = (indent * '\t') + code.strip() + '\n'
code = o.strip('\n\r')
for rule in rules:
if rule in skipping: continue
rule.SetContext(atom, child)
line_warnings += rule.ScanLine(code)
if len(line_warnings):
warnings['{0}:{1}: {2}'.format(child.filename, child.line + i, code)] = line_warnings
alerts += len(line_warnings)
if len(warnings) > 0:
print('IN {0}/{1}:'.format(path, childName))
for context in warnings:
print(' {0}'.format(context))
for warning in warnings[context]:
print(' WARNING: {0}'.format(warning))
print('{0} processed procs, {1} alerts raised'.format(procs, alerts))
@@ -1,83 +0,0 @@
#!/usr/bin/env python
'''
Run within icons/mob/in-hand.
Usage:
$ cd icons/mob/in-hands
$ python ss13_makeinhands.py
ss13_makeinhands.py - Generates a large DMI from several smaller DMIs.
Specifically used for making icons/mob/items_(left|right)hand.dmi
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
'''
import os, sys, logging
ToBuild = {
# ' file to build': 'directory to pull from/',
'../items_lefthand.dmi': 'left/',
'../items_righthand.dmi': 'right/'
}
# Tell Python where to find BYONDTools.
# Assuming we're in icons/mob/in-hand
sys.path.append('../../../tools/BYONDTools') # For byond
sys.path.append('../../../tools/BYONDTools/scripts') # For dmi
from byond.DMI import DMI
from dmi import compare_all
def buildDMI(directory, output):
dmi = DMI(output)
logging.info('Creating {0}...'.format(output))
for root, _, files in os.walk(directory):
for filename in files:
if filename.endswith('.dmi') and not filename.endswith('.new.dmi'):
filepath = os.path.join(root, filename)
logging.info('Adding {0}...'.format(filename, output))
subdmi = DMI(filepath)
subdmi.loadAll()
if subdmi.icon_height != 32 or subdmi.icon_width != 32:
logging.warn('Skipping {0} - Invalid icon size.'.format(filepath))
changes = 0
for state_name in subdmi.states:
if state_name in dmi.states:
logging.warn('Skipping state {0}:{1} - State exists.'.format(filepath, subdmi.states[state_name].displayName()))
continue
dmi.states[state_name] = subdmi.states[state_name]
changes += 1
logging.info('Added {0} states.'.format(changes))
# save
logging.info('Saving {0} states to {1}...'.format(len(dmi.states), output))
dmi.save(output)
if __name__ == '__main__':
logging.basicConfig(
format='%(asctime)s [%(levelname)-8s]: %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p',
level=logging.INFO # ,
# filename='logs/main.log',
# filemode='w'
)
# Cheating, but useful for checking for unsync'd stuff
compare_all('left/', 'right/', 'in-hand_sync_report.txt', None, newfile_theirs=False, newfile_mine=False, check_changed=False)
for output, input_dir in ToBuild.items():
buildDMI(input_dir, output)
-209
View File
@@ -1,209 +0,0 @@
#!/usr/bin/env python
import os, sys
"""
Usage:
$ python countstrings.py path/to/your.dme .dm
CountStrings.py - Counts strings in DreamMaker code
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
def CountStringsIn(filename):
with open(filename, 'r') as f:
with open(filename + '.str', 'w') as debug:
numStrings = 0
inString = False
inMegaString = False
blockCommentLevel = 0
embeddedLevel = 0
lastChar = ''
escaped = False
buffer = ''
while(True):
c = f.read(1)
if not c:
if inString:
print('{0}: UNTERMINATED STRING!'.format(filename))
return numStrings
if not inString:
if c == '/':
if lastChar == '/' and blockCommentLevel == 0:
# debug.write("[LINECOMMENT:{0}]".format(f.tell()))
# Seek to EOL.
while(c not in '\r\n'):
c = f.read(1)
# debug.write("[ENDCOMMENT:{0}]".format(f.tell()))
lastChar = ''
continue
if c == '*':
if lastChar == '/':
# debug.write("[BLOCKCOMMENT:{0}]".format(f.tell()))
blockCommentLevel += 1
while(blockCommentLevel > 0):
c = f.read(1)
if not c:
return numStrings
if c == '*':
if lastChar == '/':
blockCommentLevel += 1
elif c == '/':
if lastChar == '*':
blockCommentLevel -= 1
lastChar = c
# debug.write("[ENDCOMMENT:{0}]".format(f.tell()))
lastChar = ''
continue
elif c == '"':
if lastChar == '{':
# debug.write("[MEGASTRING:{0}]".format(f.tell()))
inString = True
inMegaString = True
continue
else:
inString = True
# debug.write("[NEWSTRING:{0}]".format(f.tell()))
inMegaString = False
continue
elif c == '{':
lastChar = c
continue
else:
lastChar = c
else:
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
escaped = False
# debug.write("[ESCAPE:{0}]".format(repr(c)))
if inString:
buffer += '\\' + c
lastChar = c
continue
if c in ('[', ']'):
if c == '[':
embeddedLevel += 1
else:
embeddedLevel -= 1
buffer += c # +"<{0}>".format(str(embeddedLevel))
lastChar = c
continue
if embeddedLevel > 0:
buffer += c
lastChar = c
continue
if inMegaString:
if c == '}' and lastChar == '"':
# debug.write("[ENDMEGASTRING]")
inString = False
inMegaString = False
escaped = False
numStrings += 1
debug.write("\n[{0}]={1}".format(numStrings, repr(buffer)))
buffer = ''
continue
else:
if c == '"':
inString = False
# debug.write("[ENDSTRING:{0}]".format(f.tell()))
numStrings += 1
escaped = False
debug.write("\n[{0}]={1}".format(numStrings, repr(buffer)))
buffer = ''
continue
buffer += c
lastChar = c
return numStrings
def ProcessFiles(top='.', ext='.dm'):
numStringsTotal = 0
numStrings = 0
numFilesTotal = 0
maxStringsInFile = [0, '']
for root, _, files in os.walk(top):
for filename in files:
filepath = os.path.join(root, filename)
if filepath.endswith(ext):
numStrings = CountStringsIn(filepath)
numStringsTotal += numStrings
if numStrings > maxStringsInFile[0]:
maxStringsInFile = [numStrings, filepath]
numFilesTotal += 1
print(','.join([filepath, str(numStrings)]))
print('>>> Total Strings: {0}'.format(numStringsTotal))
print('>>> Total Files: {0}'.format(numFilesTotal))
print('>>> Max Strings: {0} in {1}'.format(maxStringsInFile[0], maxStringsInFile[1]))
def ProcessFilesFromDME(dmefile='baystation12.dme', ext='.dm'):
numStringsTotal = 0
numStrings = 0
numFilesTotal = 0
maxStringsInFile = [0, '']
rootdir = os.path.dirname(dmefile)
with open(os.path.join(rootdir, 'stringcounts.csv'), 'w') as csv:
with open(dmefile, 'r') as dmeh:
for line in dmeh:
if line.startswith('#include'):
inString = False
# escaped=False
filename = ''
for c in line:
"""
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
if
escaped = False
continue
"""
if c == '"':
inString = not inString
if not inString:
filepath = os.path.join(rootdir, filename)
if filepath.endswith(ext):
numStrings = CountStringsIn(filepath)
numStringsTotal += numStrings
if numStrings > maxStringsInFile[0]:
maxStringsInFile = [numStrings, filepath]
numFilesTotal += 1
csv.write(','.join([filepath, str(numStrings)]) + "\n")
filename = ''
continue
else:
if inString:
filename += c
print('>>> Total Strings: {0}'.format(numStringsTotal))
print('>>> Total Files: {0}'.format(numFilesTotal))
print('>>> Max Strings: {0} in {1}'.format(maxStringsInFile[0], maxStringsInFile[1]))
if os.path.isdir(sys.argv[1]):
for root, _, files in os.walk(sys.argv[1]):
for filename in files:
filepath = os.path.join(root, filename)
if filepath.endswith('.dme'):
ProcessFilesFromDME(filepath, sys.argv[2])
sys.exit(0)
if os.path.isfile(sys.argv[1]):
ProcessFilesFromDME(sys.argv[1], sys.argv[2])
# ProcessFiles(sys.argv[1], sys.argv[2])
-48
View File
@@ -1,48 +0,0 @@
import glob, os, sys
from setuptools import setup
from setuptools.command.install import install as _install
scripts = [
'dmm',
'dmi',
'dmindent',
'dmmrender',
'dmmfix',
'ss13_makeinhands'
]
def _post_install(dir):
from subprocess import call
print('dir={}'.format(dir))
call([sys.executable, 'byondtools-postinstall.py'], cwd=dir)
class install(_install):
def run(self):
_install.run(self)
# install_lib
self.execute(_post_install, (self.install_scripts,), msg="Running post install task")
options = {}
if sys.platform == "win32":
scripts.append("byondtools-postinstall")
scripts = ['scripts/{}.py'.format(x) for x in scripts]
setup(name='BYONDTools',
version='0.1.0',
description='Tools and interfaces for interacting with the BYOND game engine.',
url='http://github.com/N3X15/BYONDTools',
author='N3X15',
author_email='nexisentertainment@gmail.com',
license='MIT',
packages=['byond'],
install_requires=[
'Pillow'
],
tests_require=['unittest-xml-reporting'],
test_suite='tests',
scripts=scripts,
zip_safe=False,
cmdclass={'install': install})
-27
View File
@@ -1,27 +0,0 @@
'''
Created on Jan 1, 2014
@author: Rob
'''
import unittest
class AtomTest(unittest.TestCase):
def test_copy_consistency(self):
from byond.basetypes import Atom, BYONDString, BYONDValue
atom = Atom('/datum/test',__file__,0)
atom.properties={
'dir': BYONDValue(2),
'name': BYONDString('test datum')
}
atom.mapSpecified=['dir','name']
atom2=atom.copy()
atom_serialized=atom.MapSerialize()
atom2_serialized=atom2.MapSerialize()
self.assertEqual(atom_serialized, atom2_serialized)
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
-70
View File
@@ -1,70 +0,0 @@
'''
Created on Jan 1, 2014
@author: Rob
'''
import unittest
class MapParserTest(unittest.TestCase):
def setUp(self):
from byond.map import Map, Tile
self.dmm = 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)'
out = self.dmm.consumeTile(testStr, 0)
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):
from byond.map import Map, Tile
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)
if __name__ == "__main__":
# import sys;sys.argv = ['', 'Test.testName']
unittest.main()
-35
View File
@@ -1,35 +0,0 @@
'''
Created on Feb 26, 2014
@author: Rob
'''
import unittest
#from byond.map import Map
'''
class MapRenderingTest(unittest.TestCase):
def setUp(self):
self.dmm = Map()
def test_basic_bbox(self):
correct_bbox=(
3584,4382,
3616,4414
)
# 1126, 440
# 1126, 470
#3584, 4288
tile_x,tile_y=(112,134)
pixel_x=0
pixel_y=-30
icon_height=32
icon_width=32
bbox = self.dmm.tilePosToBBox(tile_x, tile_y, pixel_x,pixel_y, icon_height,icon_width)
self.assertTupleEqual(correct_bbox, bbox)
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()'''
-74
View File
@@ -1,74 +0,0 @@
'''
Created on Jan 5, 2014
@author: Rob
'''
import unittest
class ObjectTreeTests(unittest.TestCase):
def setUp(self):
from byond.objtree import ObjectTree
self.tree = ObjectTree()
def test_consumeVariable_basics(self):
test_string = 'var/obj/item/weapon/chainsaw = new'
name, data = self.tree.consumeVariable(test_string, '', 0)
self.assertEqual(name, 'chainsaw')
self.assertEqual(data.type, '/obj/item/weapon')
self.assertEqual(data.value, 'new')
self.assertEqual(data.declaration, True)
self.assertEqual(data.inherited, False)
self.assertEqual(data.special, None)
def test_consumeVariable_alternate_array_declaration_01(self):
test_string = 'var/appearance_keylist[0]'
name, data = self.tree.consumeVariable(test_string, '', 0)
self.assertEqual(name, 'appearance_keylist')
self.assertEqual(data.type, '/list')
self.assertEqual(data.value, None)
self.assertEqual(data.size, 0)
self.assertEqual(data.declaration, True)
self.assertEqual(data.inherited, False)
self.assertEqual(data.special, None)
def test_consumeVariable_alternate_array_declaration_02(self):
test_string = 'var/medical[] = list()'
name, data = self.tree.consumeVariable(test_string, '', 0)
self.assertEqual(name, 'medical')
self.assertEqual(data.type, '/list')
self.assertEqual(data.value, None)
self.assertEqual(data.size, -1)
self.assertEqual(data.declaration, True)
self.assertEqual(data.inherited, False)
self.assertEqual(data.special, None)
def test_consumeVariable_complex_types(self):
test_string = 'var/datum/gas_mixture/air_temporary'
name, data = self.tree.consumeVariable(test_string, '', 0)
self.assertEqual(name, 'air_temporary')
self.assertEqual(data.type, '/datum/gas_mixture')
self.assertEqual(data.value, None)
self.assertEqual(data.size, None)
self.assertEqual(data.declaration, True)
self.assertEqual(data.inherited, False)
self.assertEqual(data.special, None)
def test_consumeVariable_file_ref(self):
test_string = 'icon = \'butts.dmi\''
name, data = self.tree.consumeVariable(test_string, '', 0)
self.assertEqual(name, 'icon')
self.assertEqual(data.type, '/icon')
self.assertEqual(str(data.value), 'butts.dmi')
self.assertEqual(data.size, None)
self.assertEqual(data.declaration, False)
self.assertEqual(data.inherited, False)
self.assertEqual(data.special, None)
if __name__ == "__main__":
#import sys;sys.argv = ['', 'Test.testName']
unittest.main()
-9
View File
@@ -1,9 +0,0 @@
import unittest
from Atom import *
from MapParser import *
from MapRendering import *
from ObjectTree import *
if __name__ == "__main__":
unittest.main()
-13
View File
@@ -1,13 +0,0 @@
# Tox (http://tox.testrun.org/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
[tox]
envlist = py27
[testenv:py27]
deps =
pytest
Pillow
commands = py.test tests/runtests.py --junit-xml=pyunit-py27.xml
Binary file not shown.
-53
View File
@@ -1,53 +0,0 @@
/*
Written by contributor Doohl for the /tg/station Open Source project, hosted on Google Code.
(2012)
*/
var/list/config_stream = list()
var/list/servers = list()
var/list/servernames = list()
var/list/adminfiles = list()
var/list/adminkeys = list()
proc/gen_configs()
config_stream = dd_file2list("config.txt")
var/server_gen = 0 // if the stream is looking for servers
var/admin_gen = 0 // if the stream is looking for admins
for(var/line in config_stream)
if(line == "\[SERVERS\]")
server_gen = 1
if(admin_gen)
admin_gen = 0
else if(line == "\[ADMINS\]")
admin_gen = 1
if(server_gen)
server_gen = 0
else
if(findtext(line, ".") && !findtext(line, "##"))
if(server_gen)
var/filterline = replacetext(line, " ", "")
var/serverlink = copytext(filterline, findtext( filterline, ")") + 1)
servers.Add(serverlink)
servernames.Add( copytext(line, findtext(line, "("), findtext(line, ")") + 1))
else if(admin_gen)
adminfiles.Add(line)
world << line
// Generate the list of admins now
for(var/file in adminfiles)
var/admin_config_stream = dd_file2list(file)
for(var/line in admin_config_stream)
var/akey = copytext(line, 1, findtext(line, " "))
adminkeys.Add(akey)
Binary file not shown.
-21
View File
@@ -1,21 +0,0 @@
// DM Environment file for Redirect_Tgstation.dme.
// All manual changes should be made outside the BEGIN_ and END_ blocks.
// New source code should be placed in .dm files: choose File/New --> Code File.
// BEGIN_INTERNALS
// END_INTERNALS
// BEGIN_FILE_DIR
#define FILE_DIR .
// END_FILE_DIR
// BEGIN_PREFERENCES
// END_PREFERENCES
// BEGIN_INCLUDE
#include "Configurations.dm"
#include "Redirector.dm"
#include "textprocs.dm"
#include "skin.dmf"
// END_INCLUDE
-87
View File
@@ -1,87 +0,0 @@
/*
Written by contributor Doohl for the /tg/station Open Source project, hosted on Google Code.
(2012)
*/
/* TODO: work on server selection for detected admins */
#define ADMINS 1
#define PLAYERS 0
var/player_weight = 1 // players are more likely to join a server with less players
var/admin_weight = 5 // admins are more likely to join a server with less admins
var/player_substr = "players=" // search for this substring to locate # of players
var/admin_substr = "admins=" // search for this to locate # of admins
world
name = "TGstation Redirector"
New()
..()
gen_configs()
/datum/server
var/players = 0
var/admins = 0
var/weight = 0 // lower weight is good; highet weight is bad
var/link = ""
mob/Login()
..()
var/list/weights = list()
var/list/servers = list()
for(var/x in global.servers)
world << "[x] [servernames[ global.servers.Find(x) ]]"
var/info = world.Export("[x]?status")
var/datum/server/S = new()
S.players = extract(info, PLAYERS)
S.admins = extract(info, ADMINS)
S.weight += player_weight * S.players
S.link = x
world << S.players
world << S.admins
weights.Add(S.weight)
servers.Add(S)
var/lowest = min(weights)
var/serverlink
for(var/datum/server/S in servers)
if(S.weight == lowest)
serverlink = S.link
src << link(serverlink)
proc/extract(var/data, var/type = PLAYERS)
var/nextpos = 0
if(type == PLAYERS)
nextpos = findtextEx(data, player_substr)
nextpos += length(player_substr)
else
nextpos = findtextEx(data, admin_substr)
nextpos += length(admin_substr)
var/returnval = ""
for(var/i = 1, i <= 10, i++)
var/interval = copytext(data, nextpos + (i-1), nextpos + i)
if(interval == "&")
break
else
returnval += interval
return returnval
-12
View File
@@ -1,12 +0,0 @@
[SERVERS]
## Simply enter a list of servers to poll. Be sure to specify a server name in parentheses.
(Sibyl #1) byond://game.nanotrasen.com:1337
(Sibyl #2) byond://game.nanotrasen.com:2337
[ADMINS]
## Specify some standard Windows filepaths (you may use relative paths) for admin txt lists to poll.
C:\SS13\config\admins.txt
-149
View File
@@ -1,149 +0,0 @@
macro "macro"
elem
name = "North+REP"
command = ".north"
is-disabled = false
elem
name = "South+REP"
command = ".south"
is-disabled = false
elem
name = "East+REP"
command = ".east"
is-disabled = false
elem
name = "West+REP"
command = ".west"
is-disabled = false
elem
name = "Northeast+REP"
command = ".northeast"
is-disabled = false
elem
name = "Northwest+REP"
command = ".northwest"
is-disabled = false
elem
name = "Southeast+REP"
command = ".southeast"
is-disabled = false
elem
name = "Southwest+REP"
command = ".southwest"
is-disabled = false
elem
name = "Center+REP"
command = ".center"
is-disabled = false
menu "menu"
elem
name = "&Quit"
command = ".quit"
category = "&File"
is-checked = false
can-check = false
group = ""
is-disabled = false
saved-params = "is-checked"
window "window"
elem "window"
type = MAIN
pos = 281,0
size = 594x231
anchor1 = none
anchor2 = none
font-family = ""
font-size = 0
font-style = ""
text-color = #000000
background-color = #000000
is-visible = false
is-disabled = false
is-transparent = false
is-default = true
border = none
drop-zone = false
right-click = false
saved-params = "pos;size;is-minimized;is-maximized"
on-size = ""
title = ""
titlebar = true
statusbar = false
can-close = true
can-minimize = true
can-resize = true
is-pane = false
is-minimized = false
is-maximized = false
can-scroll = none
icon = ""
image = ""
image-mode = stretch
keep-aspect = false
transparent-color = none
alpha = 255
macro = "macro"
menu = ""
on-close = ""
elem "servers"
type = GRID
pos = 8,8
size = 576x152
anchor1 = none
anchor2 = none
font-family = ""
font-size = 0
font-style = ""
text-color = #ffffff
background-color = #000000
is-visible = true
is-disabled = false
is-transparent = false
is-default = false
border = none
drop-zone = true
right-click = false
saved-params = ""
on-size = ""
cells = 1x1
current-cell = 1,1
show-lines = none
small-icons = true
show-names = true
enable-http-images = false
link-color = #0000ff
visited-color = #ff00ff
line-color = #c0c0c0
style = ""
is-list = false
elem "output1"
type = OUTPUT
pos = 8,168
size = 576x56
anchor1 = none
anchor2 = none
font-family = ""
font-size = 0
font-style = ""
text-color = #ffffff
background-color = #000000
is-visible = true
is-disabled = false
is-transparent = false
is-default = true
border = none
drop-zone = false
right-click = false
saved-params = "max-lines"
on-size = ""
link-color = #0000ff
visited-color = #ff00ff
style = ""
enable-http-images = false
max-lines = 1000
image = ""
-150
View File
@@ -1,150 +0,0 @@
/*
Written by contributor Doohl for the /tg/station Open Source project, hosted on Google Code.
(2012)
NOTE: The below functions are part of BYOND user Deadron's "TextHandling" library.
[ http://www.byond.com/developer/Deadron/TextHandling ]
*/
proc
///////////////////
// Reading files //
///////////////////
dd_file2list(file_path, separator = "\n")
var/file
if (isfile(file_path))
file = file_path
else
file = file(file_path)
return dd_text2list(file2text(file), separator)
////////////////////
// Replacing text //
////////////////////
dd_replacetext(text, search_string, replacement_string)
// A nice way to do this is to split the text into an array based on the search_string,
// then put it back together into text using replacement_string as the new separator.
var/list/textList = dd_text2list(text, search_string)
return dd_list2text(textList, replacement_string)
dd_replaceText(text, search_string, replacement_string)
var/list/textList = dd_text2List(text, search_string)
return dd_list2text(textList, replacement_string)
/////////////////////
// Prefix checking //
/////////////////////
dd_hasprefix(text, prefix)
var/start = 1
var/end = lentext(prefix) + 1
return findtext(text, prefix, start, end)
dd_hasPrefix(text, prefix)
var/start = 1
var/end = lentext(prefix) + 1
return findtextEx(text, prefix, start, end)
/////////////////////
// Suffix checking //
/////////////////////
dd_hassuffix(text, suffix)
var/start = length(text) - length(suffix)
if (start) return findtext(text, suffix, start)
dd_hasSuffix(text, suffix)
var/start = length(text) - length(suffix)
if (start) return findtextEx(text, suffix, start)
/////////////////////////////
// Turning text into lists //
/////////////////////////////
dd_text2list(text, separator)
var/textlength = lentext(text)
var/separatorlength = lentext(separator)
var/list/textList = new /list()
var/searchPosition = 1
var/findPosition = 1
var/buggyText
while (1) // Loop forever.
findPosition = findtext(text, separator, searchPosition, 0)
buggyText = copytext(text, searchPosition, findPosition) // Everything from searchPosition to findPosition goes into a list element.
textList += "[buggyText]" // Working around weird problem where "text" != "text" after this copytext().
searchPosition = findPosition + separatorlength // Skip over separator.
if (findPosition == 0) // Didn't find anything at end of string so stop here.
return textList
else
if (searchPosition > textlength) // Found separator at very end of string.
textList += "" // So add empty element.
return textList
dd_text2List(text, separator)
var/textlength = lentext(text)
var/separatorlength = lentext(separator)
var/list/textList = new /list()
var/searchPosition = 1
var/findPosition = 1
var/buggyText
while (1) // Loop forever.
findPosition = findtextEx(text, separator, searchPosition, 0)
buggyText = copytext(text, searchPosition, findPosition) // Everything from searchPosition to findPosition goes into a list element.
textList += "[buggyText]" // Working around weird problem where "text" != "text" after this copytext().
searchPosition = findPosition + separatorlength // Skip over separator.
if (findPosition == 0) // Didn't find anything at end of string so stop here.
return textList
else
if (searchPosition > textlength) // Found separator at very end of string.
textList += "" // So add empty element.
return textList
dd_list2text(list/the_list, separator)
var/total = the_list.len
if (total == 0) // Nothing to work with.
return
var/newText = "[the_list[1]]" // Treats any object/number as text also.
var/count
for (count = 2, count <= total, count++)
if (separator) newText += separator
newText += "[the_list[count]]"
return newText
dd_centertext(message, length)
var/new_message = message
var/size = length(message)
if (size == length)
return new_message
if (size > length)
return copytext(new_message, 1, length + 1)
// Need to pad text to center it.
var/delta = length - size
if (delta == 1)
// Add one space after it.
return new_message + " "
// Is this an odd number? If so, add extra space to front.
if (delta % 2)
new_message = " " + new_message
delta--
// Divide delta in 2, add those spaces to both ends.
delta = delta / 2
var/spaces = ""
for (var/count = 1, count <= delta, count++)
spaces += " "
return spaces + new_message + spaces
dd_limittext(message, length)
// Truncates text to limit if necessary.
var/size = length(message)
if (size <= length)
return message
else
return copytext(message, 1, length + 1)
File diff suppressed because it is too large Load Diff
-314
View File
@@ -1,314 +0,0 @@
/* Runtime Condenser by Nodrak
* This will sum up identical runtimes into one, giving a total of how many times it occured. The first occurance
* of the runtime will log the proc, source, usr and src, the rest will just add to the total. Infinite loops will
* also be caught and displayed (if any) above the list of runtimes.
*
* How to use:
* 1) Copy and paste your list of runtimes from Dream Daemon into input.exe
* 2) Run RuntimeCondenser.exe
* 3) Open output.txt for a condensed report of the runtimes
*/
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//Make all of these global. It's bad yes, but it's a small program so it really doesn't affect anything.
//Because hardcoded numbers are bad :(
const unsigned short maxStorage = 99; //100 - 1
//What we use to read input
string currentLine = "Blank";
string nextLine = "Blank";
//Stores lines we want to keep to print out
string storedRuntime[maxStorage+1];
string storedProc[maxStorage+1];
string storedSource[maxStorage+1];
string storedUsr[maxStorage+1];
string storedSrc[maxStorage+1];
//Stat tracking stuff for output
unsigned int totalRuntimes = 0;
unsigned int totalUniqueRuntimes = 0;
unsigned int totalInfiniteLoops = 0;
unsigned int totalUniqueInfiniteLoops = 0;
//Misc
unsigned int numRuntime[maxStorage+1]; //Number of times a specific runtime has occured
bool checkNextLines = false; //Used in case byond has condensed a large number of similar runtimes
int storedIterator = 0; //Used to remember where we stored the runtime
bool readFromFile()
{
//Open file to read
ifstream inputFile("input.txt");
if(inputFile.is_open())
{
while(!inputFile.eof()) //Until end of file
{
//If we've run out of storage
if(storedRuntime[maxStorage] != "Blank") break;
//Update our lines
currentLine = nextLine;
getline(inputFile, nextLine);
//After finding a new runtime, check to see if there are extra values to store
if(checkNextLines)
{
//Skip ahead
currentLine = nextLine;
getline(inputFile, nextLine);
//If we find this, we have new stuff to store
if(nextLine.find("usr:") != std::string::npos)
{
//Store more info
storedSource[storedIterator] = currentLine;
storedUsr[storedIterator] = nextLine;
//Skip ahead again
currentLine = nextLine;
getline(inputFile, nextLine);
//Store the last of the info
storedSrc[storedIterator] = nextLine;
}
checkNextLines = false;
}
//Found an infinite loop!
if(currentLine.find("Infinite loop suspected") != std::string::npos || currentLine.find("Maximum recursion level reached") != std::string::npos)
{
totalInfiniteLoops++;
for(int i=0; i <= maxStorage; i++)
{
//We've already encountered this
if(currentLine == storedRuntime[i])
{
numRuntime[i]++;
break;
}
//We've never encoutnered this
if(storedRuntime[i] == "Blank")
{
storedRuntime[i] = currentLine;
currentLine = nextLine;
getline(inputFile, nextLine); //Skip the "if this is not an infinite loop" line
storedProc[i] = nextLine;
numRuntime[i] = 1;
checkNextLines = true;
storedIterator = i;
totalUniqueInfiniteLoops++;
break;
}
}
}
//Found a runtime!
else if(currentLine.find("runtime error:") != std::string::npos)
{
totalRuntimes++;
for(int i=0; i <= maxStorage; i++)
{
//We've already encountered this
if(currentLine == storedRuntime[i])
{
numRuntime[i]++;
break;
}
//We've never encoutnered this
if(storedRuntime[i] == "Blank")
{
storedRuntime[i] = currentLine;
storedProc[i] = nextLine;
numRuntime[i] = 1;
checkNextLines = true;
storedIterator = i;
totalUniqueRuntimes++;
break;
}
}
}
}
}
else
{
return false;
}
return true;
}
bool writeToFile()
{
//Open and clear the file
ofstream outputFile("Output.txt", ios::trunc);
if(outputFile.is_open())
{
outputFile << "Note: The proc name, source file, src and usr are all from the FIRST of the identical runtimes. Everything else is cropped.\n\n";
if(totalUniqueInfiniteLoops > 0)
{
outputFile << "Total unique infinite loops: " << totalUniqueInfiniteLoops << endl;
}
if(totalInfiniteLoops > 0)
{
outputFile << "Total infinite loops: " << totalInfiniteLoops << endl;
}
outputFile << "Total unique runtimes: " << totalUniqueRuntimes << endl;
outputFile << "Total runtimes: " << totalRuntimes << endl << endl;
//Display a warning if we've hit the maximum space we've allocated for storage
if(totalUniqueRuntimes + totalUniqueInfiniteLoops >= maxStorage)
{
outputFile << "Warning: The maximum number of unique runtimes has been hit. If there were more, they have been cropped out.\n\n";
}
//If we have infinite loops, display them first.
if(totalInfiniteLoops > 0)
{
outputFile << "** Infinite loops **";
for(int i=0; i <= maxStorage; i++)
{
if(storedRuntime[i].find("Infinite loop suspected") != std::string::npos || storedRuntime[i].find("Maximum recursion level reached") != std::string::npos)
{
if(numRuntime[i] != 0) outputFile << endl << endl << "The following infinite loop has occured " << numRuntime[i] << " time(s).\n";
if(storedRuntime[i] != "Blank") outputFile << storedRuntime[i] << endl;
if(storedProc[i] != "Blank") outputFile << storedProc[i] << endl;
if(storedSource[i] != "Blank") outputFile << storedSource[i] << endl;
if(storedUsr[i] != "Blank") outputFile << storedUsr[i] << endl;
if(storedSrc[i] != "Blank") outputFile << storedSrc[i] << endl;
}
}
outputFile << endl << endl; //For spacing
}
//Do runtimes next
outputFile << "** Runtimes **";
for(int i=0; i <= maxStorage; i++)
{
if(storedRuntime[i].find("Infinite loop suspected") != std::string::npos || storedRuntime[i].find("Maximum recursion level reached") != std::string::npos) continue;
if(numRuntime[i] != 0) outputFile << endl << endl << "The following runtime has occured " << numRuntime[i] << " time(s).\n";
if(storedRuntime[i] != "Blank") outputFile << storedRuntime[i] << endl;
if(storedProc[i] != "Blank") outputFile << storedProc[i] << endl;
if(storedSource[i] != "Blank") outputFile << storedSource[i] << endl;
if(storedUsr[i] != "Blank") outputFile << storedUsr[i] << endl;
if(storedSrc[i] != "Blank") outputFile << storedSrc[i] << endl;
}
outputFile.close();
}
else
{
return false;
}
return true;
}
void sortRuntimes()
{
string tempRuntime[maxStorage+1];
string tempProc[maxStorage+1];
string tempSource[maxStorage+1];
string tempUsr[maxStorage+1];
string tempSrc[maxStorage+1];
unsigned int tempNumRuntime[maxStorage+1];
unsigned int highestCount = 0; //Used for descending order
// int keepLooping = 0;
//Move all of our data into temporary arrays. Also clear the stored data (not necessary but.. just incase)
for(int i=0; i <= maxStorage; i++)
{
//Get the largest occurance of a single runtime
if(highestCount < numRuntime[i])
{
highestCount = numRuntime[i];
}
tempRuntime[i] = storedRuntime[i]; storedRuntime[i] = "Blank";
tempProc[i] = storedProc[i]; storedProc[i] = "Blank";
tempSource[i] = storedSource[i]; storedSource[i] = "Blank";
tempUsr[i] = storedUsr[i]; storedUsr[i] = "Blank";
tempSrc[i] = storedSrc[i]; storedSrc[i] = "Blank";
tempNumRuntime[i] = numRuntime[i]; numRuntime[i] = 0;
}
while(highestCount > 0)
{
for(int i=0; i <= maxStorage; i++) //For every runtime
{
if(tempNumRuntime[i] == highestCount) //If the number of occurances of that runtime is equal to our current highest
{
for(int j=0; j <= maxStorage; j++) //Find the next available slot and store the info
{
if(storedRuntime[j] == "Blank") //Found an empty spot
{
storedRuntime[j] = tempRuntime[i];
storedProc[j] = tempProc[i];
storedSource[j] = tempSource[i];
storedUsr[j] = tempUsr[i];
storedSrc[j] = tempSrc[i];
numRuntime[j] = tempNumRuntime[i];
break;
}
}
}
}
highestCount--; //Lower our 'highest' by one and continue
}
}
int main() {
char exit; //Used to stop the program from immediatly exiting
//Start everything fresh. "Blank" should never occur in the runtime logs on its own.
for(int i=0; i <= maxStorage; i++)
{
storedRuntime[i] = "Blank";
storedProc[i] = "Blank";
storedSource[i] = "Blank";
storedUsr[i] = "Blank";
storedSrc[i] = "Blank";
numRuntime[i] = 0;
}
if(readFromFile())
{
cout << "Input read successfully!\n";
}
else
{
cout << "Input failed to open, shutting down.\n";
cout << "\nEnter any letter to quit.\n";
cin >> exit;
return 1;
}
sortRuntimes();
if(writeToFile())
{
cout << "Output was successful!\n";
cout << "\nEnter any letter to quit.\n";
cin >> exit;
return 0;
}
else
{
cout << "The output file could not be opened, shutting down.\n";
cout << "\nEnter any letter to quit.\n";
cin >> exit;
return 0;
}
return 0;
}
-190
View File
@@ -1,190 +0,0 @@
Note: The proc name, source file, src and usr are all from the FIRST of the identical runtimes. Everything else is cropped.
Total unique runtimes: 25
Total runtimes: 767
** Runtimes **
The following runtime has occured 269 time(s).
runtime error: Cannot read null.viruses
proc name: cure (/datum/disease/proc/cure)
source file: disease.dm,156
usr: null
src: Space Retrovirus (/datum/disease/dnaspread)
The following runtime has occured 199 time(s).
runtime error: Cannot read null.has_gravity
proc name: throw at (/atom/movable/proc/throw_at)
source file: throwing.dm,194
usr: Reese Marcotte (/mob/living/carbon/human)
src: Reese Marcotte (/mob/living/carbon/human)
The following runtime has occured 165 time(s).
runtime error: Cannot read null.slot_flags
proc name: db click (/mob/living/carbon/human/db_click)
source file: inventory.dm,1083
usr: Puke Chunks (/mob/living/carbon/human)
src: Puke Chunks (/mob/living/carbon/human)
The following runtime has occured 25 time(s).
runtime error: Cannot read null.flags
proc name: relaymove (/obj/effect/dummy/spell_jaunt/relaymove)
The following runtime has occured 24 time(s).
runtime error: Cannot read null.len
proc name: mergeRecordLists (/proc/mergeRecordLists)
source file: helpers.dm,260
usr: Wintermute (/mob/living/silicon/ai)
src: null
The following runtime has occured 20 time(s).
runtime error: Cannot read null.total_volume
proc name: attackby (/obj/machinery/reagentgrinder/attackby)
source file: Chemistry-Machinery.dm,751
usr: Reese Marcotte (/mob/living/carbon/human)
src: All-In-One Grinder (/obj/machinery/reagentgrinder)
The following runtime has occured 16 time(s).
runtime error: Cannot read null.broadcasting
proc name: radio menu (/mob/living/silicon/robot/proc/radio_menu)
source file: robot.dm,857
usr: Engineering Cyborg -432 (/mob/living/silicon/robot)
src: Engineering Cyborg -432 (/mob/living/silicon/robot)
The following runtime has occured 7 time(s).
runtime error: unexpected stat
proc name: Stat (/mob/living/silicon/robot/Stat)
source file: robot.dm,227
usr: Michigan Slim (/mob/living/carbon/human)
src: Engineering Cyborg -133 (/mob/living/silicon/robot)
The following runtime has occured 7 time(s).
runtime error: Cannot read null.current
proc name: check completion (/datum/objective/download/check_completion)
source file: objective.dm,411
usr: null
src: /datum/objective/download (/datum/objective/download)
The following runtime has occured 6 time(s).
runtime error: Cannot create objects of type null.
proc name: Topic (/obj/machinery/computer/rdconsole/Topic)
source file: rdconsole.dm,381
usr: Matthew Hoff (/mob/living/carbon/human)
src: Core R&D Console (/obj/machinery/computer/rdconsole/core)
The following runtime has occured 6 time(s).
runtime error: Cannot read null.fields
proc name: mergeRecordLists (/proc/mergeRecordLists)
source file: helpers.dm,263
usr: Wintermute (/mob/living/silicon/ai)
src: null
The following runtime has occured 3 time(s).
runtime error: undefined variable /client/var/loc
proc name: get turf (/proc/get_turf)
source file: helper_procs.dm,38
usr: the ghost (/mob/dead/observer)
src: null
The following runtime has occured 3 time(s).
runtime error: Cannot read null.nodes
proc name: merge powernets (/datum/powernet/proc/merge_powernets)
source file: power.dm,401
usr: Darin Keppel (/mob/living/carbon/human)
src: /datum/powernet (/datum/powernet)
The following runtime has occured 3 time(s).
runtime error: Cannot read null.reagents
proc name: fire syringe (/obj/item/weapon/gun/syringe/proc/fire_syringe)
The following runtime has occured 2 time(s).
runtime error: undefined proc or verb /obj/machinery/space_heater/attack().
The following runtime has occured 2 time(s).
runtime error: list index out of bounds
proc name: mergeConnectedNetworksOnTurf (/obj/structure/cable/proc/mergeConnectedNetworksOnTurf)
source file: cable.dm,520
usr: Josue Sandford (/mob/living/carbon/human)
src: the power cable (/obj/structure/cable)
The following runtime has occured 2 time(s).
runtime error: Cannot read null.loc
proc name: Life (/mob/living/simple_animal/corgi/Ian/Life)
source file: corgi.dm,304
usr: null
src: Captain Ian (/mob/living/simple_animal/corgi/Ian)
The following runtime has occured 1 time(s).
runtime error: undefined proc or verb /obj/machinery/portable_atmospherics/canister/toxins/attack().
The following runtime has occured 1 time(s).
runtime error: undefined variable /datum/preferences/var/fields
proc name: Topic (/obj/machinery/computer/cloning/Topic)
source file: cloning.dm,370
usr: Logan Graves (/mob/living/carbon/human)
src: Cloning console (/obj/machinery/computer/cloning)
The following runtime has occured 1 time(s).
runtime error: undefined variable /turf/simulated/floor/plating/var/mineral
proc name: attackby (/turf/simulated/wall/attackby)
source file: turf.dm,600
usr: Monte Smail (/mob/living/carbon/human)
src: the plating (176,172,5) (/turf/simulated/floor/plating)
The following runtime has occured 1 time(s).
runtime error: Cannot read null.blood_DNA
proc name: update inv w uniform (/mob/living/carbon/human/update_inv_w_uniform)
source file: update_icons.dm,372
usr: null
src: Chip Harshman (/mob/living/carbon/human)
The following runtime has occured 1 time(s).
runtime error: Cannot execute null.dropped().
proc name: drop l hand (/mob/proc/drop_l_hand)
source file: inventory.dm,104
usr: Jeb Stone (/mob/living/carbon/human)
src: Jeb Stone (/mob/living/carbon/human)
The following runtime has occured 1 time(s).
runtime error: Cannot read null.w_class
proc name: attackby (/obj/item/weapon/storage/attackby)
source file: storage.dm,187
usr: Samuel York (/mob/living/carbon/human)
src: the backpack (/obj/item/weapon/storage/backpack)
The following runtime has occured 1 time(s).
runtime error: Cannot read null.amount
proc name: attackby (/obj/machinery/constructable_frame/machine_frame/attackby)
source file: constructable_frame.dm,27
usr: Quinton Bould (/mob/living/carbon/human)
src: the machine frame (/obj/machinery/constructable_frame/machine_frame)
The following runtime has occured 1 time(s).
runtime error: Cannot modify null.status.
proc name: death (/mob/living/silicon/robot/death)
Binary file not shown.
@@ -1,20 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnstandardnessTestForDM", "UnstandardnessTestForDM\UnstandardnessTestForDM.csproj", "{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}.Debug|x86.ActiveCfg = Debug|x86
{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}.Debug|x86.Build.0 = Debug|x86
{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}.Release|x86.ActiveCfg = Release|x86
{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -1,160 +0,0 @@
namespace UnstandardnessTestForDM
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.panel1 = new System.Windows.Forms.Panel();
this.listBox2 = new System.Windows.Forms.ListBox();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(222, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Locate all #defines";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(12, 82);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(696, 160);
this.listBox1.TabIndex = 1;
this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
//
// panel1
//
this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panel1.Controls.Add(this.listBox2);
this.panel1.Controls.Add(this.label4);
this.panel1.Controls.Add(this.label3);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.label1);
this.panel1.Location = new System.Drawing.Point(12, 297);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(696, 244);
this.panel1.TabIndex = 2;
//
// listBox2
//
this.listBox2.FormattingEnabled = true;
this.listBox2.Location = new System.Drawing.Point(8, 71);
this.listBox2.Name = "listBox2";
this.listBox2.Size = new System.Drawing.Size(683, 160);
this.listBox2.TabIndex = 4;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(5, 55);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(69, 13);
this.label4.TabIndex = 3;
this.label4.Text = "Referenced: ";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(5, 42);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(40, 13);
this.label3.TabIndex = 2;
this.label3.Text = "Value: ";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(5, 29);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(61, 13);
this.label2.TabIndex = 1;
this.label2.Text = "Defined in: ";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.label1.Location = new System.Drawing.Point(3, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(79, 29);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(9, 38);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(81, 13);
this.label5.TabIndex = 3;
this.label5.Text = "Files searched: ";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(720, 553);
this.Controls.Add(this.label5);
this.Controls.Add(this.panel1);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Unstandardness Test For DM";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
public System.Windows.Forms.ListBox listBox2;
public System.Windows.Forms.Label label5;
public System.Windows.Forms.ListBox listBox1;
}
}
@@ -1,484 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
namespace UnstandardnessTestForDM
{
public partial class Form1 : Form
{
DMSource source;
public Form1()
{
InitializeComponent();
source = new DMSource();
source.mainform = this;
}
private void button1_Click(object sender, EventArgs e)
{
source.find_all_defines();
generate_define_report();
}
public void generate_define_report()
{
TextWriter tw = new StreamWriter("DEFINES REPORT.txt");
tw.WriteLine("Unstandardness Test For DM report for DEFINES");
tw.WriteLine("Generated on " + DateTime.Now);
tw.WriteLine("Total number of defines " + source.defines.Count());
tw.WriteLine("Total number of Files " + source.filessearched);
tw.WriteLine("Total number of references " + source.totalreferences);
tw.WriteLine("Total number of errorous defines " + source.errordefines);
tw.WriteLine("------------------------------------------------");
foreach (Define d in source.defines)
{
tw.WriteLine(d.name);
tw.WriteLine("\tValue: " + d.value);
tw.WriteLine("\tComment: " + d.comment);
tw.WriteLine("\tDefined in: " + d.location + " : " + d.line);
tw.WriteLine("\tNumber of references: " + d.references.Count());
foreach (String s in d.references)
{
tw.WriteLine("\t\t" + s);
}
}
tw.WriteLine("------------------------------------------------");
tw.WriteLine("SUCCESS");
tw.Close();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
Define d = (Define)listBox1.Items[listBox1.SelectedIndex];
label1.Text = d.name;
label2.Text = "Defined in: " + d.location + " : " + d.line;
label3.Text = "Value: " + d.value;
label4.Text = "References: " + d.references.Count();
listBox2.Items.Clear();
foreach (String s in d.references)
{
listBox2.Items.Add(s);
}
}
catch (Exception ex) { Console.WriteLine("ERROR HERE: " + ex.Message); }
}
}
public class DMSource
{
public List<Define> defines;
public const int FLAG_DEFINE = 1;
public Form1 mainform;
public int filessearched = 0;
public int totalreferences = 0;
public int errordefines = 0;
public List<String> filenames;
public DMSource()
{
defines = new List<Define>();
filenames = new List<String>();
}
public void find_all_defines()
{
find_all_files();
foreach(String filename in filenames){
searchFileForDefines(filename);
}
}
public void find_all_files()
{
filenames = new List<String>();
String dmefilename = "";
foreach (string f in Directory.GetFiles("."))
{
if (f.ToLower().EndsWith(".dme"))
{
dmefilename = f;
break;
}
}
if (dmefilename.Equals(""))
{
MessageBox.Show("dme file not found");
return;
}
using (var reader = File.OpenText(dmefilename))
{
String s;
while (true)
{
s = reader.ReadLine();
if (!(s is String))
break;
if (s.StartsWith("#include"))
{
int start = s.IndexOf("\"")+1;
s = s.Substring(start, s.Length - 11);
if (s.EndsWith(".dm"))
{
filenames.Add(s);
}
}
s = s.Trim(' ');
if (s == "") { continue; }
}
reader.Close();
}
}
public void DirSearch(string sDir, int flag)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d))
{
if (f.ToLower().EndsWith(".dm"))
{
if ((flag & FLAG_DEFINE) > 0)
{
searchFileForDefines(f);
}
}
}
DirSearch(d, flag);
}
}
catch (System.Exception excpt)
{
Console.WriteLine("ERROR IN DIRSEARCH");
Console.WriteLine(excpt.Message);
Console.WriteLine(excpt.Data);
Console.WriteLine(excpt.ToString());
Console.WriteLine(excpt.StackTrace);
Console.WriteLine("END OF ERROR IN DIRSEARCH");
}
}
//DEFINES
public void searchFileForDefines(String fileName)
{
filessearched++;
FileInfo f = new FileInfo(fileName);
List<String> lines = new List<String>();
List<String> lines_without_comments = new List<String>();
mainform.label5.Text = "Files searched: " + filessearched + "; Defines found: " + defines.Count() + "; References found: " + totalreferences + "; Errorous defines: " + errordefines;
mainform.label5.Refresh();
//This code segment reads the file and stores it into the lines variable.
using (var reader = File.OpenText(fileName))
{
try
{
String s;
while (true)
{
s = reader.ReadLine();
lines.Add(s);
s = s.Trim(' ');
if (s == "") { continue; }
}
}
catch { }
reader.Close();
}
mainform.listBox1.Items.Add("ATTEMPTING: " + fileName);
lines_without_comments = remove_comments(lines);
/*TextWriter tw = new StreamWriter(fileName);
foreach (String s in lines_without_comments)
{
tw.WriteLine(s);
}
tw.Close();
mainform.listBox1.Items.Add("REWRITE: "+fileName);*/
try
{
for (int i = 0; i < lines_without_comments.Count; i++)
{
String line = lines_without_comments[i];
if (!(line is string))
continue;
//Console.WriteLine("LINE: " + line);
foreach (Define define in defines)
{
if (line.IndexOf(define.name) >= 0)
{
define.references.Add(fileName + " : " + i);
totalreferences++;
}
}
if( line.ToLower().IndexOf("#define") >= 0 )
{
line = line.Trim();
line = line.Replace('\t', ' ');
//Console.WriteLine("LINE = "+line);
String[] slist = line.Split(' ');
if(slist.Length >= 3){
//slist[0] has the value of "#define"
String name = slist[1];
String value = slist[2];
for (int j = 3; j < slist.Length; j++)
{
value += " " + slist[j];
//Console.WriteLine("LISTITEM["+j+"] = "+slist[j]);
}
value = value.Trim();
String comment = "";
if (value.IndexOf("//") >= 0)
{
comment = value.Substring(value.IndexOf("//"));
value = value.Substring(0, value.IndexOf("//"));
}
comment = comment.Trim();
value = value.Trim();
Define d = new Define(fileName,i,name,value,comment);
defines.Add(d);
mainform.listBox1.Items.Add(d);
mainform.listBox1.Refresh();
}else{
Define d = new Define(fileName, i, "ERROR ERROR", "Something went wrong here", line);
errordefines++;
defines.Add(d);
mainform.listBox1.Items.Add(d);
mainform.listBox1.Refresh();
}
}
}
}
catch (Exception e) {
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
MessageBox.Show("Exception: " + e.Message + " | " + e.ToString());
}
}
bool iscomment = false;
int ismultilinecomment = 0;
bool isstring = false;
bool ismultilinestring = false;
int escapesequence = 0;
int stringvar = 0;
public List<String> remove_comments(List<String> lines)
{
List<String> r = new List<String>();
iscomment = false;
ismultilinecomment = 0;
isstring = false;
ismultilinestring = false;
bool skiponechar = false; //Used so the / in */ doesn't get written;
for (int i = 0; i < lines.Count(); i++)
{
String line = lines[i];
if (!(line is String))
continue;
iscomment = false;
isstring = false;
char ca = ' ';
escapesequence = 0;
String newline = "";
int k = line.Length;
for (int j = 0; j < k; j++)
{
char c = line.ToCharArray()[j];
if (escapesequence == 0)
if (normalstatus())
{
if (ca == '/' && c == '/')
{
c = ' ';
iscomment = true;
newline = newline.Remove(newline.Length - 1);
k = line.Length;
}
if (ca == '/' && c == '*')
{
c = ' ';
ismultilinecomment = 1;
newline = newline.Remove(newline.Length - 1);
k = line.Length;
}
if (c == '"')
{
isstring = true;
}
if (ca == '{' && c == '"')
{
ismultilinestring = true;
}
}
else if (isstring)
{
if (c == '\\')
{
escapesequence = 2;
}
else if (stringvar > 0)
{
if (c == ']')
{
stringvar--;
}
else if (c == '[')
{
stringvar++;
}
}
else if (c == '"')
{
isstring = false;
}
else if (c == '[')
{
stringvar++;
}
}
else if (ismultilinestring)
{
if (ca == '"' && c == '}')
{
ismultilinestring = false;
}
}
else if (ismultilinecomment > 0)
{
if (ca == '/' && c == '*')
{
c = ' '; //These things are here to prevent /*/ from bieng interpreted as the start and end of a comment.
skiponechar = true;
ismultilinecomment++;
}
if (ca == '*' && c == '/')
{
c = ' '; //These things are here to prevent /*/ from bieng interpreted as the start and end of a comment.
skiponechar = true;
ismultilinecomment--;
}
}
if (!iscomment && (ismultilinecomment==0) && !skiponechar)
{
newline += c;
}
if (skiponechar)
{
skiponechar = false;
}
if (escapesequence > 0)
{
escapesequence--;
}
else
{
ca = c;
}
}
r.Add(newline.TrimEnd());
}
return r;
}
private bool normalstatus()
{
return !isstring && !ismultilinestring && (ismultilinecomment==0) && !iscomment && (escapesequence == 0);
}
}
public class Define
{
public String location;
public int line;
public String name;
public String value;
public String comment;
public List<String> references;
public Define(String location, int line, String name, String value, String comment)
{
this.location = location;
this.line = line;
this.name = name;
this.value = value;
this.comment = comment;
this.references = new List<String>();
}
public override String ToString()
{
return "DEFINE: \""+name+"\" is defined as \""+value+"\" AT "+location+" : "+line;
}
}
}
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace UnstandardnessTestForDM
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnstandardnessTestForDM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("UnstandardnessTestForDM")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c0e09000-1840-4416-8bb2-d86a8227adf1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,71 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.239
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UnstandardnessTestForDM.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UnstandardnessTestForDM.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.239
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UnstandardnessTestForDM.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -1,87 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A0EEBFC9-41D4-474D-853D-126AFDFB82DE}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnstandardnessTestForDM</RootNamespace>
<AssemblyName>UnstandardnessTestForDM</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
@@ -1,18 +0,0 @@
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\bin\Debug\UnstandardnessTestForDM.exe
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\bin\Debug\UnstandardnessTestForDM.pdb
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\ResolveAssemblyReference.cache
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.Form1.resources
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.Properties.Resources.resources
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\GenerateResource.read.1.tlog
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\GenerateResource.write.1.tlog
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.exe
c:\users\baloh\documents\visual studio 2010\Projects\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.pdb
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\bin\Debug\UnstandardnessTestForDM.exe
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\bin\Debug\UnstandardnessTestForDM.pdb
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\ResolveAssemblyReference.cache
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.Form1.resources
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.Properties.Resources.resources
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\GenerateResource.read.1.tlog
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\GenerateResource.write.1.tlog
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.exe
C:\Users\Baloh\Desktop\tgs13\tools\UnstandardnessTestForDM\UnstandardnessTestForDM\obj\x86\Debug\UnstandardnessTestForDM.pdb
-123
View File
@@ -1,123 +0,0 @@
import os, sys
"""
Usage:
$ python countstrings.py path/to/your.dme .dm
CountStrings.py - Counts strings in DreamMaker code
Copyright 2013 Rob "N3X15" Nelson <nexis@7chan.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
def CountStringsIn(f):
numStrings = 0
inString = False
escaped = False
while(True):
c = f.read(1)
if not c:
return numStrings
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
escaped = False
continue
if c == '"':
inString = not inString
if not inString:
numStrings += 1
continue
return numStrings
def ProcessFiles(top='.', ext='.dm'):
numStringsTotal = 0
numStrings = 0
numFilesTotal = 0
maxStringsInFile = [0, '']
for root, _, files in os.walk(top):
for filename in files:
filepath = os.path.join(root, filename)
if filepath.endswith(ext):
with open(filepath, 'r') as f:
numStrings = CountStringsIn(f)
numStringsTotal += numStrings
if numStrings > maxStringsInFile[0]:
maxStringsInFile = [numStrings, filepath]
numFilesTotal += 1
print(','.join([filepath, str(numStrings)]))
print('>>> Total Strings: {0}'.format(numStringsTotal))
print('>>> Total Files: {0}'.format(numFilesTotal))
print('>>> Max Strings: {0} in {1}'.format(maxStringsInFile[0], maxStringsInFile[1]))
def ProcessFilesFromDME(dmefile='baystation12.dme', ext='.dm'):
numStringsTotal = 0
numStrings = 0
numFilesTotal = 0
maxStringsInFile = [0, '']
rootdir = os.path.dirname(dmefile)
with open(os.path.join(rootdir,'stringcounts.csv'),'w') as csv:
with open(dmefile,'r') as dmeh:
for line in dmeh:
if line.startswith('#include'):
inString = False
#escaped=False
filename=''
for c in line:
"""
if c == '\\' and not escaped:
escaped = True
continue
if escaped:
if
escaped = False
continue
"""
if c == '"':
inString = not inString
if not inString:
filepath = os.path.join(rootdir, filename)
if filepath.endswith(ext):
with open(filepath, 'r') as f:
numStrings = CountStringsIn(f)
numStringsTotal += numStrings
if numStrings > maxStringsInFile[0]:
maxStringsInFile = [numStrings, filepath]
numFilesTotal += 1
csv.write(','.join([filepath, str(numStrings)])+"\n")
filename=''
continue
else:
if inString:
filename += c
print('>>> Total Strings: {0}'.format(numStringsTotal))
print('>>> Total Files: {0}'.format(numFilesTotal))
print('>>> Max Strings: {0} in {1}'.format(maxStringsInFile[0], maxStringsInFile[1]))
if os.path.isdir(sys.argv[1]):
for root, _, files in os.walk(sys.argv[1]):
for filename in files:
filepath = os.path.join(root, filename)
if filepath.endswith('.dme'):
ProcessFilesFromDME(filepath,sys.argv[2])
sys.exit(0)
if os.path.isfile(sys.argv[1]):
ProcessFilesFromDME(sys.argv[1],sys.argv[2])
#ProcessFiles(sys.argv[1], sys.argv[2])
-93
View File
@@ -1,93 +0,0 @@
#!/usr/bin/env python
import re, os, sys, fnmatch
# Regex pattern to extract the directory path in a #define FILE_DIR
filedir_pattern = re.compile(r'^#define\s*FILE_DIR\s*"(.*?)"')
# Regex pattern to extract any single quoted piece of text. This can also
# match single quoted strings inside of double quotes, which is part of a
# regular text string and should not be replaced. The replacement function
# however will any match that doesn't appear to be a filename so these
# extra matches should not be a problem.
rename_pattern = re.compile(r"'(.+?)'")
# Only filenames matching this pattern will have their resources renamed
source_pattern = re.compile(r"^.*?\.(dm|dmm)$")
# Open the .dme file and return a list of all FILE_DIR paths in it
def read_filedirs(filename):
result = []
dme_file = file(filename, "rt")
# Read each line from the file and check for regex pattern match
for row in dme_file:
match = filedir_pattern.match(row)
if match:
result.append(match.group(1))
dme_file.close()
return result
# Search through a list of directories, and build a dictionary which
# maps every file to its full pathname (relative to the .dme file)
# If the same filename appears in more than one directory, the earlier
# directory in the list takes preference.
def index_files(file_dirs):
result = {}
# Reverse the directory list so the earlier directories take precedence
# by replacing the previously indexed file of the same name
for directory in reversed(file_dirs):
for name in os.listdir(directory):
# Replace backslash path separators on Windows with forward slash
# Force "name" to lowercase when used as a key since BYOND resource
# names are case insensitive, even on Linux.
if name.find(".") == -1:
continue
result[name.lower()] = directory.replace('\\', '/') + '/' + name
return result
# Recursively search for every .dm/.dmm file in the .dme file directory. For
# each file, search it for any resource names in single quotes, and replace
# them with the full path previously found by index_files()
def rewrite_sources(resources):
# Create a closure for the regex replacement function to capture the
# resources dictionary which can't be passed directly to this function
def replace_func(name):
key = name.group(1).lower()
if key in resources:
replacement = resources[key]
else:
replacement = name.group(1)
return "'" + replacement + "'"
# Search recursively for all .dm and .dmm files
for (dirpath, dirs, files) in os.walk("."):
for name in files:
if source_pattern.match(name):
path = dirpath + '/' + name
source_file = file(path, "rt")
output_file = file(path + ".tmp", "wt")
# Read file one line at a time and perform replacement of all
# single quoted resource names with the fullpath to that resource
# file. Write the updated text back out to a temporary file.
for row in source_file:
row = rename_pattern.sub(replace_func, row)
output_file.write(row)
output_file.close()
source_file.close()
# Delete original source file and replace with the temporary
# output. On Windows, an atomic rename() operation is not
# possible like it is under POSIX.
os.remove(path)
os.rename(path + ".tmp", path)
dirs = read_filedirs("tgstation.dme");
resources = index_files(dirs)
rewrite_sources(resources)
-6
View File
@@ -1,6 +0,0 @@
the compiled exe file for the Unstandardness text for DM program is in:
UnstandardnessTestForDM\bin\Debug\UnstandardnessTestForDM.exe
of
UnstandardnessTestForDM\bin\Release\UnstandardnessTestForDM.exe
You have to move it to the root folder (where the dme file is) and run it from there for it to work.