Platform API
The Platform API provides a unified way to access platform-specific information and functionality across Fabric, Forge, and NeoForge. It abstracts away the differences between mod loaders, allowing you to write code that works consistently across all platforms.
Overview
The Platform API consists of several key components:
- Platform Class: Main utility class for platform information and environment detection
- ModInfo Interface: Provides information about loaded mods
- Environment Detection: Client/server environment detection
- Path Management: Cross-platform access to game directories
- Mod Discovery: Query loaded mods and their information
Platform Class
The main utility class for platform operations. All methods are static and work by calling the appropriate platform service behind the scenes.
Environment Detection
getEnvironment()
Gets the current runtime environment type.
public static Env getEnvironment()Returns:
Env.CLIENT- Running on the clientEnv.SERVER- Running on the dedicated server
isClient() / isServer()
Convenience methods for environment checking.
public static boolean isClient()
public static boolean isServer()Example:
public class ClientServerLogic {
public static void initialize() {
if (Platform.isClient()) {
// Initialize client-side features
setupClientRendering();
setupKeybinds();
} else {
// Initialize server-side features
setupServerLogic();
setupWorldGen();
}
// Common initialization
setupCommonFeatures();
}
}Platform Information
getPlatformName()
Gets the name of the current platform.
public static String getPlatformName()Returns: "Fabric", "Forge", or "NeoForge"
Platform Check Methods
public static boolean isFabric()
public static boolean isForge()
public static boolean isNeoForge()Example:
public class PlatformSpecificFeatures {
public static void registerFeatures() {
// Common features for all platforms
registerCommonFeatures();
// Platform-specific features
if (Platform.isFabric()) {
registerFabricFeatures();
} else if (Platform.isForge()) {
registerForgeFeatures();
} else if (Platform.isNeoForge()) {
registerNeoForgeFeatures();
}
}
private static void registerFabricFeatures() {
// Fabric-specific registrations
}
private static void registerForgeFeatures() {
// Forge-specific registrations
}
private static void registerNeoForgeFeatures() {
// NeoForge-specific registrations
}
}isDevelopmentEnvironment()
Checks if running in a development environment.
public static boolean isDevelopmentEnvironment()Example:
public class DevelopmentFeatures {
public static void setupFeatures() {
if (Platform.isDevelopmentEnvironment()) {
// Enable debug features
enableDebugLogging();
registerDebugCommands();
setupTestingHooks();
}
// Always enable in production
setupProductionFeatures();
}
private static void enableDebugLogging() {
// Enable verbose logging
Logger.getLogger("mymod").setLevel(Level.DEBUG);
}
private static void registerDebugCommands() {
// Register commands only available in development
}
}Path Management
The Platform API provides convenient access to common Minecraft directories.
Game Directory
public static Path getGameFolder()Returns the main Minecraft game directory (usually .minecraft).
Config Directory
public static Path getConfigFolder()Returns the config directory where mod settings are stored.
Specialized Directories
public static Path getModsFolder() // mods folder
public static Path getLogsFolder() // logs folder
public static Path getScreenshotsFolder() // screenshots folder
public static Path getResourcePacksFolder() // resourcepacks folder
public static Path getShaderPacksFolder() // shaderpacks folder
public static Path getSavesFolder() // saves folderExample:
public class PathManager {
public static void setupDirectories() {
Path configDir = Platform.getConfigFolder();
Path modConfigDir = configDir.resolve("mymod");
// Create mod-specific config directory
try {
Files.createDirectories(modConfigDir);
} catch (IOException e) {
Logger.getLogger("mymod").error("Failed to create config directory", e);
}
// Setup other paths
Path logFile = Platform.getLogsFolder().resolve("mymod.log");
Path screenshotDir = Platform.getScreenshotsFolder();
System.out.println("Config dir: " + modConfigDir);
System.out.println("Log file: " + logFile);
}
}Mod Discovery
isModLoaded(String modId)
Checks if a specific mod is currently loaded.
public static boolean isModLoaded(String id)getModInfo(String modId)
Gets information about a specific mod.
public static ModInfo getModInfo(String modId)getModIds()
Gets a collection of all loaded mod IDs.
public static Collection<String> getModIds()Convenience Methods
public static String getModVersion(String modId)
public static String getModName(String modId)
public static boolean isAnyModLoaded(String... modIds)
public static boolean areAllModsLoaded(String... modIds)Example:
public class ModCompatibility {
public static void checkDependencies() {
// Check required dependencies
if (!Platform.isModLoaded("amber")) {
throw new RuntimeException("Amber is required but not found!");
}
// Check optional dependencies
if (Platform.isModLoaded("jei")) {
System.out.println("JEI detected - enabling integration");
setupJEIIntegration();
}
if (Platform.isModLoaded("fabric-api")) {
System.out.println("Fabric API detected - enabling Fabric features");
setupFabricAPIFeatures();
}
// Check for alternative mods
if (Platform.isAnyModLoaded("jei", "rei", "emi")) {
System.out.println("Recipe viewer detected - enabling recipe integration");
setupRecipeIntegration();
}
// Log all loaded mods (debug)
if (Platform.isDevelopmentEnvironment()) {
System.out.println("Loaded mods: " + String.join(", ", Platform.getModIds()));
}
}
private static void setupJEIIntegration() {
// JEI-specific integration code
}
private static void setupFabricAPIFeatures() {
// Fabric API-specific features
}
private static void setupRecipeIntegration() {
// Recipe viewer integration
}
}ModInfo Interface
Provides information about a loaded mod.
public interface ModInfo {
String modId(); // The mod's unique identifier
String name(); // The mod's display name
String version(); // The mod's version
String description(); // The mod's description (may be empty)
}Example:
public class ModInfoExample {
public static void printModInfo(String modId) {
ModInfo info = Platform.getModInfo(modId);
if (info != null) {
System.out.println("Mod ID: " + info.modId());
System.out.println("Name: " + info.name());
System.out.println("Version: " + info.version());
System.out.println("Description: " + info.description());
} else {
System.out.println("Mod not found: " + modId);
}
}
public static void checkAmberVersion() {
ModInfo amberInfo = Platform.getModInfo("amber");
if (amberInfo != null) {
String version = amberInfo.version();
System.out.println("Using Amber version: " + version);
// Check for minimum version
if (compareVersions(version, "8.3.2") < 0) {
System.out.println("Warning: Amber version is too old!");
}
}
}
private static int compareVersions(String v1, String v2) {
// Simple version comparison logic
String[] parts1 = v1.split("\\.");
String[] parts2 = v2.split("\\.");
for (int i = 0; i < Math.min(parts1.length, parts2.length); i++) {
int num1 = Integer.parseInt(parts1[i]);
int num2 = Integer.parseInt(parts2[i]);
if (num1 != num2) {
return Integer.compare(num1, num2);
}
}
return Integer.compare(parts1.length, parts2.length);
}
}Advanced Usage
Conditional Feature Loading
public class ConditionalFeatures {
public static void loadFeatures() {
// Load based on platform
if (Platform.isFabric()) {
loadFabricFeatures();
} else if (Platform.isForge()) {
loadForgeFeatures();
} else if (Platform.isNeoForge()) {
loadNeoForgeFeatures();
}
// Load based on environment
if (Platform.isClient()) {
loadClientFeatures();
}
// Load based on available mods
if (Platform.isModLoaded("cloth-config")) {
loadClothConfigIntegration();
}
// Load based on development mode
if (Platform.isDevelopmentEnvironment()) {
loadDevelopmentFeatures();
}
}
private static void loadFabricFeatures() {
// Fabric-specific feature loading
}
private static void loadForgeFeatures() {
// Forge-specific feature loading
}
private static void loadNeoForgeFeatures() {
// NeoForge-specific feature loading
}
private static void loadClientFeatures() {
// Client-only features
}
private static void loadClothConfigIntegration() {
// Cloth Config integration
}
private static void loadDevelopmentFeatures() {
// Development-only features
}
}Configuration Management
public class PlatformConfig {
private static final Path CONFIG_DIR = Platform.getConfigFolder();
private static final Path MOD_CONFIG_DIR = CONFIG_DIR.resolve("mymod");
private static final Path CONFIG_FILE = MOD_CONFIG_DIR.resolve("config.json");
public static void loadConfig() {
try {
// Create directories if they don't exist
Files.createDirectories(MOD_CONFIG_DIR);
// Load configuration
if (Files.exists(CONFIG_FILE)) {
String content = Files.readString(CONFIG_FILE);
// Parse configuration
} else {
// Create default configuration
createDefaultConfig();
}
} catch (IOException e) {
Logger.getLogger("mymod").error("Failed to load configuration", e);
}
}
private static void createDefaultConfig() throws IOException {
String defaultConfig = """
{
"enabled": true,
"debugMode": false,
"features": {
"feature1": true,
"feature2": false
}
}
""";
Files.writeString(CONFIG_FILE, defaultConfig);
}
}Best Practices
- Always Check Environment: Use
isClient()andisServer()before accessing client/server-only code - Use Platform Abstraction: Avoid platform-specific APIs when possible
- Handle Missing Mods: Always check if optional mods are loaded before using them
- Development Detection: Use
isDevelopmentEnvironment()for debug features - Path Safety: Always ensure directories exist before writing files
- Version Compatibility: Check mod versions when integrating with other mods
Migration Guide
From Fabric Loader
// Old Fabric way
if (FabricLoader.getInstance().isModLoaded("jei")) {
// Do something
}
Path configDir = FabricLoader.getInstance().getConfigDir();
// New Amber way
if (Platform.isModLoaded("jei")) {
// Do something
}
Path configDir = Platform.getConfigFolder();From Forge
// Old Forge way
if (ModList.get().isLoaded("jei")) {
// Do something
}
Path configDir = FMLPaths.CONFIGDIR.get();
// New Amber way
if (Platform.isModLoaded("jei")) {
// Do something
}
Path configDir = Platform.getConfigFolder();The Platform API provides a consistent interface across all platforms, making your code more maintainable and portable.