// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.builtin.buildertools.objimport;

import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.builtin.buildertools.BlockColorIndex;
import java.io.IOException;
import com.hypixel.hytale.logger.HytaleLogger;
import java.util.logging.Level;
import com.hypixel.hytale.builtin.buildertools.utils.PasteToolUtil;
import com.hypixel.hytale.protocol.packets.interface_.Page;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection;
import java.util.Map;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin;
import com.hypixel.hytale.server.core.entity.entities.Player;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.Random;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import com.hypixel.hytale.server.core.ui.browser.FileBrowserEventData;
import com.hypixel.hytale.common.util.StringUtil;
import java.util.List;
import com.hypixel.hytale.server.core.ui.builder.EventData;
import com.hypixel.hytale.protocol.packets.interface_.CustomUIEventBindingType;
import com.hypixel.hytale.server.core.ui.LocalizableString;
import com.hypixel.hytale.server.core.ui.DropdownEntryInfo;
import java.util.ArrayList;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.ui.builder.UIEventBuilder;
import com.hypixel.hytale.server.core.ui.builder.UICommandBuilder;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.ui.browser.FileBrowserConfig;
import com.hypixel.hytale.protocol.packets.interface_.CustomPageLifetime;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.ui.browser.ServerFileBrowser;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.entity.entities.player.pages.InteractiveCustomUIPage;

public class ObjImportPage extends InteractiveCustomUIPage<PageData>
{
    private static final String DEFAULT_BLOCK = "Rock_Stone";
    private static final int DEFAULT_HEIGHT = 20;
    private static final int MIN_HEIGHT = 1;
    private static final int MAX_HEIGHT = 320;
    private static final float DEFAULT_SCALE = 1.0f;
    private static final float MIN_SCALE = 0.01f;
    private static final float MAX_SCALE = 100.0f;
    private static final String ASSET_PACK_SUB_PATH = "Server/Imports/Models";
    @Nonnull
    private String objPath;
    private int targetHeight;
    private boolean useScaleMode;
    private float scale;
    @Nonnull
    private String blockPattern;
    private boolean fillSolid;
    private boolean useMaterials;
    private boolean autoDetectTextures;
    @Nonnull
    private String originStr;
    @Nonnull
    private Origin origin;
    @Nonnull
    private String rotationStr;
    @Nonnull
    private MeshRotation rotation;
    @Nullable
    private String statusMessage;
    private boolean isError;
    private boolean isProcessing;
    private boolean showBrowser;
    @Nonnull
    private final ServerFileBrowser browser;
    private static final String[] AUTO_DETECT_SUFFIXES;
    private static final String[] AUTO_DETECT_EXTENSIONS;
    
    public ObjImportPage(@Nonnull final PlayerRef playerRef) {
        super(playerRef, CustomPageLifetime.CanDismiss, PageData.CODEC);
        this.objPath = "";
        this.targetHeight = 20;
        this.useScaleMode = false;
        this.scale = 1.0f;
        this.blockPattern = "Rock_Stone";
        this.fillSolid = true;
        this.useMaterials = true;
        this.autoDetectTextures = false;
        this.originStr = "bottom_center";
        this.origin = Origin.BOTTOM_CENTER;
        this.rotationStr = "y_up";
        this.rotation = MeshRotation.NONE;
        this.statusMessage = null;
        this.isError = false;
        this.isProcessing = false;
        this.showBrowser = false;
        final FileBrowserConfig config = FileBrowserConfig.builder().listElementId("#BrowserPage #FileList").searchInputId("#BrowserPage #SearchInput").currentPathId("#BrowserPage #CurrentPath").allowedExtensions(".obj").enableRootSelector(false).enableSearch(true).enableDirectoryNav(true).maxResults(50).assetPackMode(true, "Server/Imports/Models").build();
        this.browser = new ServerFileBrowser(config);
    }
    
    @Override
    public void build(@Nonnull final Ref<EntityStore> ref, @Nonnull final UICommandBuilder commandBuilder, @Nonnull final UIEventBuilder eventBuilder, @Nonnull final Store<EntityStore> store) {
        commandBuilder.append("Pages/ObjImportPage.ui");
        commandBuilder.set("#ObjPath #Input.Value", this.objPath);
        commandBuilder.set("#HeightInput #Input.Value", this.targetHeight);
        commandBuilder.set("#ScaleInput #Input.Value", this.scale);
        commandBuilder.set("#BlockPattern #Input.Value", this.blockPattern);
        commandBuilder.set("#FillModeCheckbox #CheckBox.Value", this.fillSolid);
        commandBuilder.set("#UseMaterialsCheckbox #CheckBox.Value", this.useMaterials);
        commandBuilder.set("#AutoDetectTexturesCheckbox #CheckBox.Value", this.autoDetectTextures);
        commandBuilder.set("#HeightInput.Visible", !this.useScaleMode);
        commandBuilder.set("#ScaleInput.Visible", this.useScaleMode);
        final List<DropdownEntryInfo> sizeModeEntries = new ArrayList<DropdownEntryInfo>();
        sizeModeEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.objImport.sizeMode.height"), "height"));
        sizeModeEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.objImport.sizeMode.scale"), "scale"));
        commandBuilder.set("#SizeModeInput #Input.Entries", sizeModeEntries);
        commandBuilder.set("#SizeModeInput #Input.Value", this.useScaleMode ? "scale" : "height");
        final List<DropdownEntryInfo> originEntries = new ArrayList<DropdownEntryInfo>();
        originEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.origin.bottom_front_left"), "bottom_front_left"));
        originEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.origin.bottom_center"), "bottom_center"));
        originEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.origin.center"), "center"));
        originEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.origin.top_center"), "top_center"));
        commandBuilder.set("#OriginInput #Input.Entries", originEntries);
        commandBuilder.set("#OriginInput #Input.Value", this.originStr);
        final List<DropdownEntryInfo> axisEntries = new ArrayList<DropdownEntryInfo>();
        axisEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.objImport.axis.yUp"), "y_up"));
        axisEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.objImport.axis.zUp"), "z_up"));
        axisEntries.add(new DropdownEntryInfo(LocalizableString.fromMessageId("server.customUI.objImport.axis.xUp"), "x_up"));
        commandBuilder.set("#RotationInput #Input.Entries", axisEntries);
        commandBuilder.set("#RotationInput #Input.Value", this.rotationStr);
        this.updateStatus(commandBuilder);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#ObjPath #Input", EventData.of("@ObjPath", "#ObjPath #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#HeightInput #Input", EventData.of("@Height", "#HeightInput #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#ScaleInput #Input", EventData.of("@Scale", "#ScaleInput #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#SizeModeInput #Input", EventData.of("SizeMode", "#SizeModeInput #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#BlockPattern #Input", EventData.of("@BlockPattern", "#BlockPattern #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#FillModeCheckbox #CheckBox", EventData.of("@FillSolid", "#FillModeCheckbox #CheckBox.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#UseMaterialsCheckbox #CheckBox", EventData.of("@UseMaterials", "#UseMaterialsCheckbox #CheckBox.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#AutoDetectTexturesCheckbox #CheckBox", EventData.of("@AutoDetectTextures", "#AutoDetectTexturesCheckbox #CheckBox.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#OriginInput #Input", EventData.of("@Origin", "#OriginInput #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.ValueChanged, "#RotationInput #Input", EventData.of("@Rotation", "#RotationInput #Input.Value"), false);
        eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ImportButton", EventData.of("Import", "true"));
        eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#ObjPath #BrowseButton", EventData.of("Browse", "true"));
        commandBuilder.set("#FormContainer.Visible", !this.showBrowser);
        commandBuilder.set("#BrowserPage.Visible", this.showBrowser);
        if (this.showBrowser) {
            this.buildBrowserPage(commandBuilder, eventBuilder);
        }
    }
    
    private void buildBrowserPage(@Nonnull final UICommandBuilder commandBuilder, @Nonnull final UIEventBuilder eventBuilder) {
        this.browser.buildSearchInput(commandBuilder, eventBuilder);
        this.browser.buildCurrentPath(commandBuilder);
        this.browser.buildFileList(commandBuilder, eventBuilder);
        eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#BrowserPage #SelectButton", EventData.of("BrowserSelect", "true"));
        eventBuilder.addEventBinding(CustomUIEventBindingType.Activating, "#BrowserPage #CancelButton", EventData.of("BrowserCancel", "true"));
    }
    
    private void updateStatus(@Nonnull final UICommandBuilder commandBuilder) {
        if (this.statusMessage != null) {
            commandBuilder.set("#StatusText.Text", this.statusMessage);
            commandBuilder.set("#StatusText.Visible", true);
            commandBuilder.set("#StatusText.Style.TextColor", this.isError ? "#e74c3c" : "#cfd8e3");
        }
        else {
            commandBuilder.set("#StatusText.Visible", false);
        }
    }
    
    private void setError(@Nonnull final String message) {
        this.statusMessage = message;
        this.isError = true;
        this.isProcessing = false;
        this.rebuild();
    }
    
    private void setStatus(@Nonnull final String message) {
        this.statusMessage = message;
        this.isError = false;
        this.rebuild();
    }
    
    @Override
    public void handleDataEvent(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, @Nonnull final PageData data) {
        if (data.browse != null && data.browse) {
            this.showBrowser = true;
            this.rebuild();
            return;
        }
        if (data.browserCancel != null && data.browserCancel) {
            this.showBrowser = false;
            this.rebuild();
            return;
        }
        if (data.browserSelect != null && data.browserSelect) {
            this.showBrowser = false;
            this.rebuild();
            return;
        }
        if (this.showBrowser && this.handleBrowserEvent(data)) {
            return;
        }
        boolean needsUpdate = false;
        if (data.objPath != null) {
            this.objPath = StringUtil.stripQuotes(data.objPath.trim());
            this.statusMessage = null;
            needsUpdate = true;
        }
        if (data.height != null) {
            this.targetHeight = Math.max(1, Math.min(320, data.height));
            needsUpdate = true;
        }
        if (data.scale != null) {
            this.scale = Math.max(0.01f, Math.min(100.0f, data.scale));
            needsUpdate = true;
        }
        if (data.sizeMode != null) {
            this.useScaleMode = "scale".equalsIgnoreCase(data.sizeMode);
            this.rebuild();
            return;
        }
        if (data.blockPattern != null) {
            this.blockPattern = data.blockPattern.trim();
            needsUpdate = true;
        }
        if (data.fillSolid != null) {
            this.fillSolid = data.fillSolid;
            needsUpdate = true;
        }
        if (data.useMaterials != null) {
            this.useMaterials = data.useMaterials;
            needsUpdate = true;
        }
        if (data.autoDetectTextures != null) {
            this.autoDetectTextures = data.autoDetectTextures;
            needsUpdate = true;
        }
        if (data.origin != null) {
            this.originStr = data.origin.trim().toLowerCase();
            final String originStr = this.originStr;
            this.origin = switch (originStr) {
                case "bottom_front_left" -> Origin.BOTTOM_FRONT_LEFT;
                case "center" -> Origin.CENTER;
                case "top_center" -> Origin.TOP_CENTER;
                default -> Origin.BOTTOM_CENTER;
            };
            needsUpdate = true;
        }
        if (data.rotation != null) {
            this.rotationStr = data.rotation.trim().toLowerCase();
            final String rotationStr = this.rotationStr;
            this.rotation = switch (rotationStr) {
                case "z_up" -> MeshRotation.Z_UP_TO_Y_UP;
                case "x_up" -> MeshRotation.X_UP_TO_Y_UP;
                default -> MeshRotation.NONE;
            };
            needsUpdate = true;
        }
        if (data.doImport != null && data.doImport && !this.isProcessing) {
            this.performImport(ref, store);
            return;
        }
        if (needsUpdate) {
            this.sendUpdate();
        }
    }
    
    private boolean handleBrowserEvent(@Nonnull final PageData data) {
        if (data.searchQuery != null) {
            this.browser.setSearchQuery(data.searchQuery.trim().toLowerCase());
            this.rebuildBrowser();
            return true;
        }
        if (data.file != null) {
            final String fileName = data.file;
            if ("..".equals(fileName)) {
                this.browser.navigateUp();
                this.rebuildBrowser();
                return true;
            }
            if (this.browser.handleEvent(FileBrowserEventData.file(fileName))) {
                this.rebuildBrowser();
                return true;
            }
            final String virtualPath = this.browser.getAssetPackCurrentPath().isEmpty() ? fileName : (this.browser.getAssetPackCurrentPath() + "/" + fileName);
            final Path resolvedPath = this.browser.resolveAssetPackPath(virtualPath);
            if (resolvedPath != null && Files.isRegularFile(resolvedPath, new LinkOption[0])) {
                this.objPath = resolvedPath.toString();
                this.showBrowser = false;
                this.rebuild();
                return true;
            }
        }
        if (data.searchResult != null) {
            final Path resolvedPath2 = this.browser.resolveAssetPackPath(data.searchResult);
            if (resolvedPath2 != null && Files.isRegularFile(resolvedPath2, new LinkOption[0])) {
                this.objPath = resolvedPath2.toString();
                this.showBrowser = false;
                this.rebuild();
                return true;
            }
        }
        return false;
    }
    
    private void rebuildBrowser() {
        final UICommandBuilder commandBuilder = new UICommandBuilder();
        final UIEventBuilder eventBuilder = new UIEventBuilder();
        this.browser.buildFileList(commandBuilder, eventBuilder);
        this.browser.buildCurrentPath(commandBuilder);
        this.sendUpdate(commandBuilder, eventBuilder, false);
    }
    
    @Nullable
    private List<WeightedBlock> parseBlockPattern(@Nonnull final String pattern) {
        final List<WeightedBlock> result = new ArrayList<WeightedBlock>();
        final String[] split;
        final String[] parts = split = pattern.split(",");
        for (String part : split) {
            part = part.trim();
            if (!part.isEmpty()) {
                int weight = 100;
                String blockName = part;
                final int pctIdx = part.indexOf(37);
                if (pctIdx > 0) {
                    try {
                        weight = Integer.parseInt(part.substring(0, pctIdx).trim());
                        blockName = part.substring(pctIdx + 1).trim();
                    }
                    catch (final NumberFormatException e) {
                        return null;
                    }
                }
                final int blockId = BlockType.getAssetMap().getIndex(blockName);
                if (blockId == Integer.MIN_VALUE) {
                    return null;
                }
                result.add(new WeightedBlock(blockId, weight));
            }
        }
        return result.isEmpty() ? null : result;
    }
    
    private int selectRandomBlock(@Nonnull final List<WeightedBlock> blocks, @Nonnull final Random random) {
        if (blocks.isEmpty()) {
            throw new IllegalStateException("Cannot select from empty blocks list");
        }
        if (blocks.size() == 1) {
            return blocks.get(0).blockId;
        }
        int totalWeight = 0;
        for (final WeightedBlock wb : blocks) {
            totalWeight += wb.weight;
        }
        if (totalWeight <= 0) {
            return blocks.get(0).blockId;
        }
        final int roll = random.nextInt(totalWeight);
        int cumulative = 0;
        for (final WeightedBlock wb2 : blocks) {
            cumulative += wb2.weight;
            if (roll < cumulative) {
                return wb2.blockId;
            }
        }
        return blocks.get(0).blockId;
    }
    
