forked from bartvdbraak/blender
678 lines
30 KiB
Python
678 lines
30 KiB
Python
|
#!BPY
|
||
|
"""
|
||
|
Name: 'Convert BGE 2.49'
|
||
|
Blender: 246
|
||
|
Group: 'TextPlugin'
|
||
|
Shortcut: ''
|
||
|
Tooltip: 'Attemps to update deprecated usage of game engine API.'
|
||
|
"""
|
||
|
|
||
|
#
|
||
|
# Copyright 2009 Alex Fraser <alex@phatcore.com>
|
||
|
#
|
||
|
# This program is free software: you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU General Public License as published by
|
||
|
# the Free Software Foundation, either version 3 of the License, or
|
||
|
# (at your option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
# GNU General Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
#
|
||
|
|
||
|
import string
|
||
|
import re
|
||
|
|
||
|
COMMENTCHAR = '#'
|
||
|
|
||
|
class ParseError(Exception): pass
|
||
|
class ConversionError(Exception): pass
|
||
|
|
||
|
def findBalancedParens(lines, row, col, openChar = '(', closeChar = ')'):
|
||
|
"""Finds a balanced pair of parentheses, searching from lines[row][col].
|
||
|
The opening parenthesis must be on the starting line.
|
||
|
|
||
|
Returns a 4-tuple containing the row and column of the opening paren, and
|
||
|
the row and column of the matching paren.
|
||
|
|
||
|
Throws a ParseError if the first character is not openChar, or if a matching
|
||
|
paren cannot be found."""
|
||
|
|
||
|
#
|
||
|
# Find the opening coordinates.
|
||
|
#
|
||
|
oRow = row
|
||
|
oCol = col
|
||
|
line = lines[oRow]
|
||
|
while oCol < len(line):
|
||
|
if line[oCol] == openChar:
|
||
|
break
|
||
|
elif line[oCol] == COMMENTCHAR:
|
||
|
break
|
||
|
oCol = oCol + 1
|
||
|
|
||
|
if oCol >= len(line) or line[oCol] != openChar or not re.match(r'^\s*$', line[col:oCol]):
|
||
|
raise ParseError, "Can't find opening parenthesis. '%s'" % openChar
|
||
|
|
||
|
#
|
||
|
# Find the closing coordinates.
|
||
|
#
|
||
|
eRow = oRow
|
||
|
eCol = oCol + 1
|
||
|
level = 1
|
||
|
while eRow < len(lines) and level > 0:
|
||
|
line = lines[eRow]
|
||
|
while eCol < len(line) and level > 0:
|
||
|
c = line[eCol]
|
||
|
if c == openChar:
|
||
|
# Found a nested paren.
|
||
|
level = level + 1
|
||
|
elif c == closeChar:
|
||
|
# Exiting one level of nesting.
|
||
|
level = level - 1
|
||
|
if level == 0:
|
||
|
# Back to top level!
|
||
|
return (oRow, oCol), (eRow, eCol)
|
||
|
elif c == COMMENTCHAR:
|
||
|
# Comment. Skip the rest of the line.
|
||
|
break
|
||
|
eCol = eCol + 1
|
||
|
eRow = eRow + 1
|
||
|
eCol = 0
|
||
|
raise ParseError, "Couldn't find closing parenthesis."
|
||
|
|
||
|
def findLastAssignment(lines, row, attrName):
|
||
|
"""Finds the most recent assignment of `attrName' before `row'. Returns
|
||
|
everything after the '=' sign or None, if there was no match."""
|
||
|
contRegex = re.compile(r'[^#]*?' + # Don't search in comments.
|
||
|
attrName +
|
||
|
r'\s*=\s*(.*)') # Assignment
|
||
|
|
||
|
cRow = row - 1
|
||
|
while cRow >= 0:
|
||
|
match = contRegex.search(lines[cRow])
|
||
|
if match:
|
||
|
return match.group(1)
|
||
|
cRow = cRow - 1
|
||
|
return None
|
||
|
|
||
|
def replaceSubstr(s, start, end, newSubStr):
|
||
|
"""Replace the contents of `s' between `start' and `end' with
|
||
|
`newSubStr'."""
|
||
|
return s[:start] + newSubStr + s[end:]
|
||
|
|
||
|
def replaceNextParens(lines, row, colStart, newOpenChar, newCloseChar,
|
||
|
oldOpenChar = '(', oldCloseChar = ')'):
|
||
|
"""Replace the next set of parentheses with different characters. The
|
||
|
opening parenthesis must be located on line `row', and on or after
|
||
|
`colStart'. The closing parenthesis may be on the same line or any following
|
||
|
line. The strings are edited in-place.
|
||
|
|
||
|
Throws a ParseError if the set of parentheses can't be found. In this case,
|
||
|
the strings in `lines' will be untouched."""
|
||
|
try:
|
||
|
pOpen, pClose = findBalancedParens(lines, row, colStart, oldOpenChar,
|
||
|
oldCloseChar)
|
||
|
except ParseError:
|
||
|
raise
|
||
|
|
||
|
# Replacement may change string length. Replace closing paren first.
|
||
|
r, c = pClose
|
||
|
lines[r] = replaceSubstr(lines[r], c, c + 1, newCloseChar)
|
||
|
# Replace opening paren.
|
||
|
r, c = pOpen
|
||
|
lines[r] = replaceSubstr(lines[r], c, c + 1, newOpenChar)
|
||
|
|
||
|
def replaceSimpleGetter(lines, row, colStart, colEnd, newName):
|
||
|
"""Replace a call to a simple getter function with a reference to a
|
||
|
property, e.g. foo.getBar() -> foo.bar
|
||
|
|
||
|
The function identifier being replaced must be on line `row' and
|
||
|
between `colStart' and `colEnd'. The opening parenthesis must follow
|
||
|
immediately (whitespace is allowed). The closing parenthesis may be on the
|
||
|
same or following lines.
|
||
|
|
||
|
Throws a ConversionError if the parentheses can't be found. In this case
|
||
|
the content of `lines' will be untouched."""
|
||
|
try:
|
||
|
replaceNextParens(lines, row, colEnd, newOpenChar = '', newCloseChar = '')
|
||
|
except ParseError:
|
||
|
raise ConversionError, ("Deprecated function reference.")
|
||
|
|
||
|
lines[row] = replaceSubstr(lines[row], colStart, colEnd, newName)
|
||
|
|
||
|
def replaceSimpleSetter(lines, row, colStart, colEnd, newName):
|
||
|
"""Replace a call to a simple setter function with a reference to a
|
||
|
property, e.g. foo.setBar(baz) -> foo.bar = baz
|
||
|
|
||
|
The function identifier being replaced must be on line `row' and
|
||
|
between `colStart' and `colEnd'. The opening parenthesis must follow
|
||
|
immediately (whitespace is allowed). The closing parenthesis may be on the
|
||
|
same or following lines.
|
||
|
|
||
|
Throws a ConversionError if the parentheses can't be found. In this case
|
||
|
the content of `lines' will be untouched."""
|
||
|
try:
|
||
|
replaceNextParens(lines, row, colEnd, newOpenChar = '', newCloseChar = '')
|
||
|
except ParseError:
|
||
|
raise ConversionError, ("Deprecated function reference.")
|
||
|
|
||
|
lines[row] = replaceSubstr(lines[row], colStart, colEnd, newName + ' = ')
|
||
|
|
||
|
def replaceKeyedGetter(lines, row, colStart, colEnd, newName):
|
||
|
"""Replace a call to a keyed getter function with a reference to a
|
||
|
property, e.g. foo.getBar(baz) -> foo.bar[baz]
|
||
|
|
||
|
The function identifier being replaced must be on line `row' and
|
||
|
between `colStart' and `colEnd'. The opening parenthesis must follow
|
||
|
immediately (whitespace is allowed). The closing parenthesis may be on the
|
||
|
same or following lines.
|
||
|
|
||
|
Throws a ConversionError if the parentheses can't be found. In this case
|
||
|
the content of `lines' will be untouched."""
|
||
|
try:
|
||
|
replaceNextParens(lines, row, colEnd, newOpenChar = '[', newCloseChar = ']')
|
||
|
except ParseError:
|
||
|
raise ConversionError, ("Deprecated function reference.")
|
||
|
|
||
|
lines[row] = replaceSubstr(lines[row], colStart, colEnd, newName)
|
||
|
|
||
|
def replaceGetXYPosition(lines, row, colStart, colEnd, axis):
|
||
|
'''SCA_MouseSensor.getXPosition; SCA_MouseSensor.getYPosition.
|
||
|
This is like a keyed getter, but the key is embedded in the attribute
|
||
|
name.
|
||
|
|
||
|
Throws a ConversionError if the parentheses can't be found. In this case
|
||
|
the content of `lines' will be untouched.'''
|
||
|
try:
|
||
|
(openRow, openCol), (closeRow, closeCol) = findBalancedParens(lines,
|
||
|
row, colEnd)
|
||
|
except ParseError:
|
||
|
raise ConversionError, "Deprecated function reference."
|
||
|
if closeRow != row:
|
||
|
raise ConversionError, "Can't modify multiple lines."
|
||
|
|
||
|
lines[row] = replaceSubstr(lines[row], openCol, closeCol + 1,
|
||
|
"[%s]" % axis)
|
||
|
|
||
|
lines[row] = replaceSubstr(lines[row], colStart, colEnd, 'position')
|
||
|
|
||
|
def replaceRename(lines, row, colStart, colEnd, newName):
|
||
|
"""Replace an identifier with another, e.g. foo.getBar() -> foo.getBaz()
|
||
|
|
||
|
The identifier being replaced must be on line `row' and between `colStart'
|
||
|
and `colEnd'."""
|
||
|
lines[row] = replaceSubstr(lines[row], colStart, colEnd, newName)
|
||
|
|
||
|
def replaceAddActiveActuator(lines, row, colStart, colEnd, closure):
|
||
|
'''Extra work needs to be done here to find out the name of the controller,
|
||
|
and whether the actuator should be activated or deactivated.
|
||
|
|
||
|
Throws a ConversionError if the actuator, controller or condition can't be
|
||
|
found. In this case the content of `lines' will be untouched.'''
|
||
|
try:
|
||
|
(openRow, openCol), (closeRow, closeCol) = findBalancedParens(lines, row, colEnd)
|
||
|
except ParseError:
|
||
|
ConversionError, "Can't find arguments."
|
||
|
|
||
|
if closeRow != openRow:
|
||
|
raise ConversionError, ("Can't perform conversion: arguments span multiple lines.")
|
||
|
|
||
|
args = lines[row][openCol + 1:closeCol]
|
||
|
match = re.search(r'([a-zA-Z_]\w*)' # Actuator identifier
|
||
|
r',\s*'
|
||
|
r'([0-9a-zA-Z_]\w*)', # Condition (boolean)
|
||
|
args)
|
||
|
if not match:
|
||
|
raise ConversionError, "Can't find arguments."
|
||
|
|
||
|
actuator = match.group(1)
|
||
|
condition = match.group(2)
|
||
|
controller = None
|
||
|
|
||
|
assn = findLastAssignment(lines, row, actuator)
|
||
|
if assn:
|
||
|
match = re.search(r'([a-zA-Z_]\w*)' # Controller identifier
|
||
|
r'\s*\.\s*' # Dot
|
||
|
r'(actuators\s*\[|getActuator\s*\()', # Dictionary/getter identifier
|
||
|
assn)
|
||
|
if match:
|
||
|
controller = match.group(1)
|
||
|
|
||
|
if not controller:
|
||
|
raise ConversionError, "Can't find actuator's controller."
|
||
|
|
||
|
gameLogicStart = lines[row].rfind("GameLogic", 0, colStart)
|
||
|
if gameLogicStart < 0:
|
||
|
raise ConversionError, "Can't find GameLogic identifier."
|
||
|
|
||
|
newExpr = None
|
||
|
if condition in ['1', 'True']:
|
||
|
newExpr = "%s.activate(%s)" % (controller, actuator)
|
||
|
elif condition in ['0', 'False']:
|
||
|
newExpr = "%s.deactivate(%s)" % (controller, actuator)
|
||
|
else:
|
||
|
newExpr = "(lambda: %s and (%s.activate(%s) or True) or %s.deactivate(%s))()" % (
|
||
|
condition, controller, actuator, controller, actuator)
|
||
|
lines[row] = replaceSubstr(lines[row], gameLogicStart, closeCol + 1, newExpr)
|
||
|
|
||
|
def getObject(line, attributeStart):
|
||
|
match = re.search(r'([a-zA-Z_]\w*)\s*\.\s*$', line[0:attributeStart])
|
||
|
if not match:
|
||
|
return None
|
||
|
return match.group(1)
|
||
|
|
||
|
def replaceGetActuator(lines, row, colStart, colEnd, closure):
|
||
|
'''getActuator is ambiguous: it could belong to SCA_IController or
|
||
|
SCA_ActuatorSensor. Try to resolve.
|
||
|
|
||
|
Raises a ConversionError if the parentheses can't be found, or if the
|
||
|
ambiguity can't be resolved.'''
|
||
|
# Get the name of the object this attribute is attached to.
|
||
|
obName = getObject(lines[row], colStart)
|
||
|
if obName:
|
||
|
# Try to find out whether the object is a controller.
|
||
|
assn = findLastAssignment(lines, row, obName)
|
||
|
if assn and re.search(r'GameLogic\s*\.\s*getCurrentController', assn):
|
||
|
# It is (probably) a controller!
|
||
|
replaceKeyedGetter(lines, row, colStart, colEnd, 'actuators')
|
||
|
return
|
||
|
|
||
|
raise ConversionError, "Ambiguous: addActiveActuator -> actuators[key] (SCA_IController) or actuator (SCA_ActuatorSensor)."
|
||
|
|
||
|
#
|
||
|
# Deprecated attribute information. The format is:
|
||
|
# deprecatedAttributeName: {(conversionFunction, closure): classList}
|
||
|
# Usually the closure will be the name of the superceding attribute.
|
||
|
#
|
||
|
# If an attribute maps to more than one function/attribute pair, the conversion
|
||
|
# is ambiguous and can't be performed.
|
||
|
#
|
||
|
attributeRenameDict = {
|
||
|
# Special cases
|
||
|
'addActiveActuator': {(replaceAddActiveActuator, None): []},
|
||
|
'getActuator': {(replaceGetActuator, None): ['SCA_IController', 'SCA_ActuatorSensor']},
|
||
|
'getXPosition': {(replaceGetXYPosition, '0'): ['SCA_MouseSensor']},
|
||
|
'getYPosition': {(replaceGetXYPosition, '1'): ['SCA_MouseSensor']},
|
||
|
|
||
|
# Unimplemented! There are probably more of these below that would cause errors.
|
||
|
#'getLinearVelocity': {(replaceSimpleGetter, 'linearVelocity'): ['KX_SCA_AddObjectActuator']},
|
||
|
#'setLinearVelocity': {(replaceSimpleSetter, 'linearVelocity'): ['KX_SCA_AddObjectActuator']},
|
||
|
#'getAngularVelocity': {(replaceSimpleGetter, 'angularVelocity'): ['KX_SCA_AddObjectActuator']},
|
||
|
#'setAngularVelocity': {(replaceSimpleSetter, 'angularVelocity'): ['KX_SCA_AddObjectActuator']},
|
||
|
|
||
|
# Generic converters
|
||
|
'enableViewport': {(replaceSimpleSetter, 'useViewport'): ['KX_Camera']},
|
||
|
'getAction': {(replaceSimpleGetter, 'action'): ['BL_ShapeActionActuator', 'BL_ActionActuator']},
|
||
|
'getActuators': {(replaceKeyedGetter, 'actuators'): ['SCA_IController']},
|
||
|
'getAxis': {(replaceSimpleGetter, 'axis'): ['SCA_JoystickSensor']},
|
||
|
'getAxisValue': {(replaceSimpleGetter, 'axisSingle'): ['SCA_JoystickSensor']},
|
||
|
'getBlendin': {(replaceSimpleGetter, 'blendIn'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'getBodies': {(replaceSimpleGetter, 'bodies'): ['KX_NetworkMessageSensor']},
|
||
|
'getButton': {(replaceSimpleGetter, 'button'): ['SCA_JoystickSensor']},
|
||
|
'getButtonValue': {(replaceRename, 'getButtonActiveList'): ['SCA_JoystickSensor']},
|
||
|
'getCamera': {(replaceSimpleGetter, 'camera'): ['KX_SceneActuator']},
|
||
|
'getConeOrigin': {(replaceSimpleGetter, 'coneOrigin'): ['KX_RadarSensor']},
|
||
|
'getConeTarget': {(replaceSimpleGetter, 'coneTarget'): ['KX_RadarSensor']},
|
||
|
'getContinue': {(replaceSimpleGetter, 'useContinue'): ['BL_ActionActuator']},
|
||
|
'getCurrentlyPressedKeys': {(replaceSimpleGetter, 'events'): ['SCA_KeyboardSensor']},
|
||
|
'getDelay': {(replaceSimpleGetter, 'delay'): ['SCA_DelaySensor']},
|
||
|
'getDistribution': {(replaceSimpleGetter, 'distribution'): ['SCA_RandomActuator']},
|
||
|
'getDuration': {(replaceSimpleGetter, 'duration'): ['SCA_DelaySensor']},
|
||
|
'getEnd': {(replaceSimpleGetter, 'frameEnd'): ['BL_ShapeActionActuator',
|
||
|
'KX_IpoActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'getExecutePriority': {(replaceSimpleGetter, 'executePriority'): ['SCA_ILogicBrick']},
|
||
|
'getFile': {(replaceSimpleGetter, 'fileName'): ['KX_GameActuator']},
|
||
|
'getFilename': {(replaceSimpleGetter, 'fileName'): ['KX_SoundActuator']},
|
||
|
'getForceIpoActsLocal': {(replaceSimpleGetter, 'useIpoLocal'): ['KX_IpoActuator']},
|
||
|
'getFrame': {(replaceSimpleGetter, 'frame'): ['BL_ShapeActionActuator', 'BL_ActionActuator']},
|
||
|
'getFrameMessageCount': {(replaceSimpleGetter, 'frameMessageCount'): ['KX_NetworkMessageSensor']},
|
||
|
'getFrameProperty': {(replaceSimpleGetter, 'framePropName'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'getFrequency': {(replaceSimpleGetter, 'frequency'): ['SCA_ISensor']},
|
||
|
'getGain': {(replaceSimpleGetter, 'volume'): ['KX_SoundActuator', 'KX_CDActuator']},
|
||
|
'getHat': {(replaceSimpleGetter, 'hat'): ['SCA_JoystickSensor']},
|
||
|
'getHeight': {(replaceSimpleGetter, 'height'): ['KX_CameraActuator']},
|
||
|
'getHitNormal': {(replaceSimpleGetter, 'hitNormal'): ['KX_MouseFocusSensor', 'KX_RaySensor']},
|
||
|
'getHitObject': {(replaceSimpleGetter, 'hitObject'): ['KX_MouseFocusSensor',
|
||
|
'KX_RaySensor',
|
||
|
'KX_TouchSensor']},
|
||
|
'getHitObjectList': {(replaceSimpleGetter, 'hitObjectList'): ['KX_TouchSensor']},
|
||
|
'getHitPosition': {(replaceSimpleGetter, 'hitPosition'): ['KX_MouseFocusSensor',
|
||
|
'KX_RaySensor']},
|
||
|
'getHold1': {(replaceSimpleGetter, 'hold1'): ['SCA_KeyboardSensor']},
|
||
|
'getHold2': {(replaceSimpleGetter, 'hold2'): ['SCA_KeyboardSensor']},
|
||
|
'getIndex': {(replaceSimpleGetter, 'index'): ['SCA_JoystickSensor']},
|
||
|
'getInvert': {(replaceSimpleGetter, 'invert'): ['SCA_ISensor']},
|
||
|
'getIpoAdd': {(replaceSimpleGetter, 'useIpoAdd'): ['KX_IpoActuator']},
|
||
|
'getIpoAsForce': {(replaceSimpleGetter, 'useIpoAsForce'): ['KX_IpoActuator']},
|
||
|
'getKey': {(replaceSimpleGetter, 'key'): ['SCA_KeyboardSensor']},
|
||
|
'getLastCreatedObject': {(replaceSimpleGetter, 'objectLastCreated'): ['KX_SCA_AddObjectActuator']},
|
||
|
'getLevel': {(replaceSimpleGetter, 'level'): ['SCA_ISensor']},
|
||
|
'getLightList': {(replaceSimpleGetter, 'lights'): ['KX_Scene']},
|
||
|
'getLooping': {(replaceSimpleGetter, 'looping'): ['KX_SoundActuator']},
|
||
|
'getMass': {(replaceSimpleGetter, 'mass'): ['KX_GameObject']},
|
||
|
'getMax': {(replaceSimpleGetter, 'max'): ['KX_CameraActuator']},
|
||
|
'getMesh': {(replaceSimpleGetter, 'mesh'): ['KX_SCA_ReplaceMeshActuator']},
|
||
|
'getMin': {(replaceSimpleGetter, 'min'): ['KX_CameraActuator']},
|
||
|
'getName': {(replaceSimpleGetter, 'name'): ['KX_Scene']},
|
||
|
'getNumAxes': {(replaceSimpleGetter, 'numAxis'): ['SCA_JoystickSensor']},
|
||
|
'getNumButtons': {(replaceSimpleGetter, 'numButtons'): ['SCA_JoystickSensor']},
|
||
|
'getNumHats': {(replaceSimpleGetter, 'numHats'): ['SCA_JoystickSensor']},
|
||
|
'getObject': {(replaceSimpleGetter, 'object'): ['KX_SCA_AddObjectActuator',
|
||
|
'KX_CameraActuator',
|
||
|
'KX_TrackToActuator',
|
||
|
'KX_ParentActuator']},
|
||
|
'getObjectList': {(replaceSimpleGetter, 'objects'): ['KX_Scene']},
|
||
|
'getOperation': {(replaceSimpleGetter, 'mode'): ['KX_SCA_DynamicActuator']},
|
||
|
'getOrientation': {(replaceSimpleGetter, 'worldOrientation'): ['KX_GameObject']},
|
||
|
'getOwner': {(replaceSimpleGetter, 'owner'): ['SCA_ILogicBrick']},
|
||
|
'getPara1': {(replaceSimpleGetter, 'para1'): ['SCA_RandomActuator']},
|
||
|
'getPara2': {(replaceSimpleGetter, 'para2'): ['SCA_RandomActuator']},
|
||
|
'getParent': {(replaceSimpleGetter, 'parent'): ['KX_GameObject']},
|
||
|
'getPitch': {(replaceSimpleGetter, 'pitch'): ['KX_SoundActuator']},
|
||
|
'getPosition': {(replaceSimpleGetter, 'worldPosition'): ['KX_GameObject']},
|
||
|
'getPressedKeys': {(replaceSimpleGetter, 'events'): ['SCA_KeyboardSensor']},
|
||
|
'getPriority': {(replaceSimpleGetter, 'priority'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'getProjectionMatrix': {(replaceSimpleGetter, 'projection_matrix'): ['KX_Camera']},
|
||
|
'getProperty': {(replaceSimpleGetter, 'propName'): ['SCA_PropertySensor',
|
||
|
'SCA_RandomActuator']},
|
||
|
'getRayDirection': {(replaceSimpleGetter, 'rayDirection'): ['KX_MouseFocusSensor',
|
||
|
'KX_RaySensor']},
|
||
|
'getRaySource': {(replaceSimpleGetter, 'raySource'): ['KX_MouseFocusSensor']},
|
||
|
'getRayTarget': {(replaceSimpleGetter, 'rayTarget'): ['KX_MouseFocusSensor']},
|
||
|
'getRepeat': {(replaceSimpleGetter, 'repeat'): ['SCA_DelaySensor']},
|
||
|
'getRollOffFactor': {(replaceSimpleGetter, 'rollOffFactor'): ['KX_SoundActuator']},
|
||
|
'getScene': {(replaceSimpleGetter, 'scene'): ['KX_SceneActuator']},
|
||
|
'getScript': {(replaceSimpleGetter, 'script'): ['SCA_PythonController']},
|
||
|
'getSeed': {(replaceSimpleGetter, 'seed'): ['SCA_RandomActuator']},
|
||
|
'getSensor': {(replaceKeyedGetter, 'sensors'): ['SCA_IController']},
|
||
|
'getSensors': {(replaceKeyedGetter, 'sensors'): ['SCA_IController']},
|
||
|
'getStart': {(replaceSimpleGetter, 'frameStart'): ['BL_ShapeActionActuator',
|
||
|
'KX_IpoActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'getState': {(replaceSimpleGetter, 'state'): ['SCA_IController', 'KX_GameObject']},
|
||
|
'getSubject': {(replaceSimpleGetter, 'subject'): ['KX_NetworkMessageSensor']},
|
||
|
'getSubjects': {(replaceSimpleGetter, 'subjects'): ['KX_NetworkMessageSensor']},
|
||
|
'getThreshold': {(replaceSimpleGetter, 'threshold'): ['SCA_JoystickSensor']},
|
||
|
'getTime': {(replaceSimpleGetter, 'time'): ['KX_SCA_AddObjectActuator', 'KX_TrackToActuator']},
|
||
|
'getTouchMaterial': {(replaceSimpleGetter, 'useMaterial'): ['KX_TouchSensor']},
|
||
|
'getType': {(replaceSimpleGetter, 'mode'): ['SCA_PropertySensor']},
|
||
|
'getUse3D': {(replaceSimpleGetter, 'use3D'): ['KX_TrackToActuator']},
|
||
|
'getUseNegPulseMode': {(replaceSimpleGetter, 'useNegPulseMode'): ['SCA_ISensor']},
|
||
|
'getUsePosPulseMode': {(replaceSimpleGetter, 'usePosPulseMode'): ['SCA_ISensor']},
|
||
|
'getUseRestart': {(replaceSimpleGetter, 'useRestart'): ['KX_SceneActuator']},
|
||
|
'getValue': {(replaceSimpleGetter, 'value'): ['SCA_PropertySensor', 'SCA_PropertyActuator']},
|
||
|
'getVisible': {(replaceSimpleGetter, 'visible'): ['KX_GameObject']},
|
||
|
'getXY': {(replaceSimpleGetter, 'useXY'): ['KX_CameraActuator']},
|
||
|
'isConnected': {(replaceSimpleGetter, 'connected'): ['SCA_JoystickSensor']},
|
||
|
'isPositive': {(replaceSimpleGetter, 'positive'): ['SCA_ISensor']},
|
||
|
'isTriggered': {(replaceSimpleGetter, 'triggered'): ['SCA_ISensor']},
|
||
|
'set': {(replaceSimpleSetter, 'visibility'): ['KX_VisibilityActuator']},
|
||
|
'setAction': {(replaceSimpleSetter, 'action'): ['BL_ShapeActionActuator', 'BL_ActionActuator']},
|
||
|
'setActuator': {(replaceSimpleSetter, 'actuator'): ['SCA_ActuatorSensor']},
|
||
|
'setAxis': {(replaceSimpleSetter, 'axis'): ['SCA_JoystickSensor']},
|
||
|
'setBlendin': {(replaceSimpleSetter, 'blendIn'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setBlendtime': {(replaceSimpleSetter, 'blendTime'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setBodyType': {(replaceSimpleSetter, 'usePropBody'): ['KX_NetworkMessageActuator']},
|
||
|
'setButton': {(replaceSimpleSetter, 'button'): ['SCA_JoystickSensor']},
|
||
|
'setCamera': {(replaceSimpleSetter, 'camera'): ['KX_SceneActuator']},
|
||
|
'setContinue': {(replaceSimpleSetter, 'useContinue'): ['BL_ActionActuator']},
|
||
|
'setDelay': {(replaceSimpleSetter, 'delay'): ['SCA_DelaySensor']},
|
||
|
'setDuration': {(replaceSimpleSetter, 'duration'): ['SCA_DelaySensor']},
|
||
|
'setEnd': {(replaceSimpleSetter, 'frameEnd'): ['BL_ShapeActionActuator',
|
||
|
'KX_IpoActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setExecutePriority': {(replaceSimpleSetter, 'executePriority'): ['SCA_ILogicBrick']},
|
||
|
'setFile': {(replaceSimpleSetter, 'fileName'): ['KX_GameActuator']},
|
||
|
'setFilename': {(replaceSimpleSetter, 'fileName'): ['KX_SoundActuator']},
|
||
|
'setForceIpoActsLocal': {(replaceSimpleSetter, 'useIpoLocal'): ['KX_IpoActuator']},
|
||
|
'setFrame': {(replaceSimpleSetter, 'frame'): ['BL_ShapeActionActuator', 'BL_ActionActuator']},
|
||
|
'setFrameProperty': {(replaceSimpleSetter, 'framePropName'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setFrequency': {(replaceSimpleSetter, 'frequency'): ['SCA_ISensor']},
|
||
|
'setGain': {(replaceSimpleSetter, 'volume'): ['KX_SoundActuator', 'KX_CDActuator']},
|
||
|
'setHat': {(replaceSimpleSetter, 'hat'): ['SCA_JoystickSensor']},
|
||
|
'setHeight': {(replaceSimpleSetter, 'height'): ['KX_CameraActuator']},
|
||
|
'setHold1': {(replaceSimpleSetter, 'hold1'): ['SCA_KeyboardSensor']},
|
||
|
'setHold2': {(replaceSimpleSetter, 'hold2'): ['SCA_KeyboardSensor']},
|
||
|
'setIndex': {(replaceSimpleSetter, 'index'): ['SCA_JoystickSensor']},
|
||
|
'setInvert': {(replaceSimpleSetter, 'invert'): ['SCA_ISensor']},
|
||
|
'setIpoAdd': {(replaceSimpleSetter, 'useIpoAdd'): ['KX_IpoActuator']},
|
||
|
'setIpoAsForce': {(replaceSimpleSetter, 'useIpoAsForce'): ['KX_IpoActuator']},
|
||
|
'setKey': {(replaceSimpleSetter, 'key'): ['SCA_KeyboardSensor']},
|
||
|
'setLevel': {(replaceSimpleSetter, 'level'): ['SCA_ISensor']},
|
||
|
'setLooping': {(replaceSimpleSetter, 'looping'): ['KX_SoundActuator']},
|
||
|
'setMask': {(replaceSimpleSetter, 'mask'): ['KX_StateActuator']},
|
||
|
'setMax': {(replaceSimpleSetter, 'max'): ['KX_CameraActuator']},
|
||
|
'setMesh': {(replaceSimpleSetter, 'mesh'): ['KX_SCA_ReplaceMeshActuator']},
|
||
|
'setMin': {(replaceSimpleSetter, 'min'): ['KX_CameraActuator']},
|
||
|
'setObject': {(replaceSimpleSetter, 'object'): ['KX_SCA_AddObjectActuator',
|
||
|
'KX_CameraActuator',
|
||
|
'KX_TrackToActuator',
|
||
|
'KX_ParentActuator']},
|
||
|
'setOperation': {(replaceSimpleSetter, 'mode'): ['KX_SCA_DynamicActuator'],
|
||
|
(replaceSimpleSetter, 'operation'): ['KX_StateActuator']},
|
||
|
'setOrientation': {(replaceSimpleSetter, 'localOrientation'): ['KX_GameObject'],
|
||
|
(replaceSimpleSetter, 'orientation'): ['KX_SoundActuator']},
|
||
|
'setPitch': {(replaceSimpleSetter, 'pitch'): ['KX_SoundActuator']},
|
||
|
'setPosition': {(replaceSimpleSetter, 'localPosition'): ['KX_GameObject'],
|
||
|
(replaceSimpleSetter, 'position'): ['KX_SoundActuator']},
|
||
|
'setPriority': {(replaceSimpleSetter, 'priority'): ['BL_ShapeActionActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setProjectionMatrix': {(replaceSimpleSetter, 'projection_matrix'): ['KX_Camera']},
|
||
|
'setProperty': {(replaceSimpleSetter, 'propName'): ['KX_IpoActuator',
|
||
|
'SCA_PropertySensor',
|
||
|
'SCA_RandomActuator']},
|
||
|
'setRepeat': {(replaceSimpleSetter, 'repeat'): ['SCA_DelaySensor']},
|
||
|
'setRollOffFactor': {(replaceSimpleSetter, 'rollOffFactor'): ['KX_SoundActuator']},
|
||
|
'setScene': {(replaceSimpleSetter, 'scene'): ['KX_SceneActuator']},
|
||
|
'setScript': {(replaceSimpleSetter, 'script'): ['SCA_PythonController']},
|
||
|
'setSeed': {(replaceSimpleSetter, 'seed'): ['SCA_RandomActuator']},
|
||
|
'setStart': {(replaceSimpleSetter, 'frameStart'): ['BL_ShapeActionActuator',
|
||
|
'KX_IpoActuator',
|
||
|
'BL_ActionActuator']},
|
||
|
'setState': {(replaceSimpleSetter, 'state'): ['KX_GameObject']},
|
||
|
'setSubject': {(replaceSimpleSetter, 'subject'): ['KX_NetworkMessageActuator']},
|
||
|
'setSubjectFilterText': {(replaceSimpleSetter, 'subject'): ['KX_NetworkMessageSensor']},
|
||
|
'setThreshold': {(replaceSimpleSetter, 'threshold'): ['SCA_JoystickSensor']},
|
||
|
'setTime': {(replaceSimpleSetter, 'time'): ['KX_SCA_AddObjectActuator', 'KX_TrackToActuator']},
|
||
|
'setToPropName': {(replaceSimpleSetter, 'propName'): ['KX_NetworkMessageActuator']},
|
||
|
'setType': {(replaceSimpleSetter, 'mode'): ['SCA_PropertySensor']},
|
||
|
'setUse3D': {(replaceSimpleSetter, 'use3D'): ['KX_TrackToActuator']},
|
||
|
'setUseNegPulseMode': {(replaceSimpleSetter, 'useNegPulseMode'): ['SCA_ISensor']},
|
||
|
'setUsePosPulseMode': {(replaceSimpleSetter, 'usePosPulseMode'): ['SCA_ISensor']},
|
||
|
'setUseRestart': {(replaceSimpleSetter, 'useRestart'): ['KX_SceneActuator']},
|
||
|
'setValue': {(replaceSimpleSetter, 'value'): ['SCA_PropertySensor', 'SCA_PropertyActuator']},
|
||
|
'setVelocity': {(replaceSimpleSetter, 'velocity'): ['KX_SoundActuator']},
|
||
|
'setXY': {(replaceSimpleSetter, 'useXY'): ['KX_CameraActuator']}
|
||
|
}
|
||
|
|
||
|
def convert248to249(lines, log = True, logErrors = True):
|
||
|
# Regular expression for finding attributes. For the string 'a.b', this
|
||
|
# returns three groups: ['a.b', 'a.', 'b']. The last is the attribute name.
|
||
|
attrRegex = re.compile(r'\.\s*' # Dot
|
||
|
r'([a-zA-Z_]\w*)') # Identifier
|
||
|
|
||
|
row = 0
|
||
|
sourceRow = 0
|
||
|
col = 0
|
||
|
nconverted = 0
|
||
|
nerrors = 0
|
||
|
while row < len(lines):
|
||
|
originalLine = lines[row]
|
||
|
changed = False
|
||
|
while col < len(lines[row]):
|
||
|
# Don't search past comment. We have to check each iteration
|
||
|
# because the line contents may have changed.
|
||
|
commentStart = lines[row].find('#', col)
|
||
|
if commentStart < 0:
|
||
|
commentStart = len(lines[row])
|
||
|
|
||
|
# Search for an attribute identifier.
|
||
|
match = attrRegex.search(lines[row], col, commentStart)
|
||
|
if not match:
|
||
|
break
|
||
|
|
||
|
attrName = match.group(1)
|
||
|
if attributeRenameDict.has_key(attrName):
|
||
|
# name is deprecated.
|
||
|
conversionDict = attributeRenameDict[attrName]
|
||
|
|
||
|
if len(conversionDict.keys()) > 1:
|
||
|
# Ambiguous! Can't convert.
|
||
|
print "ERROR: source line %d, ambiguous conversion:" % sourceRow
|
||
|
if logErrors:
|
||
|
lines.insert(row, "##248## ERROR: ambiguous conversion.\n")
|
||
|
row = row + 1
|
||
|
for conversion in conversionDict.keys():
|
||
|
_, newAttrName = conversion
|
||
|
classes = conversionDict[conversion]
|
||
|
print "\t%s -> %s (classes %s)" % (attrName, newAttrName, classes)
|
||
|
if logErrors:
|
||
|
lines.insert(row, "##248##%s -> %s (classes %s)\n" %
|
||
|
(attrName, newAttrName, classes))
|
||
|
row = row + 1
|
||
|
nerrors = nerrors + 1
|
||
|
|
||
|
else:
|
||
|
# Conversion is well-defined. Execute.
|
||
|
func, newAttrName = conversionDict.keys()[0]
|
||
|
try:
|
||
|
func(lines, row, match.start(1), match.end(1), newAttrName)
|
||
|
except ConversionError as e:
|
||
|
# Insert a comment saying the conversion failed.
|
||
|
print "ERROR: source line %d, %s: %s\n" % (
|
||
|
sourceRow, attrName, e)
|
||
|
if logErrors:
|
||
|
lines.insert(row,
|
||
|
"##248## ERROR: %s: %s\n" %
|
||
|
(attrName, e))
|
||
|
row = row + 1
|
||
|
nerrors = nerrors + 1
|
||
|
else:
|
||
|
changed = True
|
||
|
nconverted = nconverted + 1
|
||
|
# Search the rest of this line.
|
||
|
col = match.start(1)
|
||
|
if changed and log:
|
||
|
if originalLine[-1] != '\n':
|
||
|
originalLine = originalLine + '\n'
|
||
|
lines.insert(row, "##248##%s" % originalLine)
|
||
|
row = row + 1
|
||
|
row = row + 1
|
||
|
sourceRow = sourceRow + 1
|
||
|
col = 0
|
||
|
return nconverted, nerrors
|
||
|
|
||
|
def usage():
|
||
|
print "Usage: blender248to249.py [options] <infile> [outfile]"
|
||
|
print "Options:"
|
||
|
print "\t--nolog Don't include old lines as comments."
|
||
|
print "\t--quieterrors Don't insert errors as comments."
|
||
|
|
||
|
def runAsConsoleScript():
|
||
|
'''Called when being run as a console script.'''
|
||
|
try:
|
||
|
opts, args = getopt.getopt(sys.argv[1:], "", ["nolog", "quieterrors"])
|
||
|
except getopt.GetoptError, err:
|
||
|
# print help information and exit:
|
||
|
print str(err)
|
||
|
usage()
|
||
|
sys.exit(2)
|
||
|
|
||
|
log = True
|
||
|
logErrors = True
|
||
|
for o, a in opts:
|
||
|
if o == "--nolog":
|
||
|
log = False
|
||
|
elif o == "--quieterrors":
|
||
|
logErrors = False
|
||
|
|
||
|
try:
|
||
|
inpath = args.pop(0)
|
||
|
except IndexError:
|
||
|
usage()
|
||
|
sys.exit(2)
|
||
|
try:
|
||
|
outpath = args.pop(0)
|
||
|
except IndexError:
|
||
|
outpath = inpath
|
||
|
|
||
|
infile = io.FileIO(inpath, 'r')
|
||
|
# arbitrary file size of around 100kB
|
||
|
lines = infile.readlines(100000)
|
||
|
infile.close()
|
||
|
|
||
|
nconverted, nerrors = convert248to249(lines, log, logErrors)
|
||
|
|
||
|
outfile = io.FileIO(outpath, 'w')
|
||
|
outfile.writelines(lines)
|
||
|
outfile.close()
|
||
|
print "Conversion finished. Modified %d attributes." % nconverted
|
||
|
print "There were %d errors." % nerrors
|
||
|
print "Please review all the changes."
|
||
|
|
||
|
def runAsTextPlugin():
|
||
|
'''Called when run as a text plugin.'''
|
||
|
|
||
|
import Blender
|
||
|
from Blender import Window, sys, Draw
|
||
|
import BPyTextPlugin, bpy
|
||
|
|
||
|
# Gets the active text object, there can be many in one blend file.
|
||
|
txt = bpy.data.texts.active
|
||
|
|
||
|
# Silently return if the script has been run with no active text
|
||
|
if not txt:
|
||
|
return
|
||
|
|
||
|
Window.WaitCursor(1)
|
||
|
try:
|
||
|
lines = txt.asLines()
|
||
|
for i in range(0, len(lines)):
|
||
|
if not lines[i].endswith('\n'):
|
||
|
lines[i] = lines[i] + '\n'
|
||
|
|
||
|
nconverted, nerrors = convert248to249(lines)
|
||
|
|
||
|
Blender.SaveUndoState('Convert GE 249')
|
||
|
txt.clear()
|
||
|
for line in lines:
|
||
|
txt.write(line)
|
||
|
|
||
|
message = "Converted %d attributes." % nconverted
|
||
|
if nerrors == 1:
|
||
|
message = message + " There was 1 error (see console)."
|
||
|
if nerrors > 1:
|
||
|
message = message + " There were %d errors (see console)." % nerrors
|
||
|
message = message + "|Please review all the changes."
|
||
|
Draw.PupMenu(message)
|
||
|
|
||
|
finally:
|
||
|
Window.WaitCursor(0)
|
||
|
|
||
|
def main():
|
||
|
try:
|
||
|
import Blender
|
||
|
except ImportError:
|
||
|
runAsConsoleScript()
|
||
|
else:
|
||
|
runAsTextPlugin()
|
||
|
|
||
|
# This lets you import the script without running it
|
||
|
if __name__ == "__main__":
|
||
|
import sys
|
||
|
import getopt
|
||
|
import io
|
||
|
main()
|