Last active
May 8, 2024 06:31
-
-
Save sehraf/cb6d128fcd1fba7a1f37b15292d210f4 to your computer and use it in GitHub Desktop.
Skryim RaceMenu BodySlide morphe converter. Converts the racemenu preset BodySlide morphs to a BodySlide studio preset. Tested once with mixed results...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import xml.etree.ElementTree as ET | |
import xml.dom.minidom as MD | |
# BodySlide options, too be completed | |
bodyslide_elems = [ | |
"Ankles", | |
"AppleCheeks", | |
"Arms", | |
"Back", | |
"Belly", | |
"BigBelly", | |
"BigButt", | |
"BigTorso", | |
"BreastCleavage", | |
"BreastFlatness", | |
"BreastGravity", | |
"BreastHeight", | |
"BreastPerkiness", | |
"Breasts", | |
"BreastsFantasy", | |
"BreastsSH", | |
"BreastsSmall", | |
"BreastsSSH", | |
"BreastWidth", | |
"Butt", | |
"ButtCrack", | |
"ButtShape2", | |
"ButtSmall", | |
"CalfSize", | |
"CalfSmooth", | |
"ChubbyArms", | |
"ChubbyButt", | |
"ChubbyLegs", | |
"ChubbyWaist", | |
"DoubleMelon", | |
"Groin", | |
"HipBone", | |
"Hips", | |
"KneeHeight", | |
"Legs", | |
"NippleAreola", | |
"NippleDistance", | |
"NippleDown", | |
"NippleLength", | |
"NippleSize", | |
"NippleTip", | |
"NippleUp", | |
"NipplePerkiness", | |
"RoundAss", | |
"PushUp", | |
"ShoulderSmooth", | |
"ShoulderWidth", | |
"SlimThighs", | |
"Thighs", | |
"TummyTuck", | |
"Waist", | |
"WideWaistLine", | |
] | |
def load_json(file): | |
with open(file, 'r') as handle: | |
parsed = json.load(handle) | |
return parsed | |
def save_xml(file, data): | |
with open(file, 'w') as handle: | |
handle.write(prettify(data.getroot())) | |
def prettify(elem): | |
"""Return a pretty-printed XML string for the Element. | |
""" | |
rough_string = ET.tostring(elem, 'utf-8') | |
reparsed = MD.parseString(rough_string) | |
return reparsed.toprettyxml(indent="\t", ) | |
def convert_racemenu_2_bodyslide(file_name: str): | |
# read input file | |
input = load_json(file_name + '.jslot') | |
# get bodyMorph node | |
body_morph = input['bodyMorphs'] | |
# print(body_morph) | |
# fill missing entries | |
for e in bodyslide_elems: | |
if e not in [a['name'] for a in body_morph]: | |
body_morph.append( | |
{ | |
'name': e, | |
'keys': [ | |
{ | |
'value': 0 | |
} | |
] | |
} | |
) | |
# build xml | |
r = ET.Element('SliderPresets') | |
tree = ET.ElementTree(r) | |
root = tree.getroot() | |
preset = ET.SubElement(root, 'Preset') | |
preset.attrib['name'] = file_name + ' preset' | |
preset.attrib['set'] = file_name + ' Body' # ??? | |
group = ET.SubElement(preset, 'Group') | |
group.attrib['name'] = 'CBAdvanced' | |
# calculate new values | |
for entry in body_morph: | |
# get name and value | |
value = entry['keys'][0]['value'] | |
name = entry['name'] | |
if name not in bodyslide_elems: | |
print('missing option', name) | |
bodyslide_elems.append(name) | |
# math time | |
value_new = value # -2 - +2 | |
value_new *= 25 # scale to -50 - +50 | |
value_new += 50 # shift to 0 - 100 | |
value_new = round(value_new) | |
print('{:10}\t{: 2.3f}\t{}'.format(name, value, value_new)) | |
# add to xml | |
slider = ET.SubElement(preset, 'SetSlider') | |
slider.attrib['name'] = name | |
slider.attrib['size'] = 'small' | |
slider.attrib['value'] = str(value_new) | |
# print(prettify(root)) | |
save_xml(file_name + '.xml', tree) | |
def diff_xml(file_a, file_b): | |
a = ET.ElementTree() | |
a.parse(file_a) | |
a_root = a.getroot() | |
a_preset = a_root.find('Preset') | |
b = ET.ElementTree() | |
b.parse(file_b) | |
b_root = b.getroot() | |
b_preset = b_root.find('Preset') | |
for entry in a_preset: | |
if entry.tag != 'SetSlider': continue | |
name = entry.attrib['name'] | |
if name not in bodyslide_elems: | |
print('missing option', name) | |
bodyslide_elems.append(name) | |
for entry in b_preset: | |
if entry.tag != 'SetSlider': continue | |
name = entry.attrib['name'] | |
if name not in bodyslide_elems: | |
print('missing option', name) | |
bodyslide_elems.append(name) | |
for name in bodyslide_elems: | |
a_entry = None | |
b_entry = None | |
for a_it in a_preset: | |
if a_it.tag != 'SetSlider': continue | |
if a_it.attrib['name'] == name and a_it.attrib['size'] == 'small': | |
a_entry = a_it | |
for b_it in b_preset: | |
if b_it.tag != 'SetSlider': continue | |
if b_it.attrib['name'] == name and b_it.attrib['size'] == 'small': | |
b_entry = b_it | |
if a_entry is None and b_entry is None: | |
continue | |
if a_entry is None: | |
a_entry = ET.Element('SetSlider') | |
a_entry.attrib['value'] = 0 | |
if b_entry is None: | |
b_entry = ET.Element('SetSlider') | |
b_entry.attrib['value'] = 0 | |
# print(name, a_entry.attrib['value'], b_entry.attrib['value']) | |
a_value = int(a_entry.attrib['value']) | |
b_value = int(b_entry.attrib['value']) | |
diff = abs(a_value - b_value) | |
print('{:15} {:5d}'.format(name, diff)) | |
if __name__ == "__main__": | |
# place <name>.jslot RaceMenu preset file in the same directory as this script. | |
# will generate <name>.xml which can be loaded by BodySlide Studio | |
convert_racemenu_2_bodyslide('Flun') | |
diff_xml('Flun.xml', 'Flun-manuell.xml') | |
See the comment:
# place .jslot RaceMenu preset file in the same directory as this script.
# will generate .xml which can be loaded by BodySlide Studio
Change the file name (Flun) to something else.
Also keep in mind that this is two years old, no idea if it still works or not 🤷♂️
(Of course you need to be able to use python)
Can you elaborate? Give an idiots guide and step by step to use this. Please and thank you. :)
How does one upload the json file into the directory?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how
do i use the code?