    private void performImport(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        if (this.objPath.isEmpty()) {
            this.setError("Please enter a path to an OBJ file");
            return;
        }
        final Path path = Paths.get(this.objPath, new String[0]);
        if (!Files.exists(path, new LinkOption[0])) {
            this.setError("File not found: " + this.objPath);
            return;
        }
        if (!this.objPath.toLowerCase().endsWith(".obj")) {
            this.setError("File must be a .obj file");
            return;
        }
        final List<WeightedBlock> blocks = this.parseBlockPattern(this.blockPattern);
        if (blocks == null) {
            this.setError("Invalid block pattern: " + this.blockPattern);
            return;
        }
        this.isProcessing = true;
        this.setStatus("Processing...");
        final Player playerComponent = store.getComponent(ref, Player.getComponentType());
        final PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType());
        if (playerComponent == null || playerRefComponent == null) {
            this.setError("Player not found");
            return;
        }
        final int finalHeight = this.targetHeight;
        final boolean finalUseScaleMode = this.useScaleMode;
        final float finalScale = this.scale;
        final String finalPath = this.objPath;
        final boolean finalFillSolid = this.fillSolid;
        final boolean finalUseMaterials = this.useMaterials;
        final boolean finalAutoDetectTextures = this.autoDetectTextures;
        final Origin finalOrigin = this.origin;
        final MeshRotation finalRotation = this.rotation;
        final List<WeightedBlock> finalBlocks = blocks;
        BuilderToolsPlugin.addToQueue(playerComponent, playerRefComponent, (r, builderState, componentAccessor) -> {
            try {
                final Path objFilePath = Paths.get(finalPath, new String[0]);
                final ObjParser.ObjMesh mesh = ObjParser.parse(objFilePath);
                switch (finalRotation.ordinal()) {
                    case 1: {
                        mesh.transformZUpToYUp();
                        break;
                    }
                    case 2: {
                        mesh.transformXUpToYUp();
                        break;
                    }
                }
                int computedHeight;
                if (finalUseScaleMode) {
                    final float[] bounds = mesh.getBounds();
                    final float meshHeight = bounds[4] - bounds[1];
                    computedHeight = Math.max(1, (int)Math.ceil(meshHeight * finalScale));
                }
                else {
                    computedHeight = finalHeight;
                }
                if (finalBlocks.isEmpty()) {
                    this.setError("No blocks available for import");
                }
                else {
                    final BlockColorIndex colorIndex = BuilderToolsPlugin.get().getBlockColorIndex();
                    final Map<String, BufferedImage> materialTextures = new HashMap<String, BufferedImage>();
                    final Map<String, Integer> materialToBlockId = new HashMap<String, Integer>();
                    int defaultBlockId = finalBlocks.get(0).blockId;
                    if (finalUseMaterials && mesh.mtlLib() != null) {
                        this.loadMaterialData(objFilePath, mesh, colorIndex, materialTextures, materialToBlockId, finalAutoDetectTextures);
                        if (!materialToBlockId.isEmpty()) {
                            defaultBlockId = materialToBlockId.values().iterator().next();
                        }
                    }
                    final boolean hasUvTextures = mesh.hasUvCoordinates() && !materialTextures.isEmpty();
                    final boolean preserveOrigin = finalOrigin == Origin.BOTTOM_FRONT_LEFT;
                    MeshVoxelizer.VoxelResult result;
                    if (hasUvTextures) {
                        result = MeshVoxelizer.voxelize(mesh, computedHeight, finalFillSolid, materialTextures, materialToBlockId, colorIndex, defaultBlockId, preserveOrigin);
                    }
                    else {
                        result = MeshVoxelizer.voxelize(mesh, computedHeight, finalFillSolid, null, materialToBlockId, colorIndex, defaultBlockId, preserveOrigin);
                    }
                    TextureSampler.clearCache();
                    int offsetX = 0;
                    int offsetY = 0;
                    int offsetZ = 0;
                    switch (finalOrigin.ordinal()) {
                        case 1: {
                            offsetX = -result.sizeX() / 2;
                            offsetZ = -result.sizeZ() / 2;
                            break;
                        }
                        case 2: {
                            offsetX = -result.sizeX() / 2;
                            offsetY = -result.sizeY() / 2;
                            offsetZ = -result.sizeZ() / 2;
                            break;
                        }
                        case 3: {
                            offsetX = -result.sizeX() / 2;
                            offsetY = -result.sizeY();
                            offsetZ = -result.sizeZ() / 2;
                            break;
                        }
                    }
                    final BlockSelection selection = new BlockSelection(result.countSolid(), 0);
                    selection.setPosition(0, 0, 0);
                    final Random random = new Random();
                    final boolean hasMaterialBlockIds = result.blockIds() != null;
                    for (int x = 0; x < result.sizeX(); ++x) {
                        for (int y = 0; y < result.sizeY(); ++y) {
                            for (int z = 0; z < result.sizeZ(); ++z) {
                                if (result.voxels()[x][y][z]) {
                                    int blockId;
                                    if (hasMaterialBlockIds) {
                                        blockId = result.getBlockId(x, y, z);
                                        if (blockId == 0) {
                                            blockId = this.selectRandomBlock(finalBlocks, random);
                                        }
                                    }
                                    else {
                                        blockId = this.selectRandomBlock(finalBlocks, random);
                                    }
                                    selection.addBlockAtLocalPos(x + offsetX, y + offsetY, z + offsetZ, blockId, 0, 0, 0);
                                }
                            }
                        }
                    }
                    selection.setSelectionArea(new Vector3i(offsetX, offsetY, offsetZ), new Vector3i(result.sizeX() - 1 + offsetX, result.sizeY() - 1 + offsetY, result.sizeZ() - 1 + offsetZ));
                    builderState.setSelection(selection);
                    builderState.sendSelectionToClient();
                    final int blockCount = result.countSolid();
                    final String textureInfo = hasUvTextures ? " (UV textured)" : "";
                    this.statusMessage = String.format("Success! %d blocks copied to clipboard (%dx%dx%d)%s", blockCount, result.sizeX(), result.sizeY(), result.sizeZ(), textureInfo);
                    this.isProcessing = false;
                    playerRefComponent.sendMessage(Message.translation("server.builderTools.objImport.success").param("count", blockCount).param("width", result.sizeX()).param("height", result.sizeY()).param("depth", result.sizeZ()));
                    playerComponent.getPageManager().setPage(r, store, Page.None);
                    PasteToolUtil.switchToPasteTool(playerComponent, playerRefComponent);
                }
            }
            catch (final ObjParser.ObjParseException e) {
                BuilderToolsPlugin.get().getLogger().at(Level.WARNING).log("OBJ parse error: %s", e.getMessage());
                this.setError("Parse error: " + e.getMessage());
            }
            catch (final IOException e2) {
                BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(e2).log("OBJ import IO error");
                this.setError("IO error: " + e2.getMessage());
            }
            catch (final Exception e3) {
                BuilderToolsPlugin.get().getLogger().at(Level.WARNING).withCause(e3).log("OBJ import error");
                this.setError("Error: " + e3.getMessage());
            }
        });
    }
    
    private void loadMaterialData(@Nonnull final Path objPath, @Nonnull final ObjParser.ObjMesh mesh, @Nonnull final BlockColorIndex colorIndex, @Nonnull final Map<String, BufferedImage> materialTextures, @Nonnull final Map<String, Integer> materialToBlockId, final boolean autoDetectTextures) throws IOException {
        if (mesh.mtlLib() == null) {
            return;
        }
        final Path mtlPath = objPath.getParent().resolve(mesh.mtlLib());
        if (!Files.exists(mtlPath, new LinkOption[0])) {
            return;
        }
        final Map<String, MtlParser.MtlMaterial> materials = MtlParser.parse(mtlPath);
        final Path textureDir = mtlPath.getParent();
        for (final Map.Entry<String, MtlParser.MtlMaterial> entry : materials.entrySet()) {
            final String materialName = entry.getKey();
            final MtlParser.MtlMaterial material = entry.getValue();
            String texturePath = material.diffuseTexturePath();
            if (texturePath == null && autoDetectTextures) {
                texturePath = findMatchingTexture(textureDir, materialName);
            }
            if (texturePath != null) {
                final Path resolvedPath = textureDir.resolve(texturePath);
                final BufferedImage texture = TextureSampler.loadTexture(resolvedPath);
                if (texture != null) {
                    materialTextures.put(materialName, texture);
                    final int[] avgColor = TextureSampler.getAverageColor(resolvedPath);
                    if (avgColor != null) {
                        final int blockId = colorIndex.findClosestBlock(avgColor[0], avgColor[1], avgColor[2]);
                        if (blockId <= 0) {
                            continue;
                        }
                        materialToBlockId.put(materialName, blockId);
                        continue;
                    }
                    continue;
                }
            }
            final int[] rgb = material.getDiffuseColorRGB();
            if (rgb != null) {
                final int blockId2 = colorIndex.findClosestBlock(rgb[0], rgb[1], rgb[2]);
                if (blockId2 <= 0) {
                    continue;
                }
                materialToBlockId.put(materialName, blockId2);
            }
        }
    }
    
    @Nullable
    private static String findMatchingTexture(@Nonnull final Path directory, @Nonnull final String materialName) {
        final String[] auto_DETECT_SUFFIXES = ObjImportPage.AUTO_DETECT_SUFFIXES;
        for (int length = auto_DETECT_SUFFIXES.length, i = 0; i < length; ++i) {
            final String suffix = auto_DETECT_SUFFIXES[i];
            final String[] auto_DETECT_EXTENSIONS = ObjImportPage.AUTO_DETECT_EXTENSIONS;
            for (int length2 = auto_DETECT_EXTENSIONS.length, j = 0; j < length2; ++j) {
                final String ext = auto_DETECT_EXTENSIONS[j];
                final String filename = materialName + suffix + ext;
                if (Files.exists(directory.resolve(filename), new LinkOption[0])) {
                    return filename;
                }
            }
        }
        return null;
    }
    
    static {
        AUTO_DETECT_SUFFIXES = new String[] { "", "_dif", "_diffuse" };
        AUTO_DETECT_EXTENSIONS = new String[] { ".png", ".jpg", ".jpeg" };
    }
    
    record WeightedBlock(int blockId, int weight) {}
    
    public enum Origin
    {
        BOTTOM_FRONT_LEFT, 
        BOTTOM_CENTER, 
        CENTER, 
        TOP_CENTER;
    }
    
    public enum MeshRotation
    {
        NONE, 
        Z_UP_TO_Y_UP, 
        X_UP_TO_Y_UP;
    }
    
    public static class PageData
    {
        static final String KEY_OBJ_PATH = "@ObjPath";
        static final String KEY_HEIGHT = "@Height";
        static final String KEY_SCALE = "@Scale";
        static final String KEY_SIZE_MODE = "SizeMode";
        static final String KEY_BLOCK_PATTERN = "@BlockPattern";
        static final String KEY_FILL_SOLID = "@FillSolid";
        static final String KEY_USE_MATERIALS = "@UseMaterials";
        static final String KEY_AUTO_DETECT_TEXTURES = "@AutoDetectTextures";
        static final String KEY_ORIGIN = "@Origin";
        static final String KEY_ROTATION = "@Rotation";
        static final String KEY_IMPORT = "Import";
        static final String KEY_BROWSE = "Browse";
        static final String KEY_BROWSER_SELECT = "BrowserSelect";
        static final String KEY_BROWSER_CANCEL = "BrowserCancel";
        public static final BuilderCodec<PageData> CODEC;
        @Nullable
        private String objPath;
        @Nullable
        private Integer height;
        @Nullable
        private Float scale;
        @Nullable
        private String sizeMode;
        @Nullable
        private String blockPattern;
        @Nullable
        private Boolean fillSolid;
        @Nullable
        private Boolean useMaterials;
        @Nullable
        private Boolean autoDetectTextures;
        @Nullable
        private String origin;
        @Nullable
        private String rotation;
        @Nullable
        private Boolean doImport;
        @Nullable
        private Boolean browse;
        @Nullable
        private Boolean browserSelect;
        @Nullable
        private Boolean browserCancel;
        @Nullable
        private String file;
        @Nullable
        private String searchQuery;
        @Nullable
        private String searchResult;
        
        static {
            // 
            // This method could not be decompiled.
            // 
            // Original Bytecode:
            // 
            //     2: invokedynamic   BootstrapMethod #0, get:()Ljava/util/function/Supplier;
            //     7: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    10: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    13: dup            
            //    14: ldc             "@ObjPath"
            //    16: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //    19: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    22: invokedynamic   BootstrapMethod #1, accept:()Ljava/util/function/BiConsumer;
            //    27: invokedynamic   BootstrapMethod #2, apply:()Ljava/util/function/Function;
            //    32: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    35: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    38: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    41: dup            
            //    42: ldc             "@Height"
            //    44: getstatic       com/hypixel/hytale/codec/Codec.INTEGER:Lcom/hypixel/hytale/codec/codecs/simple/IntegerCodec;
            //    47: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    50: invokedynamic   BootstrapMethod #3, accept:()Ljava/util/function/BiConsumer;
            //    55: invokedynamic   BootstrapMethod #4, apply:()Ljava/util/function/Function;
            //    60: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    63: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    66: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    69: dup            
            //    70: ldc             "@Scale"
            //    72: getstatic       com/hypixel/hytale/codec/Codec.FLOAT:Lcom/hypixel/hytale/codec/codecs/simple/FloatCodec;
            //    75: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    78: invokedynamic   BootstrapMethod #5, accept:()Ljava/util/function/BiConsumer;
            //    83: invokedynamic   BootstrapMethod #6, apply:()Ljava/util/function/Function;
            //    88: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    91: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    94: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    97: dup            
            //    98: ldc             "SizeMode"
            //   100: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   103: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   106: invokedynamic   BootstrapMethod #7, accept:()Ljava/util/function/BiConsumer;
            //   111: invokedynamic   BootstrapMethod #8, apply:()Ljava/util/function/Function;
            //   116: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   119: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   122: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   125: dup            
            //   126: ldc             "@BlockPattern"
            //   128: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   131: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   134: invokedynamic   BootstrapMethod #9, accept:()Ljava/util/function/BiConsumer;
            //   139: invokedynamic   BootstrapMethod #10, apply:()Ljava/util/function/Function;
            //   144: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   147: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   150: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   153: dup            
            //   154: ldc             "@FillSolid"
            //   156: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
            //   159: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   162: invokedynamic   BootstrapMethod #11, accept:()Ljava/util/function/BiConsumer;
            //   167: invokedynamic   BootstrapMethod #12, apply:()Ljava/util/function/Function;
            //   172: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   175: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   178: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   181: dup            
            //   182: ldc             "@UseMaterials"
            //   184: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
            //   187: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   190: invokedynamic   BootstrapMethod #13, accept:()Ljava/util/function/BiConsumer;
            //   195: invokedynamic   BootstrapMethod #14, apply:()Ljava/util/function/Function;
            //   200: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   203: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   206: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   209: dup            
            //   210: ldc             "@AutoDetectTextures"
            //   212: getstatic       com/hypixel/hytale/codec/Codec.BOOLEAN:Lcom/hypixel/hytale/codec/codecs/simple/BooleanCodec;
            //   215: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   218: invokedynamic   BootstrapMethod #15, accept:()Ljava/util/function/BiConsumer;
            //   223: invokedynamic   BootstrapMethod #16, apply:()Ljava/util/function/Function;
            //   228: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   231: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   234: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   237: dup            
            //   238: ldc             "@Origin"
            //   240: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   243: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   246: invokedynamic   BootstrapMethod #17, accept:()Ljava/util/function/BiConsumer;
            //   251: invokedynamic   BootstrapMethod #18, apply:()Ljava/util/function/Function;
            //   256: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   259: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   262: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   265: dup            
            //   266: ldc             "@Rotation"
            //   268: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   271: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   274: invokedynamic   BootstrapMethod #19, accept:()Ljava/util/function/BiConsumer;
            //   279: invokedynamic   BootstrapMethod #20, apply:()Ljava/util/function/Function;
            //   284: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   287: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   290: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   293: dup            
            //   294: ldc             "Import"
            //   296: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   299: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   302: invokedynamic   BootstrapMethod #21, accept:()Ljava/util/function/BiConsumer;
            //   307: invokedynamic   BootstrapMethod #22, apply:()Ljava/util/function/Function;
            //   312: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   315: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   318: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   321: dup            
            //   322: ldc             "Browse"
            //   324: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   327: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   330: invokedynamic   BootstrapMethod #23, accept:()Ljava/util/function/BiConsumer;
            //   335: invokedynamic   BootstrapMethod #24, apply:()Ljava/util/function/Function;
            //   340: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   343: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   346: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   349: dup            
            //   350: ldc             "BrowserSelect"
            //   352: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   355: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   358: invokedynamic   BootstrapMethod #25, accept:()Ljava/util/function/BiConsumer;
            //   363: invokedynamic   BootstrapMethod #26, apply:()Ljava/util/function/Function;
            //   368: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   371: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   374: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   377: dup            
            //   378: ldc             "BrowserCancel"
            //   380: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   383: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   386: invokedynamic   BootstrapMethod #27, accept:()Ljava/util/function/BiConsumer;
            //   391: invokedynamic   BootstrapMethod #28, apply:()Ljava/util/function/Function;
            //   396: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   399: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   402: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   405: dup            
            //   406: ldc             "File"
            //   408: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   411: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   414: invokedynamic   BootstrapMethod #29, accept:()Ljava/util/function/BiConsumer;
            //   419: invokedynamic   BootstrapMethod #30, apply:()Ljava/util/function/Function;
            //   424: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   427: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   430: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   433: dup            
            //   434: ldc             "@SearchQuery"
            //   436: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   439: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   442: invokedynamic   BootstrapMethod #31, accept:()Ljava/util/function/BiConsumer;
            //   447: invokedynamic   BootstrapMethod #32, apply:()Ljava/util/function/Function;
            //   452: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   455: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   458: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //   461: dup            
            //   462: ldc             "SearchResult"
            //   464: getstatic       com/hypixel/hytale/codec/Codec.STRING:Lcom/hypixel/hytale/codec/codecs/simple/StringCodec;
            //   467: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //   470: invokedynamic   BootstrapMethod #33, accept:()Ljava/util/function/BiConsumer;
            //   475: invokedynamic   BootstrapMethod #34, apply:()Ljava/util/function/Function;
            //   480: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.addField:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //   483: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //   486: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //   489: putstatic       com/hypixel/hytale/builtin/buildertools/objimport/ObjImportPage$PageData.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //   492: return         
            // 
            // The error that occurred was:
            // 
            // java.lang.UnsupportedOperationException: The requested operation is not supported.
            //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
            //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitClassType(TypeSubstitutionVisitor.java:267)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitClassType(TypeSubstitutionVisitor.java:25)
            //     at com.strobel.assembler.metadata.TypeDefinition.accept(TypeDefinition.java:189)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:324)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2586)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:790)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2689)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1083)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:667)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:373)
            //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:344)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:662)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
            //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
            //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
            //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
            // 
            throw new IllegalStateException("An error occurred while decompiling this method.");
        }
    }
}
