UNPKG

rl-loadout-lib

Version:

Load Rocket League assets into three.js

166 lines 7.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const binary_1 = require("./binary"); const model_1 = require("./model"); exports.CURRENT_LOADOUT_VERSION = 2; exports.SLOT_BODY = 0; // Body won't be applied when loading in BakkesMod, user must have it equipped exports.SLOT_SKIN = 1; exports.SLOT_WHEELS = 2; exports.SLOT_BOOST = 3; exports.SLOT_ANTENNA = 4; exports.SLOT_HAT = 5; exports.SLOT_PAINTFINISH = 7; exports.SLOT_PAINTFINISH_SECONDARY = 12; exports.SLOT_ENGINE_AUDIO = 13; exports.SLOT_SUPERSONIC_TRAIL = 14; exports.SLOT_GOALEXPLOSION = 15; /** * Encode a loadout into a string that can be loaded into bakkesmod's item mod. * @param loadout loadout to encode */ function encodeLoadout(loadout) { // Allocate buffer that's big enough const writer = new binary_1.BitBinaryWriter(10000); writer.writeNumber(exports.CURRENT_LOADOUT_VERSION, 6); // Write current version /* We write 18 empty bits here, because we determine size and CRC after writing the whole loadout but we still need to allocate this space in advance */ writer.writeNumber(0, 18); writer.writeBool(loadout.body.blueIsOrange); // Write blue == orange? writeLoadout(writer, loadout.body.blueLoadout); writer.writeBool(loadout.body.blueColor.shouldOverride); // Write override blue car colors or not if (loadout.body.blueColor.shouldOverride) { writeColor(writer, loadout.body.blueColor.primaryColors); writeColor(writer, loadout.body.blueColor.secondaryColors); } if (!loadout.body.blueIsOrange) { writeLoadout(writer, loadout.body.orangeLoadout); writer.writeBool(loadout.body.orangeColor.shouldOverride); // Write override orange car colors or not if (loadout.body.orangeColor.shouldOverride) { writeColor(writer, loadout.body.orangeColor.primaryColors); writeColor(writer, loadout.body.orangeColor.secondaryColors); } } const currentBit = writer.currentBit; // Save current location of writer // Calculate how many bytes are used const sizeInBytes = Math.floor(currentBit / 8) + (currentBit % 8 === 0 ? 0 : 1); writer.currentBit = 6; // Set writer to header (bit 6) writer.writeNumber(sizeInBytes, 10); // Write size writer.writeNumber(writer.calculateCrc(3, sizeInBytes), 8); // Write calculated CRC writer.currentBit = currentBit; return writer.toHex(); } exports.encodeLoadout = encodeLoadout; /** * Decode a bakkesmod item mod string. * @param loadoutString bakkes item mod string * @param verify if true, the string is verified and an error is thrown if the verification fails * @throws Error verification failed */ function decodeLoadout(loadoutString, verify = true) { const reader = new binary_1.BitBinaryReader(loadoutString); const loadout = new model_1.BMLoadout(); /* Reads header VERSION (6 bits) SIZE_IN_BYTES (10 bits) CRC (8 BITS) */ loadout.header.version = reader.readNumber(6); loadout.header.codeSize = reader.readNumber(10); loadout.header.crc = reader.readNumber(8); // Verification (can be skipped if you already know the code is correct) if (verify) { const stringSizeCalc = (Math.ceil(4 * loadout.header.codeSize / 3) + 3) & ~3; // Diff may be at most 4 (?) because of base64 padding, but we check > 6 because IDK if (Math.abs(stringSizeCalc - loadoutString.length) > 6) { throw Error('Invalid input string size!'); } // Verify CRC, aka check if user didn't mess with the input string to create invalid loadouts if (!reader.verifyCrc(loadout.header.crc, 3, loadout.header.codeSize)) { throw Error('Invalid input string! CRC check failed'); } } // At this point we know the input string is probably correct, time to parse the body loadout.body.blueIsOrange = reader.readBool(); // Read single bit indicating whether blue = orange loadout.body.blueLoadout = readItemsFromBuffer(reader); // Read loadout loadout.body.blueColor.shouldOverride = reader.readBool(); // Read whether custom colors is on if (loadout.body.blueColor.shouldOverride) { // Read rgb for primary colors (0-255) loadout.body.blueColor.primaryColors = readColorsFromBuffer(reader); // Read rgb for secondary colors (0-255) loadout.body.blueColor.secondaryColors = readColorsFromBuffer(reader); } if (loadout.body.blueIsOrange) { loadout.body.orangeLoadout = loadout.body.blueLoadout; } else { loadout.body.orangeLoadout = readItemsFromBuffer(reader); // Read loadout loadout.body.orangeColor.shouldOverride = reader.readBool(); // Read whether custom colors is on if (loadout.body.orangeColor.shouldOverride) { // Read rgb for primary colors (0-255) loadout.body.orangeColor.primaryColors = readColorsFromBuffer(reader); // Read rgb for secondary colors (0-255) loadout.body.orangeColor.secondaryColors = readColorsFromBuffer(reader); } } return loadout; } exports.decodeLoadout = decodeLoadout; function writeLoadout(writer, loadout) { // Save current position so we can write the length here later const amountStorePos = writer.currentBit; // Reserve 4 bits to write size later writer.writeNumber(0, 4); let loadoutSize = 0; for (const entry of loadout) { const opt = entry[1]; // In bakkesmod, when unequipping the productID gets set to 0 but doesn't // get removed, so we do this check here. if (opt.productId === 0) { continue; } loadoutSize++; writer.writeNumber(opt.slotIndex, 5); // Slot index, 5 bits so we get slot upto 31 writer.writeNumber(opt.productId, 13); // Item id, 13 bits so upto 8191 should be enough writer.writeBool(opt.paintIndex > 0); // Bool indicating whether item is paintable or not if (opt.paintIndex) { // If paintable writer.writeNumber(opt.paintIndex, 6); // 6 bits, allow upto 63 paints } } // Save current position of writer const amountStorePos2 = writer.currentBit; writer.currentBit = amountStorePos; // Write the size of the loadout to the spot we allocated earlier writer.writeNumber(loadoutSize, 4); // Gives us a max of 15 customizable slots per team writer.currentBit = amountStorePos2; // Set back reader to original position } function writeColor(writer, color) { writer.writeNumber(color.r, 8); writer.writeNumber(color.g, 8); writer.writeNumber(color.b, 8); } function readColorsFromBuffer(reader) { return { r: reader.readNumber(8), g: reader.readNumber(8), b: reader.readNumber(8) }; } function readItemsFromBuffer(reader) { const items = new Map(); const size = reader.readNumber(4); // Read the length of the item array for (let i = 0; i < size; i++) { const option = new model_1.BMItem(); option.slotIndex = reader.readNumber(5); // Read slot of item option.productId = reader.readNumber(13); // Read product ID const isPaintable = reader.readBool(); // Read whether item is paintable or not if (isPaintable) { option.paintIndex = reader.readNumber(6); // Read paint index } items.set(option.slotIndex, option); // Add item to loadout at its selected slot } return items; } //# sourceMappingURL=loadout.js.map