123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- #!/usr/bin/env python3
- #
- # SuperTuxKart - a fun racing game with go-kart
- # Copyright (C) 2006-2015 SuperTuxKart-Team
- #
- # 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, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- # This script creates code for the characteristics.
- # It takes an argument that specifies what the output of the script should be.
- # The output options can be seen by running this script without arguments.
- # A more convenient version to update the code is to run update_characteristics.py
- import sys
- # Input data
- # Each line contains a topic and the attributes of that topic.
- # This model is used for the xml file and to access the kart properties in the code.
- characteristics = """Suspension: stiffness, rest, travel, expSpringResponse(bool), maxForce
- Stability: rollInfluence, chassisLinearDamping, chassisAngularDamping, downwardImpulseFactor, trackConnectionAccel, smoothFlyingImpulse
- Turn: radius(InterpolationArray), timeResetSteer, timeFullSteer(InterpolationArray)
- Engine: power, maxSpeed, brakeFactor, brakeTimeIncrease, maxSpeedReverseRatio
- Gear: switchRatio(std::vector<float>/floatVector), powerIncrease(std::vector<float>/floatVector)
- Mass
- Wheels: dampingRelaxation, dampingCompression
- Camera: distance, forwardUpAngle, backwardUpAngle
- Jump: animationTime
- Lean: max, speed
- Anvil: duration, weight, speedFactor
- Parachute: friction, duration, durationOther, lboundFraction, uboundFraction, maxSpeed
- Bubblegum: duration, speedFraction, torque, fadeInTime, shieldDuration
- Zipper: duration, force, speedGain, maxSpeedIncrease, fadeOutTime
- Swatter: duration, distance, squashDuration, squashSlowdown
- Plunger: bandMaxLength, bandForce, bandDuration, bandSpeedIncrease, bandFadeOutTime, inFaceTime
- Startup: time(std::vector<float>/floatVector), boost(std::vector<float>/floatVector)
- Rescue: duration, vertOffset, height
- Explosion: duration, radius, invulnerabilityTime
- Nitro: duration, engineForce, consumption, smallContainer, bigContainer, maxSpeedIncrease, fadeOutTime, max
- Slipstream: duration, length, width, collectTime, useTime, addPower, minSpeed, maxSpeedIncrease, fadeOutTime
- Skid: increase, decrease, max, timeTillMax, visual, visualTime, revertVisualTime, minSpeed, timeTillBonus(std::vector<float>/floatVector), bonusSpeed(std::vector<float>/floatVector), bonusTime(std::vector<float>/floatVector), bonusForce(std::vector<float>/floatVector), physicalJumpTime, graphicalJumpTime, postSkidRotateFactor, reduceTurnMin, reduceTurnMax, enabled(bool)"""
- """ A GroupMember is an attribute of a group.
- In the xml files, a value will be assigned to it.
- If the name of the attribute is 'value', the getter method will only
- contain the group name and 'value' will be omitted (e.g. used for mass). """
- class GroupMember:
- def __init__(self, name, typeC, typeStr):
- self.name = name
- if name == "value":
- self.getName = ""
- else:
- self.getName = name
- self.typeC = typeC
- self.typeStr = typeStr
- """ E.g. power(std::vector<float>/floatVector)
- or speed(InterpolationArray)
- The default type is float
- The name 'value' is special: Only the group name will be used to access
- the member but in the xml file it will be still value (because we
- need a name). """
- def parse(content):
- typeC = "float"
- typeStr = typeC
- name = content.strip()
- pos = content.find("(")
- end = content.find(")", pos)
- if pos != -1 and end != -1:
- name = content[:pos].strip()
- pos2 = content.find("/", pos, end)
- if pos2 != -1:
- typeC = content[pos + 1:pos2].strip()
- typeStr = content[pos2 + 1:end].strip()
- else:
- typeC = content[pos + 1:end].strip()
- typeStr = typeC
- return GroupMember(name, typeC, typeStr)
- """ A Group has a base name and can contain GroupMembers.
- In the xml files, a group is a tag. """
- class Group:
- def __init__(self, baseName):
- self.baseName = baseName
- self.members = []
- """ Parses and adds a member to this group """
- def addMember(self, content):
- self.members.append(GroupMember.parse(content))
- def getBaseName(self):
- return self.baseName
- """ E.g. engine: power, gears(std::vector<Gear>/Gears)
- or mass(float) or only mass """
- def parse(content):
- pos = content.find(":")
- if pos == -1:
- group = Group(content)
- group.addMember("value")
- return group
- else:
- group = Group(content[:pos].strip())
- for m in content[pos + 1:].split(","):
- group.addMember(m)
- return group
- """ Creates a list of words from a titlecase string """
- def toList(name):
- result = []
- cur = ""
- for c in name:
- if c.isupper() and len(cur) != 0:
- result.append(cur)
- cur = ""
- cur += c.lower()
- if len(cur) != 0:
- result.append(cur)
- return result
- """ titleCase: true = result is titlecase
- false = result has underscores """
- def joinSubName(group, member, titleCase):
- words = toList(group.baseName) + toList(member.getName)
- first = True
- if titleCase:
- words = [w.title() for w in words]
- return "".join(words)
- else:
- return "_".join(words)
- # Functions to generate code
- def createEnum(groups):
- for g in groups:
- print()
- print(" // {0}".format(g.getBaseName().title()))
- for m in g.members:
- print(" {0},".format(joinSubName(g, m, False).upper()))
- def createAcDefs(groups):
- for g in groups:
- print()
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False)
- typeC = m.typeC
- print(" {0} get{1}() const;".
- format(typeC, nameTitle, nameUnderscore))
- def createAcGetter(groups):
- for g in groups:
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False)
- typeC = m.typeC
- result = "result"
- print("""// ----------------------------------------------------------------------------
- {3} AbstractCharacteristic::get{1}() const
- {{
- {0} result;
- bool is_set = false;
- process({2}, &result, &is_set);
- if (!is_set)
- Log::fatal("AbstractCharacteristic", "Can't get characteristic %s",
- getName({2}).c_str());
- return {4};
- }} // get{1}
- """.format(m.typeC, nameTitle, nameUnderscore.upper(), typeC, result))
- def createKpDefs(groups):
- for g in groups:
- print()
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False)
- typeC = m.typeC
- print(" {0} get{1}() const;".
- format(typeC, nameTitle, nameUnderscore))
- def createKpGetter(groups):
- for g in groups:
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False)
- typeC = m.typeC
- result = "result"
- print("""// ----------------------------------------------------------------------------
- {1} KartProperties::get{0}() const
- {{
- return m_cached_characteristic->get{0}();
- }} // get{0}
- """.format(nameTitle, typeC))
- def createGetType(groups):
- for g in groups:
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False)
- print(" case {0}:\n return TYPE_{1};".
- format(nameUnderscore.upper(), "_".join(toList(m.typeStr)).upper()))
- def createGetName(groups):
- for g in groups:
- for m in g.members:
- nameTitle = joinSubName(g, m, True)
- nameUnderscore = joinSubName(g, m, False).upper()
- print(" case {0}:\n return \"{0}\";".
- format(nameUnderscore))
- def createLoadXml(groups):
- for g in groups:
- print(" if (const XMLNode *sub_node = node->getNode(\"{0}\"))\n {{".
- format(g.baseName.lower()))
- for m in g.members:
- nameUnderscore = joinSubName(g, m, False)
- nameMinus = "-".join(toList(m.name))
- print(""" sub_node->get(\"{0}\",
- &m_values[{1}]);""".
- format(nameMinus, nameUnderscore.upper()))
- print(" }\n")
- # Dicionary that maps an argument string to a tupel of
- # a generator function, a help string and a filename
- functions = {
- "enum": (createEnum, "List the enum values for all characteristics", "karts/abstract_characteristic.hpp"),
- "acdefs": (createAcDefs, "Create the header function definitions", "karts/abstract_characteristic.hpp"),
- "acgetter": (createAcGetter, "Implement the getters", "karts/abstract_characteristic.cpp"),
- "getType": (createGetType, "Implement the getType function", "karts/abstract_characteristic.cpp"),
- "getName": (createGetName, "Implement the getName function", "karts/abstract_characteristic.cpp"),
- "kpdefs": (createKpDefs, "Create the header function definitions for the getters", "karts/kart_properties.hpp"),
- "kpgetter": (createKpGetter, "Implement the getters", "karts/kart_properties.cpp"),
- "loadXml": (createLoadXml, "Code to load the characteristics from an xml file", "karts/xml_characteristic.hpp"),
- }
- def main():
- # Find out what to do
- if len(sys.argv) != 2:
- print("""Usage: ./create_kart_properties.py <operation>
- Operations:""")
- maxOperationLength = 0
- maxDescriptionLength = 0
- for o, f in functions.items():
- l = len(o)
- if l > maxOperationLength:
- maxOperationLength = l
- l = len(f[1])
- if l > maxDescriptionLength:
- maxDescriptionLength = l
- formatString = " {{0:{0}}} {{1:{1}}} in {{2}}".format(maxOperationLength, maxDescriptionLength)
- for o, f in functions.items():
- print(formatString.format(o, f[1], f[2]))
- return
- task = sys.argv[1]
- if task not in functions:
- print("The wanted operation was not found. Please call this script without arguments to list available arguments.")
- return
- # Parse properties
- groups = [Group.parse(line) for line in characteristics.split("\n")]
- # Create the wanted code
- functions[task][0](groups)
- if __name__ == '__main__':
- main()
|