Last active
February 23, 2022 11:20
-
-
Save desht/f004324d5a6a5510e733ba8695c17e38 to your computer and use it in GitHub Desktop.
Convmodel.pl : rough & ready Perl script to convert MC 1.16 Java entity models to MC 1.17+ format
This file contains hidden or 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
#!/usr/bin/perl | |
# | |
# Usage: convmodel.pl < YourOldModel.java | |
# | |
# Looks for declarations & instatiations of ModelRenderer, then any calls to | |
# .setPos(), .addBox() etc. and converts those to MC 1.17+ equivalents | |
# | |
# Spits out a new constructor for your model class, and a static createBodyLayer() | |
# method suitable for using when you register your layer definitions in your | |
# EntityRenderersEvent.RegisterLayerDefinitions event listener | |
# Other methods in your model class (render/setupAnim/etc.) should not need to change much, if at all | |
# | |
# You'll also need to make a ModelLayers class containing all your model layer | |
# definitions - see https://github.com/TeamPneumatic/pnc-repressurized/blob/1.18.1/src/main/java/me/desht/pneumaticcraft/client/model/PNCModelLayers.java for an example. | |
# | |
use strict; | |
use String::CamelCase; | |
my $texW = 0; | |
my $texH = 0; | |
my %parts; | |
my @parts; | |
my $cls = "??"; | |
while (<>) { | |
next if /^\/\//; | |
if (/public class (\w+)/) { | |
$cls = $1; | |
} elsif (/texWidth = (\d+)/) { | |
$texW = $1; | |
} elsif (/texHeight = (\d+)/) { | |
$texH = $1; | |
} elsif (/private final Model(?:Part|Renderer)\s+(.+?);/) { | |
for my $part (split(/,\s*/, $1)) { | |
$parts{$part} = { varname => uc($1), boxes => [], texX => 0, texY => 0, rot => [ 0, 0, 0] }; | |
push(@parts, $part); | |
} | |
} elsif (/(\w+) = new Model(?:Part|Renderer)\((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)/) { | |
$texW = $2; | |
$texH = $3; | |
$parts{$1}{texX} = $4; | |
$parts{$1}{texY} = $5; | |
} elsif (/(\w+)\.setPos\((.+?)\)/) { | |
$parts{$1}{offset} = [ split(/,\s*/, $2) ]; | |
} elsif (/(\w+)\.addChild\((\w+)\)/) { | |
$parts{$2}{parent} = $1; | |
$parts{$1}{hasChildren} = "yes"; | |
} elsif (/(\w+)\.render\(/) { | |
$parts{$1}{render} = "yes"; | |
} elsif (/setRotation(?:Angle)?\((.+?)\)/) { | |
my @f = split(/,\s*/, $1); | |
$parts{$f[0]}{rot} = [ @f[1..3] ]; | |
} elsif (/(\w+)\.xRot = (.+?);/) { | |
$parts{$1}{rot}[0] = $2 | |
} elsif (/(\w+)\.yRot = (.+?);/) { | |
$parts{$1}{rot}[1] = $2 | |
} elsif (/(\w+)\.zRot = (.+?);/) { | |
$parts{$1}{rot}[2] = $2 | |
} elsif (/(\w+)\.texOffs\((\d+),\s*(\d+)\).addBox\((.+?)\)/) { | |
my $part = $1; | |
my $offX = $2; | |
my $offY = $3; | |
my @f = split(/,\s*/, $4); | |
$f[3] =~ s/\..*//; | |
$f[4] =~ s/\..*//; | |
$f[5] =~ s/\..*//; | |
my $n = scalar @{ $parts{$part}{boxes} }; | |
my @a = ("\"${part}_$n\"", @f[0..5]); | |
if (uc($f[6]) ne "0.0F") { | |
push(@a, "new CubeDeformation($f[6])"); | |
} | |
push(@a, $offX, $offY); | |
push(@{ $parts{$part}{boxes} }, join(", ", @a)); | |
if ($f[7] eq "true") { | |
$parts{$part}{mirror} = "yes"; | |
} | |
} elsif (/(\w+)\.addBox\((.+?)\)/) { | |
my $part = $1; | |
my @f = split(/,\s*/, $2); | |
$f[3] =~ s/\..*//; | |
$f[4] =~ s/\..*//; | |
$f[5] =~ s/\..*//; | |
#print STDERR "part = $part\n"; | |
my $n = scalar @{ $parts{$part}{boxes} }; | |
push(@{ $parts{$part}{boxes} }, join(", ", "\"${part}_$n\"", @f[0..5])); | |
} | |
} | |
for my $k (@parts) { | |
my $u = uc($k); | |
print "private static final String $u = \"$k\";\n"; | |
} | |
print "\n"; | |
my $layer_name = $cls; | |
$layer_name =~ s/^Render//; | |
$layer_name = String::CamelCase::decamelize($layer_name); | |
$layer_name = uc($layer_name); | |
# set up for using a BER. You can adjust this to take an EntityRendererProvider.Context for entity rendering... | |
print <<EOT; | |
public $cls(BlockEntityRendererProvider.Context ctx) { | |
super(ctx); | |
ModelPart root = ctx.bakeLayer(ModelLayers.$layer_name); | |
EOT | |
for my $k (@parts) { | |
if ($parts{$k}{render}) { | |
my $u = uc($k); | |
print " $k = root.getChild($u);\n"; | |
} | |
} | |
print "}\n\n"; | |
print <<EOT; | |
public static LayerDefinition createBodyLayer() { | |
MeshDefinition meshdefinition = new MeshDefinition(); | |
PartDefinition partdefinition = meshdefinition.getRoot(); | |
EOT | |
for my $k (@parts) { | |
my $part = $parts{$k}; | |
my $box = "\"$k\", " . join(", ", @{ $part->{boxes} }); | |
my $pose = "ZERO"; | |
if ($part->{offset} and ($part->{rot}[0] != 0 || $part->{rot}[1] != 0 || $part->{rot}[2] != 0)) { | |
$pose = "offsetAndRotation(" . join(", ", @{ $part->{offset} }) . ", " . join(", ", @{ $part->{rot} }) . ")"; | |
} elsif ($part->{rot}[0] != 0 || $part->{rot}[1] != 0 || $part->{rot}[2] != 0) { | |
$pose = "rotation(" . join(", ", @{ $part->{rot} }) . ")"; | |
} elsif ($part->{offset}) { | |
$pose = "offset(" . join(", ", @{ $part->{offset} }) . ")"; | |
} | |
my $var = $part->{hasChildren} ? "PartDefinition $k = " : ""; | |
my $parent = $part->{parent} ? $part->{parent} : "partdefinition"; | |
print " $var$parent.addOrReplaceChild($part->{varname}, CubeListBuilder.create().texOffs($part->{texX}, $part->{texY})"; | |
if (@{ $part->{boxes} }) { | |
print "\n ."; | |
print join("\n .", map { "addBox($_)" } @{ $part->{boxes} }); | |
if ($part->{mirror}) { | |
print "\n .mirror()"; | |
} | |
print ",\n"; | |
} else { | |
print ",\n"; | |
} | |
print " PartPose.$pose);\n"; | |
} | |
print "\n return LayerDefinition.create(meshdefinition, $texW, $texH);\n}\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment