Register custom CatalogTypes

Hey,

I have a question, is it possible to register custom CatalogType’s from a Plugin using the GameRegistry?

Thanks, Feeliiix

As of Beta, yes!

You can use these methods to register your custom CatalogType class, and whatever implements it. Note that some of the classes are lacking javadocs - those are coming soon.

In the meantime, you might want to look at some of the implementation code (such as VisibilityRegistryModule) for some example usages.

1 Like

@Aaron1011 in which event should these methods called? PreInitialization?

Yes - it doen’t really matter, as long as you tell other plugins when to except your CatalogType to become available.

1 Like

Hmm I coded an example:


MessageStyle
[spoiler]

package com.feeliiix.fundamental.api.message.style;

import org.spongepowered.api.CatalogType;
import org.spongepowered.api.text.format.TextColor;
import org.spongepowered.api.text.format.TextStyle;
import org.spongepowered.api.util.annotation.CatalogedBy;

import java.util.List;
import java.util.Optional;

@CatalogedBy(MessageStyles.class)
public interface MessageStyle extends CatalogType {

    Optional<TextColor> getPrefixColor();

    Optional<List<TextStyle>> getPrefixStyle();

    Optional<TextColor> getTextColor();

    Optional<List<TextStyle>> getTextStyle();

}

[/spoiler]

MessageStyles

[spoiler]

package com.feeliiix.fundamental.api.message.style;

import org.spongepowered.api.text.format.TextColors;
import org.spongepowered.api.text.format.TextStyles;

/**
 * Represents a list of default {@link MessageStyle}'s
 */
public final class MessageStyles {

    /**
     * Represents an empty {@link MessageStyle}
     *
     * @see TextColors#NONE
     * @see TextStyles#NONE
     */
    public static final MessageStyle NONE = null;

    public static final MessageStyle NORMAL = null;
    public static final MessageStyle SUCCESS = null;
    public static final MessageStyle WARNING = null;
    public static final MessageStyle FAILURE = null;

    private MessageStyles() {}

}

[/spoiler]

MessageStyleRegistryModule THIS IS AN EXAMPLE NORMALY I NOT CREATE INSTANCES LIKE THIS:

[spoiler]

package com.feeliiix.fundamental.plugin.registry.module;

import static com.google.common.base.Preconditions.checkNotNull;

import com.feeliiix.fundamental.api.message.style.MessageStyle;
import com.feeliiix.fundamental.api.message.style.MessageStyles;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import org.spongepowered.api.registry.CatalogRegistryModule;
import org.spongepowered.api.registry.util.RegisterCatalog;
import org.spongepowered.api.text.format.TextColor;
import org.spongepowered.api.text.format.TextStyle;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public final class MessageStyleRegistryModule implements CatalogRegistryModule<MessageStyle> {

    @RegisterCatalog(MessageStyles.class)
    private static final Map<String, MessageStyle> messageStyleMappings = Maps.newHashMap();

    @Override
    public Optional<MessageStyle> getById(String id) {
        return Optional.ofNullable(messageStyleMappings.get(checkNotNull(id).toLowerCase()));
    }

    @Override
    public Collection<MessageStyle> getAll() {
        return ImmutableList.copyOf(messageStyleMappings.values());
    }

    @Override
    public void registerDefaults() {
        messageStyleMappings.put("none", new MessageStyle() {

        @Override public Optional<TextColor> getPrefixColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getPrefixStyle() {
            return Optional.empty();
        }

        @Override public Optional<TextColor> getTextColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getTextStyle() {
            return Optional.empty();
        }

        @Override public String getId() {
            return "none";
        }

        @Override public String getName() {
            return "none";
        }

    });

    messageStyleMappings.put("normal", new MessageStyle() {

        @Override public Optional<TextColor> getPrefixColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getPrefixStyle() {
            return Optional.empty();
        }

        @Override public Optional<TextColor> getTextColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getTextStyle() {
            return Optional.empty();
        }

        @Override public String getId() {
            return "normal";
        }

        @Override public String getName() {
            return "normal";
        }

    });

    messageStyleMappings.put("success", new MessageStyle() {

        @Override public Optional<TextColor> getPrefixColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getPrefixStyle() {
            return Optional.empty();
        }

        @Override public Optional<TextColor> getTextColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getTextStyle() {
            return Optional.empty();
        }

        @Override public String getId() {
            return "success";
        }

        @Override public String getName() {
            return "success";
        }

    });

    messageStyleMappings.put("warning", new MessageStyle() {

        @Override public Optional<TextColor> getPrefixColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getPrefixStyle() {
            return Optional.empty();
        }

        @Override public Optional<TextColor> getTextColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getTextStyle() {
            return Optional.empty();
        }

        @Override public String getId() {
            return "warning";
        }

        @Override public String getName() {
            return "warning";
        }

    });

    messageStyleMappings.put("failure", new MessageStyle() {

        @Override public Optional<TextColor> getPrefixColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getPrefixStyle() {
            return Optional.empty();
        }

        @Override public Optional<TextColor> getTextColor() {
            return Optional.empty();
        }

        @Override public Optional<List<TextStyle>> getTextStyle() {
            return Optional.empty();
        }

        @Override public String getId() {
            return "failure";
        }

        @Override public String getName() {
            return "failure";
        }

    });
}

[/spoiler]


Main Class

[spoiler]

package com.feeliiix.fundamental.plugin;

import com.feeliiix.fundamental.api.Fundamental;
import com.feeliiix.fundamental.api.configuration.hocon.HoconConfiguration;
import com.feeliiix.fundamental.api.message.style.MessageStyle;
import com.feeliiix.fundamental.api.message.style.MessageStyles;
import com.feeliiix.fundamental.plugin.configuration.MainConfiguration;
import com.feeliiix.fundamental.plugin.registry.module.MessageStyleRegistryModule;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GameInitializationEvent;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.item.inventory.Inventory;
import org.spongepowered.api.item.inventory.custom.CustomInventory;
import org.spongepowered.api.plugin.Plugin;

import java.nio.file.Path;

@Plugin(name = "Fundamentals", id = "Fundamentals", version = "0.1-SNAPSHOT")
public final class FundamentalPlugin implements Fundamental {

    private static Fundamental INSTANCE;

    @Inject private Logger logger;
    @Inject @ConfigDir(sharedRoot = false) private Path configDirectory;

    private HoconConfiguration mainConfiguration;

    @Listener
    public void onPreInitialization(GamePreInitializationEvent event) {

        INSTANCE = this;
    }

    @Listener
    public void onInitialization(GameInitializationEvent event) {
        Sponge.getRegistry().registerModule(MessageStyle.class, new MessageStyleRegistryModule());

        this.mainConfiguration = new MainConfiguration(this.configDirectory.resolve("config.conf"));

        this.logger.info(MessageStyles.FAILURE.getName());
    }

    public static Fundamental getInstance() {
        return INSTANCE;
    }

    @Override
    public Logger getLogger() {
        return this.logger;
    }

    public Path getConfigDirectory() {
        return this.configDirectory;
    }

    @Override
    public HoconConfiguration getMainConfiguration() {
        return this.mainConfiguration;
    }

}

[/spoiler]

And this throws an NullPointerExeption, so i think i make a mistake @Aaron1011

What is the stacktrace of the error you get?

@Deamon

[spoiler]


[18:02:55] [Server thread/ERROR] [Sponge]: Could not pass FMLInitializationEvent to Plugin{id=Fundamentals, name=Fundamentals, version=0.1-SNAPSHOT}
java.lang.NullPointerException
    at com.feeliiix.fundamental.plugin.FundamentalPlugin.onInitialization(FundamentalPlugin.java:45) ~[FundamentalPlugin.class:?]
    at org.spongepowered.common.event.listener.GameInitializationEventListener_FundamentalPlugin_onInitialization1.handle(Unknown Source) ~[?:?]
    at org.spongepowered.common.event.RegisteredListener.handle(RegisteredListener.java:86) ~[RegisteredListener.class:?]
    at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:233) [SpongeModEventManager.class:?]
    at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:277) [SpongeModEventManager.class:?]
    at org.spongepowered.mod.SpongeMod.onStateEvent(SpongeMod.java:164) [SpongeMod.class:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_65]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_65]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]
    at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
    at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
    at net.minecraftforge.fml.common.LoadController.sendEventToModContainer(LoadController.java:212) [LoadController.class:?]
    at net.minecraftforge.fml.common.LoadController.propogateStateMessage(LoadController.java:190) [LoadController.class:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_65]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_65]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]
    at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]
    at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
    at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
    at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
    at net.minecraftforge.fml.common.LoadController.onPost(LoadController.java:53) [LoadController.class:?]
    at net.minecraftforge.fml.common.LoadController.distributeStateMessage(LoadController.java:119) [LoadController.class:?]
    at net.minecraftforge.fml.common.Loader.initializeMods(Loader.java:731) [Loader.class:?]
    at net.minecraftforge.fml.server.FMLServerHandler.finishServerLoading(FMLServerHandler.java:97) [FMLServerHandler.class:?]
    at net.minecraftforge.fml.common.FMLCommonHandler.onServerStarted(FMLCommonHandler.java:360) [FMLCommonHandler.class:?]
    at net.minecraft.server.dedicated.DedicatedServer.startServer(DedicatedServer.java:213) [DedicatedServer.class:?]
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:500) [MinecraftServer.class:?]
    at java.lang.Thread.run(Thread.java:745) [?:1.8.0_65]

[/spoiler]

I wrote a simple example of how to use the new registry system. Note that due to the timing of plugin loading, it’s impossible for plugins to have registrations before pre-Initialization. Also, if you have defaults, I recommend at least making those constructed by default as you can have the guarantee that those are available.

1 Like

@gabizou

Hmm I tried it exactly like your example:

Main Class: http://pastebin.com/rHb3L5T2
MessageStyles: http://pastebin.com/3Z0qWPf8
MessageStyle: http://pastebin.com/KRVE1Ax9
MessageStyleRegistryModule: http://pastebin.com/nLTFDwEG

It should output that: “MessageStyles: MessageStyles…”,
but the list of MessageStyles getting by getAllOf() is empty.

Thanks for reviewing this,
Feeliiix

Fixed it. I need to add @DelayedRegistration(RegistrationPhase.INIT) to the registerDefaults method. Thanks to @Aaron1011