Skip to main content

Overview

Stage 2 is the final loader stage that discovers, downloads, updates, and loads Essential and other compatible mods. It provides chain-loading capabilities, Jar-in-Jar (JiJ) dependency extraction, runtime mod remapping, and Mixin integration.

Core Components

EssentialLoaderBase

Abstract base class implementing the core loading logic for all platforms. Package: gg.essential.loader.stage2
public abstract class EssentialLoaderBase {
    public EssentialLoaderBase(Path gameDir, String gameVersion)
    public void load() throws IOException
    public void initialize()
    protected abstract void loadPlatform()
    protected abstract ClassLoader getModClassLoader()
    protected abstract void addToClasspath(Path path)
}
gameDir
Path
required
Game directory for mod storage and configuration
gameVersion
String
required
Minecraft version (e.g., “1.8.9”, “1.20.1”)

Key Methods

load()

Main entry point that discovers and loads all Essential-compatible mods.
public void load() throws IOException
Process Flow:
  1. Mod Discovery
    • Scans classpath for essential-loader.properties files
    • Loads mod metadata (ID, version, branch, pinned files)
    • Adds Essential mod entry if not explicitly declared
  2. Version Resolution
    • Checks local mod files and validates checksums
    • Fetches latest versions from API if needed
    • Applies pinned version constraints
    • Handles update prompts based on auto-update mode
  3. Download & Update
    • Downloads missing mods
    • Updates existing mods (via diff or full download)
    • Validates checksums after download
  4. Classpath Integration
    • Extracts Jar-in-Jar dependencies
    • Adds mod JARs to platform class loader
    • Registers mods with platform loader
  5. Mixin Loading
    • Registers Mixin configurations
    • Chain-loads Mixins for early class transformations
Storage Location:
{gameDir}/essential/
  ├── Essential (1.8.9).jar          # Essential mod (legacy location)
  └── mods/
      └── {publisher}_{mod}/
          ├── 1.20.1.jar             # Mod JAR file
          ├── 1.20.1.meta            # Version metadata
          ├── essential-loader.properties  # User config
          └── libraries/
              └── 1.20.1/            # Extracted JiJ dependencies

initialize()

Initializes loaded mods by calling their initialization entrypoints.
public void initialize()
Behavior:
  • Calls gg.essential.api.tweaker.EssentialTweaker.initialize(File) on each mod
  • Only runs if mod classes are successfully added to classpath

addToClasspath()

Platform-specific method to add mod JAR to the class loader.
protected abstract void addToClasspath(Path path)
path
Path
required
Path to JAR file to add to classpath
Platform Implementations:
@Override
protected void addToClasspath(Path path) {
    Launch.classLoader.addURL(path.toUri().toURL());
}

Mod Configuration

essential-loader.properties (Discovery)

Embedded in container JARs to declare Essential-compatible mods.
# Mod identification
publisherSlug=essential
publisherId=da30033d-5f3a-4de1-9d41-c96de919e071
modSlug=essential
modId=3ddb560e-c2e5-49a4-a0f0-a82748d7fbf7

# Display information
displayName=Essential

# Update channel
branch=stable

# Pinned version (optional)
pinnedFile=/essential-1.2.3.jar
pinnedFileMd5=abc123...
pinnedFileVersionId=version-id
pinnedFileVersion=1.2.3
publisherSlug
String
required
Publisher’s slug identifier
publisherId
String
required
Publisher’s UUID
modSlug
String
required
Mod’s slug identifier
modId
String
required
Mod’s UUID
displayName
String
required
Human-readable mod name
branch
String
default:"stable"
Default update branch
pinnedFile
String
Path to pinned mod JAR (resource path or URL)
pinnedFileMd5
String
MD5 checksum of pinned JAR
pinnedFileVersion
String
Version string of pinned JAR
pinnedFileVersionId
String
Version ID for API queries

User Configuration

Runtime configuration stored in the mod’s data directory.
# Auto-update mode
autoUpdate=true

# Update branch
branch=beta

# Advanced: Manual update tracking
overidePinnedVersion=1.3.0
pendingUpdateVersion=1.3.0
pendingUpdateResolution=true

Chain-Loading System

Mod Discovery

Stage 2 discovers mods by scanning for essential-loader.properties files on the classpath.
private List<Mod> findMods() {
    Enumeration<URL> urls = getClass()
        .getClassLoader()
        .getResources("essential-loader.properties");
    
    while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        Properties props = loadProperties(url);
        Mod mod = parseModMetadata(props);
        modList.add(mod);
    }
    return modList;
}

Version Resolution

For each discovered mod:
  1. Check for local JAR file and metadata
  2. Validate checksum to ensure integrity
  3. Check for pinned version in container JAR
  4. Fetch latest version from API
  5. Apply auto-update logic based on mode
  6. Download/update if necessary

Update Strategies

Diff Patching

Efficient UpdatesDownloads binary diff and patches existing JAR. Requires matching checksum.

Full Download

Fallback MethodDownloads complete JAR file when diff is unavailable or patching fails.
Diff Update Process:
private Path updateViaDiff(Mod mod, Path currentJar, 
                           ModJarMetadata current, ModJarMetadata latest) {
    // Verify current file matches expected checksum
    if (!Objects.equals(current.getChecksum(), 
                       getChecksum(currentJar))) {
        return null; // Checksum mismatch, use full download
    }
    
    // Fetch diff file
    FileMeta diff = fetchDiffUrl(latest.getMod(), 
                                 current.getVersion(), 
                                 latest.getVersion());
    if (diff == null) return null; // No diff available
    
    // Download and apply diff
    Path diffFile = downloadFile(diff);
    Path patchedFile = applyDiff(currentJar, diffFile);
    
    // Verify result
    if (!Objects.equals(latest.getChecksum(), 
                       getChecksum(patchedFile))) {
        throw new IOException("Checksum mismatch after patching");
    }
    
    return patchedFile;
}

Jar-in-Jar Extraction

Purpose

Essential mods can bundle dependencies as Jar-in-Jar to avoid version conflicts.

Extraction Process

private List<Path> extractJarsInJar(Mod mod, Path outerJar) {
    Path extractedJarsRoot = getExtractedJarsRoot(mod);
    List<Path> extractedJars = new ArrayList<>();
    
    try (FileSystem fs = FileSystems.newFileSystem(outerJar)) {
        Path innerJarsRoot = fs.getPath("META-INF", "jars");
        if (!Files.isDirectory(innerJarsRoot)) {
            return extractedJars; // No JiJ dependencies
        }
        
        for (Path innerJar : Files.list(innerJarsRoot)) {
            Path extractedJar = extractedJarsRoot
                .resolve(innerJar.getFileName().toString());
            
            if (!Files.exists(extractedJar)) {
                // Extract to temp, then atomic move
                Path tmpJar = Files.createTempFile(
                    extractedJarsRoot, "tmp", ".jar");
                Files.copy(innerJar, tmpJar, REPLACE_EXISTING);
                Files.move(tmpJar, extractedJar, ATOMIC_MOVE);
            }
            
            extractedJars.add(extractedJar);
        }
    }
    
    return extractedJars;
}
Storage Location:
{gameDir}/essential/mods/{mod}/libraries/{gameVersion}/
  ├── dependency-1.0.0.jar
  ├── dependency-2.0.0.jar
  └── ...

Platform Implementations

LaunchWrapper Platform

Class: gg.essential.loader.stage2.Loader LaunchWrapper uses a sophisticated chain-loading system with relaunch support.

Key Features

  • Jar Discovery: Scans LaunchWrapper sources for essential.mod.json
  • Version Resolution: Deduplicates and selects latest versions
  • Relaunch: Relaunches game with proper classpath order
  • MixinExtras: Extracts and prioritizes MixinExtras versions
public class Loader {
    public void loadAndRelaunch()
    private List<JarInfo> load(Collection<URL> sources)
    private void relaunch(List<JarInfo> jars)
}

essential.mod.json Format

{
  "schemaRevision": 0,
  "id": "publisher:mod",
  "version": "1.2.3",
  "jars": [
    {
      "file": "/path/to/dependency.jar",
      "id": "dependency:library",
      "version": "1.0.0"
    },
    {
      "builtin": "essential"
    },
    {
      "class": "com.example.DependencyResolver"
    }
  ]
}
schemaRevision
int
default:"0"
Schema version for future compatibility
id
String
required
Mod identifier (format: publisher:mod)
version
String
required
Mod version string
jars
Array
Array of dependency specifications:
  • file: Path to JAR (resource or absolute)
  • builtin: Built-in dependency name (e.g., “essential”)
  • class: Class name that provides dependencies

Fabric Platform

Class: gg.essential.loader.stage2.EssentialLoader Fabric integration with mod container registration and JiJ handling.

Key Features

  • JarInJarDependenciesHandler: Integrates with Fabric’s JiJ system
  • RuntimeModRemapper: Remaps mods to dev mappings in dev environment
  • Fake Mod Registration: Registers Essential as Fabric mod for Mod Menu
  • Mixin Chain-Loading: Reflects into Mixin internals if needed
public class EssentialLoader extends EssentialLoaderBase {
    @Override
    protected void addToClasspath(Path path)
    private void addFakeMod(Path path, URL url)
    private void chainLoadMixins()
}

Fabric JiJ Integration

@Override
protected void addToClasspath(Mod mod, ModJarMetadata jarMeta,
                              Path mainJar, List<Path> innerJars) {
    // Use Fabric's JiJ handler
    JarInJarDependenciesHandler jijHandler = 
        new JarInJarDependenciesHandler(getExtractedJarsRoot(mod));
    
    // Process all inner JARs
    innerJars = innerJars.stream()
        .flatMap(path -> jijHandler.loadMod(path).stream())
        .collect(Collectors.toList());
    
    // Check if restart is needed
    if (!jijHandler.complete()) {
        showRestartPrompt(jijHandler);
        return;
    }
    
    super.addToClasspath(mod, jarMeta, mainJar, innerJars);
}

ModLauncher Platform

Class: gg.essential.loader.stage2.EssentialLoader (dummy) + ActualEssentialLoader ModLauncher integration via transformation service and mod locator.

Key Features

  • Delayed Loading: Waits for MC version from ModLauncher
  • Mod Locator: Registers mods via EssentialModLocator
  • Descriptor Rewriting: Handles module descriptor transformations
  • Self-Renaming: Renames Essential to avoid Forge conflicts
public class EssentialLoader {
    private final EssentialTransformationService transformationService;
    
    public void load() {
        // Delayed until MC version available
    }
    
    public ITransformationService getTransformationService() {
        return transformationService;
    }
}

Mixin Integration

Configuration Loading

Stage 2 registers Mixin configurations from loaded mods.
for (String mixinConfig : metadata.getMixinConfigs(EnvType.CLIENT)) {
    Mixins.addConfiguration(mixinConfig);
}

Chain-Loading

Ensures Mixins are loaded even if third-party mods load MC classes early.
private void chainLoadMixins() throws ReflectiveOperationException {
    if (Mixins.getUnvisitedCount() == 0) {
        return; // Already chain-loaded
    }
    
    // Reflect into Mixin internals
    MixinEnvironment env = MixinEnvironment.getDefaultEnvironment();
    Object transformer = env.getActiveTransformer();
    Field processorField = transformer.getClass()
        .getDeclaredField("processor");
    processorField.setAccessible(true);
    Object processor = processorField.get(transformer);
    
    // Force Mixin to select configs
    Method select = processor.getClass()
        .getDeclaredMethod("select", MixinEnvironment.class);
    select.setAccessible(true);
    select.invoke(processor, env);
}

API Endpoints

Version Metadata

/v1/{publisher}:{mod}/versions/{branch}/platforms/{gameVersion}
Fetch latest mod version metadataResponse:
{
  "id": "version-uuid",
  "version": "1.2.3",
  "checksum": "abc123..."
}

Download URL

/v1/{publisher}:{mod}/versions/{version}/platforms/{gameVersion}/download
Fetch download URL for specific versionResponse:
{
  "url": "https://cdn.essential.gg/...",
  "checksum": "abc123..."
}

Diff Download

/v1/{publisher}:{mod}/versions/{oldVersion}/diff/{newVersion}/platforms/{gameVersion}
Fetch binary diff for updatingResponse:
{
  "url": "https://cdn.essential.gg/.../diff",
  "checksum": "def456..."
}

Changelog

/v1/{publisher}:{mod}/versions/{versionId}/changelog
Fetch changelog for update promptResponse:
{
  "summary": "New features and bug fixes..."
}

Stage 2 Version Requirements

Manifest Attribute

Mods can require minimum Stage 2 versions.
META-INF/MANIFEST.MF:
  Requires-Essential-Stage2-Version: 2.1.0

Upgrade Flow

When a mod requires newer Stage 2:
  1. Stage 2 detects requirement from manifest
  2. Configures Stage 1 to upgrade on next boot
  3. Shows restart prompt to user
  4. Game restarts with newer Stage 2

Error Handling

Warning: “Essential does not support the following game version: Behavior: Mod is skipped, loader continues with other mods
Error: “Downloaded mod file checksum did not match”Behavior: Downloaded file deleted, existing version used if available
Error: “Failed to add Essential jar to parent ClassLoader”Behavior: Loader attempts fallback methods, throws exception if all fail
UI: Restart prompt showing updated modsBehavior: Game exits cleanly, user must restart manually

Development & Testing

System Properties

# Enable debug logging
essential.debuglog=DEBUG

# Force Essential in dev environment
essential.loader.installEssentialMod=true

# Override API URL
essential.download.url=http://localhost:8080/mods

# Track relaunches
essential.loader.relaunched=true

# Integration testing
essential.integration_testing=true
essential.stage2.fallback-prompt-auto-answer=true

Mod ID Format

public class ModId {
    private final String publisherSlug;
    private final String publisherId;
    private final String modSlug;
    private final String modId;
    
    public String getFullSlug() {
        return publisherSlug + ":" + modSlug;
    }
}

See Also

Build docs developers (and LLMs) love