XaeroExtended

Extension loader for Xaero's World Map and Xaero's Minimap- work in progress!

Extension Loader for Xaero's mods!

NOTE: THE MOD MAY BE PROBLEMATIC CURRENTLY, A FULL REWRITE IS COMING SOON

 

 

 

 

# XaeroExtended Extension Loader - Comprehensive Guide

## Table of Contents
1. [Overview](#overview)
2. [Installation](#installation)
3. [Extension Development Guide](#extension-development-guide)
4. [API Reference](#api-reference)
5. [Example Extensions](#example-extensions)
6. [Best Practices](#best-practices)
7. [Troubleshooting](#troubleshooting)

## Overview

XaeroExtended is a Fabric mod that provides an extension loader for Xaero's World Map and Minimap mods. It allows developers to create custom extensions that can interact with both mods without modifying their original code.

### Key Features
- **Plugin Architecture**: Load extensions from JAR files or Java source files
- **Dual Mod Support**: Extend both World Map and Minimap simultaneously
- **Hot Reloading**: Load/unload extensions without restarting Minecraft
- **Simple API**: Easy-to-use interfaces for extension development
- **Automatic Discovery**: Automatically detects extensions in the config folder

## Installation

### For End Users
1. **Install Required Mods**:
   - Fabric Loader 0.17.3+
   - Fabric API
   - Xaero's World Map
   - Xaero's Minimap  
   - XaeroExtended mod

2. **Setup Extension Directory**:
   The mod will automatically create:
   ```
   .minecraft/config/xaeroextended/extensions/
   ```

3. **Add Extensions**:
   Place extension JAR files or Java source files in the extensions directory

### For Developers
1. **Setup Development Environment**:
   ```bash
   git clone [your-xaeroextended-repo]
   cd xaeroextended
   ./build.sh
   ```

## Extension Development Guide

### Getting Started

#### Method 1: Simple Java File
1. Create a new Java file in the extensions directory:
   ```
   .minecraft/config/xaeroextended/extensions/MyExtension.java
   ```

2. Implement the extension interfaces:
   ```java
   import com.pgt.xaeroextended.extension.WorldMapExtension;
   import com.pgt.xaeroextended.extension.MinimapExtension;

   public class MyExtension implements WorldMapExtension, MinimapExtension {
       // Your implementation here
   }
   ```

#### Method 2: JAR File (Recommended for complex extensions)
1. Create a standard Java project
2. Include XaeroExtended API interfaces in your classpath
3. Package as JAR with proper manifest

### Core Concepts

#### Extension Lifecycle
1. **Discovery**: ExtensionManager scans the extensions directory
2. **Loading**: ClassLoader loads extension classes
3. **Initialization**: `onLoad()` method called
4. **Execution**: Event methods called during gameplay
5. **Cleanup**: `onUnload()` method called when mod stops

#### Thread Safety
- Extensions run on Minecraft's main thread
- Avoid long-running operations in event handlers
- Use separate threads for heavy computations

## API Reference

### Base Interface: `XaeroExtension`

All extensions must implement this interface:

```java
public interface XaeroExtension {
    /**
     * Called when the extension is loaded
     */
    void onLoad();

    /**
     * Called when the extension is unloaded
     */
    void onUnload();

    /**
     * @return The name of this extension
     */
    String getExtensionName();

    /**
     * @return The version of this extension
     */
    String getVersion();

    /**
     * @return The author of this extension
     */
    String getAuthor();
}
```

### World Map Extension: `WorldMapExtension`

```java
public interface WorldMapExtension extends XaeroExtension {
    /**
     * Called when the world map is initialized
     */
    default void onWorldMapInit() {}

    /**
     * Called when the world map is opened
     */
    default void onWorldMapOpen() {}

    /**
     * Called when the world map is closed
     */
    default void onWorldMapClose() {}

    /**
     * Called before rendering the world map
     */
    default void onWorldMapPreRender() {}

    /**
     * Called after rendering the world map
     */
    default void onWorldMapPostRender() {}

    /**
     * Called when a waypoint is added
     */
    default void onWaypointAdded(String name, int x, int y, int z) {}

    /**
     * Called when a waypoint is removed
     */
    default void onWaypointRemoved(String name) {}

    /**
     * Called when waypoints are loaded from file
     */
    default void onWaypointsLoaded() {}

    /**
     * Called when waypoints are saved to file
     */
    default void onWaypointsSaved() {}
}
```

### Minimap Extension: `MinimapExtension`

```java
public interface MinimapExtension extends XaeroExtension {
    /**
     * Called when the minimap is initialized
     */
    default void onMinimapInit() {}

    /**
     * Called before rendering the minimap
     */
    default void onMinimapPreRender() {}

    /**
     * Called after rendering the minimap
     */
    default void onMinimapPostRender() {}

    /**
     * Called when player position changes
     */
    default void onPlayerMove(double x, double y, double z) {}

    /**
     * Called when player changes dimension
     */
    default void onDimensionChange(String dimension) {}

    /**
     * Called when entity radar updates
     */
    default void onEntityRadarUpdate() {}

    /**
     * Called when cave mode toggles
     */
    default void onCaveModeToggle(boolean enabled) {}
}
```

## Example Extensions

### Example 1: Simple Logger Extension

**File**: `config/xaeroextended/extensions/DebugLogger.java`

```java
import com.pgt.xaeroextended.extension.WorldMapExtension;
import com.pgt.xaeroextended.extension.MinimapExtension;
import java.util.logging.Logger;

public class DebugLogger implements WorldMapExtension, MinimapExtension {
    private static final Logger LOGGER = Logger.getLogger("DebugLogger");
    private int mapOpens = 0;

    @Override
    public void onLoad() {
        LOGGER.info("DebugLogger extension loaded!");
    }

    @Override
    public void onUnload() {
        LOGGER.info("DebugLogger extension unloaded. Map was opened " + mapOpens + " times.");
    }

    @Override
    public String getExtensionName() {
        return "Debug Logger";
    }

    @Override
    public String getVersion() {
        return "1.0.0";
    }

    @Override
    public String getAuthor() {
        return "Example Author";
    }

    @Override
    public void onWorldMapOpen() {
        mapOpens++;
        LOGGER.info("World Map opened! Total opens: " + mapOpens);
    }

    @Override
    public void onPlayerMove(double x, double y, double z) {
        // Log player movement (throttled in real usage)
        LOGGER.fine("Player moved to: " + x + ", " + y + ", " + z);
    }
}
```

### Example 2: Waypoint Manager Extension

**File**: `config/xaeroextended/extensions/WaypointTracker.java`

```java
import com.pgt.xaeroextended.extension.WorldMapExtension;
import java.util.*;

public class WaypointTracker implements WorldMapExtension {
    private Map<String, Integer> waypointUsage = new HashMap<>();
    private List<String> waypointHistory = new ArrayList<>();

    @Override
    public void onLoad() {
        System.out.println("WaypointTracker loaded - ready to track waypoints!");
    }

    @Override
    public void onUnload() {
        System.out.println("WaypointTracker unloaded");
        System.out.println("Most used waypoint: " + getMostUsedWaypoint());
    }

    @Override
    public String getExtensionName() {
        return "Waypoint Tracker";
    }

    @Override
    public String getVersion() {
        return "1.1.0";
    }

    @Override
    public String getAuthor() {
        return "Waypoint Wizard";
    }

    @Override
    public void onWaypointAdded(String name, int x, int y, int z) {
        waypointUsage.put(name, 0);
        waypointHistory.add("Added: " + name + " at " + x + "," + y + "," + z);
        System.out.println("New waypoint: " + name);
    }

    @Override
    public void onWaypointRemoved(String name) {
        waypointUsage.remove(name);
        waypointHistory.add("Removed: " + name);
        System.out.println("Removed waypoint: " + name);
    }

    @Override
    public void onWorldMapOpen() {
        // Track waypoint usage when map is opened
        String lastWaypoint = waypointHistory.isEmpty() ? "none" : waypointHistory.get(waypointHistory.size() - 1);
        System.out.println("Map opened. Last waypoint action: " + lastWaypoint);
    }

    private String getMostUsedWaypoint() {
        return waypointUsage.entrySet().stream()
            .max(Map.Entry.comparingByValue())
            .map(entry -> entry.getKey() + " (" + entry.getValue() + " uses)")
            .orElse("No waypoints used");
    }
}
```

### Example 3: Advanced Minimap Enhancer

**File**: `config/xaeroextended/extensions/MinimapEnhancer.java`

```java
import com.pgt.xaeroextended.extension.MinimapExtension;

public class MinimapEnhancer implements MinimapExtension {
    private boolean enabled = true;
    private long lastMoveTime = 0;
    private double lastX, lastY, lastZ;

    @Override
    public void onLoad() {
        System.out.println("MinimapEnhancer loaded - enhancing your minimap experience!");
    }

    @Override
    public void onUnload() {
        System.out.println("MinimapEnhancer unloaded");
    }

    @Override
    public String getExtensionName() {
        return "Minimap Enhancer";
    }

    @Override
    public String getVersion() {
        return "2.0.0";
    }

    @Override
    public String getAuthor() {
        return "Map Master";
    }

    @Override
    public void onMinimapPreRender() {
        // Could add custom rendering logic here
        if (!enabled) return;
        
        // Example: Add custom overlays or modify rendering
        System.out.println("Rendering minimap with enhancements...");
    }

    @Override
    public void onPlayerMove(double x, double y, double z) {
        long currentTime = System.currentTimeMillis();
        
        // Throttle position updates (once per second)
        if (currentTime - lastMoveTime > 1000) {
            double distance = calculateDistance(x, y, z, lastX, lastY, lastZ);
            System.out.println("Player moved " + String.format("%.2f", distance) + " blocks");
            
            lastX = x;
            lastY = y;
            lastZ = z;
            lastMoveTime = currentTime;
        }
    }

    @Override
    public void onDimensionChange(String dimension) {
        System.out.println("Player changed dimension to: " + dimension);
        // Reset tracking when dimension changes
        lastMoveTime = 0;
    }

    private double calculateDistance(double x1, double y1, double z1, double x2, double y2, double z2) {
        double dx = x1 - x2;
        double dy = y1 - y2;
        double dz = z1 - z2;
        return Math.sqrt(dx * dx + dy * dy + dz * dz);
    }

    // Custom method to toggle features
    public void toggleEnhancements() {
        enabled = !enabled;
        System.out.println("Minimap enhancements " + (enabled ? "enabled" : "disabled"));
    }
}
```

## Advanced Development

### Creating JAR Extensions

For more complex extensions, create a proper JAR file:

1. **Project Structure**:
   ```
   MyExtension/
   ├── src/
   │   └── com/
   │       └── myname/
   │           └── myextension/
   │               └── MyExtension.java
   ├── lib/
   │   └── (dependencies if needed)
   └── build.sh
   ```

2. **Build Script** for JAR extensions:
   ```bash
   #!/bin/bash
   javac -cp ".:../../xaeroextended/libs/fabric-loader-0.17.3.jar" \
         -d build/classes \
         src/com/myname/myextension/*.java
   
   jar cf MyExtension.jar -C build/classes .
   echo "Built MyExtension.jar - place in config/xaeroextended/extensions/"
   ```

3. **Manifest File** (optional):
   ```
   Main-Class: com.myname.myextension.MyExtension
   XaeroExtended-Extension: true
   ```

### Configuration Management

Extensions can read/write configuration files:

```java
import java.io.*;
import java.util.Properties;

public class ConfigurableExtension implements WorldMapExtension {
    private Properties config = new Properties();
    private File configFile;

    @Override
    public void onLoad() {
        configFile = new File("config/xaeroextended/extensions/mymod.properties");
        loadConfig();
    }

    private void loadConfig() {
        try (InputStream input = new FileInputStream(configFile)) {
            config.load(input);
        } catch (IOException e) {
            // Create default config
            config.setProperty("enabled", "true");
            config.setProperty("debugMode", "false");
            saveConfig();
        }
    }

    private void saveConfig() {
        try (OutputStream output = new FileOutputStream(configFile)) {
            config.store(output, "MyExtension Configuration");
        } catch (IOException e) {
            System.err.println("Failed to save config: " + e.getMessage());
        }
    }

    public boolean isEnabled() {
        return "true".equals(config.getProperty("enabled", "true"));
    }
}
```

## Best Practices

### 1. Error Handling
```java
public class SafeExtension implements WorldMapExtension {
    @Override
    public void onWorldMapOpen() {
        try {
            // Your code here
        } catch (Exception e) {
            System.err.println("Error in onWorldMapOpen: " + e.getMessage());
            // Don't crash the entire mod!
        }
    }
}
```

### 2. Performance Optimization
```java
public class EfficientExtension implements MinimapExtension {
    private long lastUpdate = 0;
    private static final long UPDATE_INTERVAL = 1000; // 1 second
    
    @Override
    public void onPlayerMove(double x, double y, double z) {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastUpdate > UPDATE_INTERVAL) {
            // Expensive operation here
            processPlayerMove(x, y, z);
            lastUpdate = currentTime;
        }
    }
}
```

### 3. Memory Management
```java
public class MemorySafeExtension implements XaeroExtension {
    private List<String> data = new ArrayList<>();
    
    @Override
    public void onUnload() {
        // Clean up resources
        data.clear();
        data = null;
        System.gc(); // Suggest garbage collection
    }
}
```

### 4. Compatibility
```java
public class CompatibleExtension implements WorldMapExtension, MinimapExtension {
    private String mcVersion;
    
    @Override
    public void onLoad() {
        // Check Minecraft version for compatibility
        try {
            mcVersion = net.minecraft.client.MinecraftClient.getInstance().getGameVersion();
        } catch (Exception e) {
            // Graceful fallback
            mcVersion = "unknown";
        }
    }
}
```

## Troubleshooting

### Common Issues

1. **Extension not loading**:
   - Check file is in `config/xaeroextended/extensions/`
   - Verify class implements `XaeroExtension`
   - Check for compilation errors in console

2. **ClassNotFoundException**:
   - Ensure all dependencies are available
   - Check package declarations match file structure

3. **Performance issues**:
   - Avoid heavy operations in render methods
   - Use throttling for frequent events

4. **Memory leaks**:
   - Implement proper cleanup in `onUnload()`
   - Avoid static references to large objects

### Debugging Tips

1. **Enable debug logging**:
   ```java
   public class DebuggableExtension implements XaeroExtension {
       @Override
       public void onLoad() {
           System.out.println(getExtensionName() + " v" + getVersion() + " loaded!");
       }
   }
   ```

2. **Check extension loading**:
   - Look for "Loaded X extensions" in Minecraft logs
   - Check for any "Failed to load extension" messages

3. **Test in development**:
   - Use the provided `run-client.sh` script
   - Monitor console output for errors

### Support

- Check Minecraft logs in `.minecraft/logs/latest.log`
- Ensure all required mods are installed and compatible
- Verify Java version compatibility (Java 21+)

## Conclusion

XaeroExtended provides a powerful yet simple way to extend Xaero's mods functionality. By following this guide, you can create everything from simple logging extensions to complex minimap enhancements. Remember to test your extensions thoroughly and follow best practices for performance and compatibility.

Happy coding! 🎮

The XaeroExtended Team

profile avatar
  • 1
    Followers
  • 3
    Projects
  • 1.0K
    Downloads

More from TheRealPGT