Skip to content

Instantly share code, notes, and snippets.

@Commoble
Last active August 4, 2021 21:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Commoble/7b6fe26a2d7856172a8c47a091616c20 to your computer and use it in GitHub Desktop.
Save Commoble/7b6fe26a2d7856172a8c47a091616c20 to your computer and use it in GitHub Desktop.
RecordCodecBuilderBuilder
#usage:
#install python 3ish
#open cmd
#run `python.recordCodecBuilderBuilder.py`
#enter name of class, e.g. Thing
#enter fields one line at a time in the format
#FieldType field_name FieldType.CODEC
#java class is output to rcbb_Thing.txt
classTemplate = '''
public class ${class}
{
public static final Codec<${class}> CODEC = RecordCodecBuilder.create(instance -> instance.group(
${codecFields}
).apply(instance, ${class}::new));
${classFields}
public ${class}(${arguments})
{
${initializers}
}
}
'''
codecFieldTemplate = '${codec}.fieldOf("${jsonFieldName}").forGetter(${class}::${getterName})'
codecFieldSeparator = ',\n\t\t\t'
fieldTemplate = 'private final ${fieldType} ${fieldName};\tpublic ${fieldType} ${getterName}() { return this.${fieldName}; }'
fieldSeparator = '\n\t'
argumentTemplate = '${fieldType} ${fieldName}'
argumentSeparator = ', '
initializerTemplate = 'this.${fieldName} = ${fieldName};'
initializerSeparator = '\n\t\t'
class Field:
#fieldType is e.g. "ResourceLocation"
#jsonFieldName is e.g. "entity_type"
#(it's easier to convert from json convention to java convention than vice-versa)
#codecName is e.g. Codec.INT or ResourceLocation.CODEC (can be left blank, "")
def __init__(self, fieldType : str, jsonFieldName : str, codecName : str):
self.fieldType = fieldType
self.jsonFieldName = jsonFieldName
fieldWords = jsonFieldName.split('_')
javaFieldWords = [fieldWords[0]] + [x.capitalize() for x in fieldWords[1:]]
self.fieldName = "".join(javaFieldWords)
self.getterName = "get" + self.fieldName.capitalize()
self.codecName = codecName
def getCodecFieldString(self, className) -> str:
out = codecFieldTemplate
out = out.replace("${codec}", self.codecName)
out = out.replace("${jsonFieldName}", self.jsonFieldName)
out = out.replace("${class}", className)
out = out.replace("${getterName}", self.getterName)
return out
def getClassFieldString(self) -> str:
out = fieldTemplate
out = out.replace("${fieldType}", self.fieldType)
out = out.replace("${fieldName}", self.fieldName)
out = out.replace("${getterName}", self.getterName)
return out
def getArgumentString(self) -> str:
out = argumentTemplate
out = out.replace("${fieldType}", self.fieldType)
out = out.replace("${fieldName}", self.fieldName)
return out
def getInitializerString(self) -> str:
out = initializerTemplate
out = out.replace("${fieldName}", self.fieldName)
return out
# Gather input from user
className = input("Enter name of class, or press enter to exit: ")
if len(className) < 1:
exit
stillGettingInput = True
fields = []
print('''
Enter a field type, json-convention field name, and codec name,
e.g. ResourceLocation entity_type ResourceLocation.CODEC)
(codec can be omitted to fill in later)
Enter as many lines as you need and then enter a blank line to conclude
''')
while(stillGettingInput):
fieldInput = input()
fieldTuple = fieldInput.split(" ")
fieldTupleLength = len(fieldTuple)
if fieldTupleLength == 3:
fields.append(Field(fieldTuple[0], fieldTuple[1], fieldTuple[2]))
elif fieldTupleLength == 2:
fields.append(Field(fieldTuple[0], fieldTuple[1], "INSERT_CODEC_HERE"))
elif fieldTupleLength < 2:
stillGettingInput = False
else:
print("Invalid input, please try again or press enter to conclude")
codecFieldsString = codecFieldSeparator.join([f.getCodecFieldString(className) for f in fields])
classFieldsString = fieldSeparator.join([f.getClassFieldString() for f in fields])
argumentsString = argumentSeparator.join([f.getArgumentString() for f in fields])
initializersString = initializerSeparator.join([f.getInitializerString() for f in fields])
output = classTemplate
output = output.replace("${class}", className)
output = output.replace("${codecFields}", codecFieldsString)
output = output.replace("${classFields}", classFieldsString)
output = output.replace("${arguments}", argumentsString)
output = output.replace("${initializers}", initializersString)
outputPath = "rcbb_" + className + ".txt"
with open(outputPath, "w+") as f:
f.write(output)
print("Generated file at " + outputPath + " -- press enter to exit")
// example class generated from
// python recordCodecBuilderBuilder.py
// Thing
// ResourceLocation entity_type ResourceLocation.CODEC
// FieldType field_name FieldType.CODEC
public class Thing
{
public static final Codec<Thing> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ResourceLocation.CODEC.fieldOf("entity_type").forGetter(Thing::getEntitytype),
FieldType.CODEC.fieldOf("field_name").forGetter(Thing::getFieldname)
).apply(instance, Thing::new));
private final ResourceLocation entityType; public ResourceLocation getEntitytype() { return this.entityType; }
private final FieldType fieldName; public FieldType getFieldname() { return this.fieldName; }
public Thing(ResourceLocation entityType, FieldType fieldName)
{
this.entityType = entityType;
this.fieldName = fieldName;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment