Skip to content

Instantly share code, notes, and snippets.

@Choonster
Created May 12, 2017 14:53
Show Gist options
  • Save Choonster/527498fc692840686c7dd899b240973c to your computer and use it in GitHub Desktop.
Save Choonster/527498fc692840686c7dd899b240973c to your computer and use it in GitHub Desktop.

Revisions

  1. Choonster created this gist May 12, 2017.
    120 changes: 120 additions & 0 deletions ExtractMinecraftAssets.lua
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,120 @@
    -- Extracts Minecraft's assets from the repository format used by the Mojang launcher and ForgeGradle into regular directories.
    -- Requires Lua 5.2+/LuaJIT, LuaJSON, Penlight and LuaFileSystem

    ---------------------
    -- Start of Config --
    ---------------------

    -- The location of the index JSON file
    local INDEX_FILE = [[C:\Users\USER\.gradle\caches\minecraft\assets\indexes\1.11.json]]

    -- The directory to extract the assets to
    local OUTPUT_DIR = [[C:\Users\USER\Documents\Minecraft\Mods\TestMod3\TestMod3_1.11.2\vanilla_assets]]

    -------------------
    -- End of Config --
    -------------------

    local json = require("json")
    local path = require("pl.path")
    local file = require("pl.file")
    local pretty = require("pl.pretty")

    --- Calls string.format and prints the result.
    local function printf(formatStr, ...)
    print(formatStr:format(...))
    end

    --- Formats a number with thousands comma separators.
    local function formatNumber(number)
    return pretty.number(number, "T")
    end

    --- Creates a directory, also creating any intermediate directories if they don't exist.
    -- @return true on success or nil, the directory that couldn't be created and an error message on failure
    local function mkdirs(directoryPath)
    local baseDirectory, thisDir = path.splitpath(directoryPath)

    if not path.isdir(baseDirectory) then -- If the base directory doesn't exist, try to create it
    local success, failedDirectory, errorMessage = mkdirs(baseDirectory)
    if not success then -- If creating the base directory fails, we can't create this directory
    return nil, failedDirectory, errorMessage
    end
    end

    local success, errorMessage = path.mkdir(directoryPath)
    if success then
    return true
    else
    return nil, directoryPath, errorMessage
    end
    end

    local function extractRepository(indexFilePath, outputDirPath)
    print("Extracting files from repository")
    printf("Index file: %s", indexFilePath)
    printf("Output dir: %s", outputDirPath)
    print("\n")

    local numSucceeded, numFailed, numSkipped = 0, 0, 0

    local function succeeded(...)
    numSucceeded = numSucceeded + 1
    printf(...)
    end

    local function failed(...)
    numFailed = numFailed + 1
    printf(...)
    end

    local function skipped(...)
    numSkipped = numSkipped + 1
    printf(...)
    end

    local index = json.decode(file.read(indexFilePath))

    local indexesDirPath = path.splitpath(indexFilePath)
    local objectsDirPath = path.join(indexesDirPath, "../objects")

    for filePath, fileData in pairs(index.objects) do
    local hash = fileData.hash
    local repositoryFilePath = path.join(hash:sub(1, 2), hash)
    local fullRepositoryFilePath = path.join(objectsDirPath, repositoryFilePath)

    filePath = path.normpath(filePath)
    local outputFilePath = path.join(outputDirPath, filePath)
    local outputSubDirPath = path.join(outputDirPath, (path.splitpath(filePath)))

    printf("Copying %s to %s...", repositoryFilePath, filePath)

    if not path.isdir(outputSubDirPath) then
    local success, failedDirectory, errorMessage = mkdirs(outputSubDirPath)
    if not success then
    failed("Failed to create directory %s: %s", failedDirectory, errorMessage)
    goto continue
    end
    end

    if path.exists(outputFilePath) then
    skipped("Skipping file as it already exists")
    else
    local success, errorMessage = file.copy(fullRepositoryFilePath, outputFilePath)
    if success then
    succeeded("Successfully copied file")
    else
    failed("Failed to copy file: %s", errorMessage)
    end
    end

    ::continue::

    print()
    end

    print()
    printf("Finished extracting %s files with %s successes, %s failures and %s skipped", formatNumber(numSucceeded + numFailed + numSkipped), formatNumber(numSucceeded), formatNumber(numFailed), formatNumber(numSkipped))
    end

    extractRepository(INDEX_FILE, OUTPUT_DIR)