Skip to content

Instantly share code, notes, and snippets.

@SnowyMouse
Created February 1, 2020 05:34
Show Gist options
  • Save SnowyMouse/4860792940132174ad4a8d6801182498 to your computer and use it in GitHub Desktop.
Save SnowyMouse/4860792940132174ad4a8d6801182498 to your computer and use it in GitHub Desktop.
/*
custom-colors-unfuckerupper - Fixes change colors on object tags when
improperly extracted using older versions of Invader or the current stable
version of Refinery.
Copyright (c) Kavawuvi
This tool is licensed strictly under the GNU General Public License version
3. Read https://www.gnu.org/licenses/gpl-3.0.en.html for more information.
*/
#include <invader/tag/parser/parser.hpp>
#include <invader/file/file.hpp>
#include <invader/tag/hek/header.hpp>
#include <invader/printf.hpp>
template<typename T> T fix_meme_shit(const std::byte *what, std::size_t size, bool &necessary) {
auto x = T::parse_hek_tag_file(what, size);
necessary = false;
for(Invader::Parser::ObjectChangeColors &c : x.change_colors) {
// Obviously this only affects tags with multiple permutations
if(c.permutations.size() <= 1) {
continue;
}
float current_weight = 0.0F;
// See if we can detect it (each iteration is greater than or equal to the last, and it ends at 1.0)
// NOTE: This CAN detect tags that are specifically set like this, but it is unlikely and never occurs on Bungie tags, at least
for(auto &ccp : c.permutations) {
if(ccp.weight <= current_weight) {
current_weight = 0.0F;
break;
}
current_weight = ccp.weight;
}
if(current_weight != 1.0F) {
continue;
}
necessary = true;
// Fix it
double progress = 0.0;
for(auto &p : c.permutations) {
double difference = p.weight - progress;
progress = p.weight;
p.weight = static_cast<float>(difference);
}
}
return x;
}
int main(int argc, char **argv) {
if(argc != 3) {
NOPE:
eprintf("Usage: %s <r|w> <tag>\n", argv[0]);
return 1;
}
bool read_only;
switch(argv[1][0]) {
case 'r':
read_only = true;
break;
case 'w':
read_only = false;
break;
default:
goto NOPE;
}
try {
auto file = Invader::File::open_file(argv[2]).value();
auto *header = reinterpret_cast<Invader::HEK::TagFileHeader *>(file.data());
Invader::HEK::TagFileHeader::validate_header(header, file.size());
std::vector<std::byte> final_result;
bool necessary;
#define FIX_MEME_SHIT(classname, class_int) case Invader::HEK::TagClassInt::class_int: { \
final_result = fix_meme_shit<Invader::Parser::classname>(file.data(), file.size(), necessary).generate_hek_tag_data(Invader::HEK::TagClassInt::class_int); \
break; \
}
switch(header->tag_class_int) {
FIX_MEME_SHIT(Biped, TAG_CLASS_BIPED)
FIX_MEME_SHIT(DeviceControl, TAG_CLASS_DEVICE_CONTROL)
FIX_MEME_SHIT(Device, TAG_CLASS_DEVICE)
FIX_MEME_SHIT(Equipment, TAG_CLASS_EQUIPMENT)
FIX_MEME_SHIT(Garbage, TAG_CLASS_GARBAGE)
FIX_MEME_SHIT(Item, TAG_CLASS_ITEM)
FIX_MEME_SHIT(DeviceLightFixture, TAG_CLASS_DEVICE_LIGHT_FIXTURE)
FIX_MEME_SHIT(DeviceMachine, TAG_CLASS_DEVICE_MACHINE)
FIX_MEME_SHIT(Object, TAG_CLASS_OBJECT)
FIX_MEME_SHIT(Scenery, TAG_CLASS_SCENERY)
FIX_MEME_SHIT(Placeholder, TAG_CLASS_PLACEHOLDER)
FIX_MEME_SHIT(Unit, TAG_CLASS_UNIT)
FIX_MEME_SHIT(Vehicle, TAG_CLASS_VEHICLE)
FIX_MEME_SHIT(Weapon, TAG_CLASS_WEAPON)
FIX_MEME_SHIT(SoundScenery, TAG_CLASS_SOUND_SCENERY)
default:
return 2;
}
if(!necessary) {
return 3;
}
oprintf("%s\n", argv[2]);
if(!read_only) {
if(!Invader::File::save_file(argv[2], final_result)) {
eprintf_error("Failed to write %s\n", argv[2]);
}
}
return 0;
}
catch(std::exception &e) {
eprintf_error("Failed to fix %s: %s", argv[2], e.what());
return 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment