Skip to content

Instantly share code, notes, and snippets.

@RobinMcCorkell
Last active August 29, 2015 14:01
Show Gist options
  • Save RobinMcCorkell/bd591324406f055f1a91 to your computer and use it in GitHub Desktop.
Save RobinMcCorkell/bd591324406f055f1a91 to your computer and use it in GitHub Desktop.
Minecraft Forge Spare ID Finder
#!/usr/bin/perl
# Copyright (C) 2014 Robin McCorkell <[email protected]>
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
use v5.10.1;
use strict;
use warnings;
use Getopt::Long;
use File::Find;
use Pod::Usage;
my $opt_help = 0;
my $opt_block = 0;
my $opt_item = 0;
my $dir;
my $print = 10;
my $opt_minID = 0;
GetOptions(
'block' => \$opt_block,
'item' => \$opt_item,
'config=s' => \$dir,
'print=i' => \$print,
'minid=i' => \$opt_minID,
'help|?' => \$opt_help)
or pod2usage(2);
pod2usage(1) if $opt_help;
pod2usage(1) unless $dir;
my @contextStrings;
my $minID;
my $maxID;
if ($opt_block) {
push(@contextStrings, "block", "camoblocks", '"block ids"');
$minID = 450;
$maxID = 4095;
} elsif ($opt_item) {
push(@contextStrings, "item", "camoitems", '"item ids"');
$minID = 3970;
$maxID = 65535;
} else {
pod2usage(1);
}
if ($opt_minID) {
$minID = $opt_minID;
}
sub chompy {
my ($ref) = @_;
$$ref =~ s/^\s+//;
$$ref =~ s/\s+$//;
}
sub loopDelims {
my ($fileName, $matchFunc, $iterFunc, $startFunc, $endFunc) = @_;
open(my $file, "<", $fileName);
my @contexts;
my $configFile = 0;
if(my $firstLine = $_ = <$file>) {
$iterFunc->(\@contexts) if $iterFunc;
chompy(\$firstLine);
if ($firstLine eq "# Configuration file") {
$configFile = 1;
}
}
while (<$file>) {
if ($configFile and not /^[[:space:]]*#/ and not /^[[:space:]]*$/) {
if (my ($context) = /^[[:space:]]*([^{]+?)[[:space:]]*{/) {
push(@contexts, $context);
$startFunc->(\@contexts) if $startFunc;
} elsif (@contexts) {
if (/}/) {
pop(@contexts);
$endFunc->(\@contexts) if $endFunc;
} else {
my $type = 0;
my $key = "";
my $valueRef;
if (/=/) {
($key, $$valueRef) = split(/=/);
chompy($valueRef);
} elsif (/</) {
$type = 1;
($key) = /(.*)</;
my @values;
while(my $listItem = <$file>) {
$_ .= $listItem;
if ($listItem =~ />/) {
last;
}
chompy(\$listItem);
push(@values, $listItem);
}
}
chompy(\$key);
$matchFunc->(\@contexts, $type, $key, $valueRef);
}
}
}
$iterFunc->(\@contexts) if $iterFunc;
}
close($file);
}
my %ids = map { $_ => 1 } ($minID..$maxID);
sub wanted {
return if -d;
loopDelims($_, sub {
my ($contextsRef, $type, $key, $valueRef) = @_;
if (@$contextsRef == 1 and $$contextsRef[0] ~~ @contextStrings and $type eq 0) {
if (exists($ids{$$valueRef})) {
delete $ids{$$valueRef};
} elsif ($$valueRef and $$valueRef >= $minID) {
print STDERR "WARN: Likely duplicate ID: " . $$valueRef . "\n";
}
}
});
}
find({ wanted => \&wanted, no_chdir => 1 }, $dir);
my @ids = sort {$a <=> $b} keys %ids;
print join("\n", @ids[0..$print - 1]) . "\n";
__END__
=head1 NAME
Minecraft Forge Spare ID Finder
=head1 SYNOPSIS
id-spare.pl [options] --config <dir>
=head1 OPTIONS
=over 8
=item B<--help>
Print a brief help message and exit
=item B<--block>
Search for spare block IDs
=item B<--item>
Search for spare item IDs
=item B<--config <dir>>
Path to config directory
=item B<--print <num>>
Print <num> spare IDs
=item B<--minid <num>>
Override minimum ID to <num>, set <num> to 0 to use default minimum ID
=back
=head1 DESCRIPTION
B<This program> searches for spare block or item IDs in the given config directory,
printing them on separate lines.
=head1 EXAMPLE
id-spare.pl --block --config $HOME/.technic/modpacks/bigdig/config --print 30
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment