Showcase Mod

Developer API Overview

Integration APIs and development resources for extending Showcase mod

Developer API Overview

MC 1.21.1MC 1.21.2MC 1.21.4MC 1.21.5MC 1.21.6

Showcase provides comprehensive APIs for mod developers, plugin creators, and server administrators to integrate with and extend the mod's functionality.

Available APIs

Quick Start

Adding Showcase as Dependency

For Minecraft 1.21.6Auto-generated
repositories {
  maven {
      name = "Modrinth"
      url = "https://api.modrinth.com/maven"
  }
}

dependencies {
  // Showcase API
  modImplementation "maven.modrinth:showcase:2.3.1+mc1.21.6"

  // Optional: Include in mod
  include "maven.modrinth:showcase:2.3.1+mc1.21.6"
}
For Minecraft 1.21.6Auto-generated
<repositories>
  <repository>
      <id>modrinth</id>
      <name>Modrinth</name>
      <url>https://api.modrinth.com/maven</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
      <groupId>maven.modrinth</groupId>
      <artifactId>showcase</artifactId>
      <version>2.3.1+mc1.21.6</version>
  </dependency>
</dependencies>
{
  "depends": {
    "showcase": ">=2.3.0"
  },
  "suggests": {
    "showcase": "2.3.1"
  }
}

Basic API Usage

import com.showcase.api.ShowcaseAPI;
import com.showcase.api.data.ShareData;
import com.showcase.api.events.ShareCreateEvent;

public class ExampleIntegration {

    public void createItemShare(ServerPlayerEntity player) {
        // Get the Showcase API instance
        ShowcaseAPI api = ShowcaseAPI.getInstance();

        // Create a new item share
        ShareData share = api.createShare(
            player,
            ShareType.ITEM,
            Duration.ofMinutes(30),
            "My custom share"
        );

        // Share was created successfully
        if (share != null) {
            player.sendMessage(Text.literal("Share created: " + share.getId()));
        }
    }

    @EventHandler
    public void onShareCreate(ShareCreateEvent event) {
        // Listen to share creation events
        ServerPlayerEntity player = event.getPlayer();
        ShareData share = event.getShare();

        // Custom logic here
        System.out.println("Player " + player.getName() + " created share: " + share.getId());
    }
}

Core API Classes

ShowcaseAPI

The main entry point for all Showcase functionality:

public class ShowcaseAPI {
    // Get API instance
    public static ShowcaseAPI getInstance();

    // Share management
    public ShareData createShare(ServerPlayerEntity player, ShareType type, Duration duration, String description);
    public Optional<ShareData> getShare(String shareId);
    public List<ShareData> getPlayerShares(ServerPlayerEntity player);
    public boolean cancelShare(String shareId);

    // Permission checking
    public boolean hasPermission(ServerPlayerEntity player, String permission);
    public Set<String> getPlayerPermissions(ServerPlayerEntity player);

    // Configuration access
    public ShowcaseConfig getConfig();
    public void reloadConfig();

    // Statistics
    public PlayerStats getPlayerStats(ServerPlayerEntity player);
    public void updatePlayerStats(ServerPlayerEntity player);
}

ShareData

Represents a created share:

public class ShareData {
    public String getId();
    public ServerPlayerEntity getCreator();
    public ShareType getType();
    public Instant getCreatedAt();
    public Instant getExpiresAt();
    public String getDescription();
    public Set<UUID> getReceivers();
    public ItemStack[] getItems();  // For inventory shares
    public ItemStack getItem();     // For item shares
    public PlayerStats getStats();  // For stats shares

    // Utility methods
    public boolean isExpired();
    public boolean canView(ServerPlayerEntity player);
    public Duration getTimeRemaining();
}

ShareType Enum

public enum ShareType {
    ITEM,
    INVENTORY,
    HOTBAR,
    ENDERCHEST,
    CONTAINER,
    MERCHANT,
    STATS;

    // Utility methods
    public String getPermissionNode();
    public Duration getDefaultDuration();
    public boolean requiresContainer();
}

Event System

Available Events

All events are fired on the server thread and can be cancelled:

// Fired before a share is created
public class ShareCreateEvent extends Event implements Cancellable {
    public ServerPlayerEntity getPlayer();
    public ShareType getType();
    public Duration getDuration();
    public String getDescription();

    // Cancel the share creation
    public void setCancelled(boolean cancelled);
}

// Fired after a share is created
public class ShareCreatedEvent extends Event {
    public ShareData getShare();
    public ServerPlayerEntity getPlayer();
}

// Fired when a share is viewed
public class ShareViewEvent extends Event {
    public ShareData getShare();
    public ServerPlayerEntity getViewer();
    public boolean isFirstView();
}

// Fired when a share expires or is cancelled
public class ShareExpireEvent extends Event {
    public ShareData getShare();
    public ExpireReason getReason();  // EXPIRED, CANCELLED, REPLACED
}
// Fired when a player uses a chat keyword
public class ChatKeywordEvent extends Event implements Cancellable {
    public ServerPlayerEntity getPlayer();
    public String getKeyword();
    public String getOriginalMessage();
    public String getReplacementText();

    public void setReplacementText(String text);
}

// Fired when player statistics are collected
public class StatsCollectEvent extends Event {
    public ServerPlayerEntity getPlayer();
    public PlayerStats getStats();

    // Modify stats before sharing
    public void addCustomStat(String category, String key, Object value);
}
// Fired when configuration is reloaded
public class ConfigReloadEvent extends Event {
    public ShowcaseConfig getOldConfig();
    public ShowcaseConfig getNewConfig();
    public List<String> getChangedKeys();
}

// Fired during cleanup operations
public class CleanupEvent extends Event {
    public int getExpiredShares();
    public int getRemovedShares();
    public Duration getCleanupTime();
}

Event Registration

// In your mod initializer
public void onInitialize() {
    // Register event listeners
    ShowcaseAPI.getInstance().getEventBus().register(new MyEventHandler());
}

public class MyEventHandler {

    @EventHandler(priority = EventPriority.HIGH)
    public void onShareCreate(ShareCreateEvent event) {
        ServerPlayerEntity player = event.getPlayer();

        // Example: Prevent sharing in certain worlds
        if (player.getWorld().getRegistryKey().getValue().getPath().equals("spawn")) {
            event.setCancelled(true);
            player.sendMessage(Text.literal("Sharing is not allowed in spawn!"));
        }
    }

    @EventHandler
    public void onChatKeyword(ChatKeywordEvent event) {
        // Example: Custom keyword processing
        if (event.getKeyword().equals("custom")) {
            event.setReplacementText("§6[Custom Item]§r");
        }
    }
}

Configuration Integration

Accessing Configuration

ShowcaseConfig config = ShowcaseAPI.getInstance().getConfig();

// Get specific settings
Duration defaultDuration = config.getDefaultDuration(ShareType.ITEM);
boolean chatKeywordsEnabled = config.isChatKeywordsEnabled();
int maxSharesPerPlayer = config.getMaxSharesPerPlayer();

// Check feature availability
if (config.isShareTypeEnabled(ShareType.STATS)) {
    // Statistics sharing is enabled
}

Custom Configuration Sections

Add your own configuration sections:

// Register custom config section
ShowcaseAPI.getInstance().registerConfigSection("mymod", MyModConfig.class);

// Access custom config
MyModConfig myConfig = config.getSection("mymod", MyModConfig.class);

Data Storage Integration

Custom Data Providers

Implement custom storage backends:

public class MyDataProvider implements DataProvider {

    @Override
    public void saveShare(ShareData share) {
        // Custom save logic (e.g., to database)
    }

    @Override
    public Optional<ShareData> loadShare(String id) {
        // Custom load logic
        return Optional.empty();
    }

    @Override
    public List<ShareData> getPlayerShares(UUID playerId) {
        // Get shares for specific player
        return Collections.emptyList();
    }

    @Override
    public void cleanup() {
        // Remove expired shares
    }
}

// Register your provider
ShowcaseAPI.getInstance().registerDataProvider(new MyDataProvider());

Performance Considerations

Async Operations

Use async operations for expensive tasks:

// Async share creation
CompletableFuture<ShareData> future = ShowcaseAPI.getInstance()
    .createShareAsync(player, ShareType.STATS, duration, description);

future.thenAccept(share -> {
    // Handle result on main thread
    player.sendMessage(Text.literal("Stats share created!"));
});

Caching

Leverage Showcase's caching system:

// Cache custom data
ShowcaseAPI.getInstance().getCache().put("mykey", myData, Duration.ofMinutes(5));

// Retrieve cached data
Optional<MyData> cached = ShowcaseAPI.getInstance().getCache().get("mykey", MyData.class);

Example Integrations

Logging Integration

public class LoggingIntegration {

    public void registerEvents() {
        ShowcaseEvents.SHOWCASE_CREATED.register((sender, sourcePlayer, receivers, shareType, shareEntry, shareId, description, duration) -> {
            // Log share creation to server logs
            String message = String.format("Player %s created a %s share (ID: %s)",
                sender.getName().getString(),
                shareType.name().toLowerCase(),
                shareId);

            logShareActivity(message);
            return ActionResult.PASS;
        });
    }

    private void logShareActivity(String message) {
        // Log to file or database
        System.out.println("[Showcase] " + message);
    }
}

Economy Integration

public class EconomyIntegration {

    @EventHandler
    public void onShareCreate(ShareCreateEvent event) {
        ServerPlayerEntity player = event.getPlayer();
        ShareType type = event.getType();

        // Charge players for premium shares
        if (type == ShareType.STATS) {
            if (!hasBalance(player, 100)) {
                event.setCancelled(true);
                player.sendMessage(Text.literal("Insufficient funds!"));
            } else {
                withdrawMoney(player, 100);
            }
        }
    }
}

Statistics Integration

public class StatsIntegration {

    @EventHandler
    public void onStatsCollect(StatsCollectEvent event) {
        PlayerStats stats = event.getStats();
        ServerPlayerEntity player = event.getPlayer();

        // Add custom statistics
        event.addCustomStat("Economy", "Balance", getBalance(player));
        event.addCustomStat("Playtime", "Hours", getPlaytimeHours(player));
        event.addCustomStat("Custom", "My Stat", getMyCustomStat(player));
    }
}

Error Handling

Exception Types

// Showcase-specific exceptions
try {
    ShareData share = api.createShare(player, type, duration, description);
} catch (ShareCreationException e) {
    // Handle share creation failure
    logger.error("Failed to create share: " + e.getMessage());
} catch (PermissionException e) {
    // Handle permission issues
    player.sendMessage(Text.literal("No permission!"));
} catch (RateLimitException e) {
    // Handle rate limiting
    player.sendMessage(Text.literal("Please wait before sharing again"));
}

Best Practices

  1. Always check permissions before API calls
  2. Handle exceptions gracefully with user-friendly messages
  3. Use async operations for expensive tasks
  4. Cache frequently accessed data
  5. Register event handlers properly to avoid memory leaks
  6. Validate input data before processing

Migration and Compatibility

Version Compatibility

// Check Showcase version
String version = ShowcaseAPI.getInstance().getVersion();
if (Version.parse(version).isOlderThan("2.3.0")) {
    throw new UnsupportedOperationException("Showcase 2.3.0+ required");
}

API Deprecation

Monitor deprecation warnings and update code accordingly:

// Deprecated method (will be removed in 3.0)
@Deprecated(since = "2.3.0", forRemoval = true)
public void oldMethod() {
    // Use newMethod() instead
}