Jump to content

[1.16.5] Help with ServerSided Configuration [SOLVED]


joelstoner

Recommended Posts

I know that the configs have something to do with ForgeConfigSpec, and ModConfig.

I am making a server sided mod, so GUI should only come into play if the user installs the mod on the client or singleplayer.

I just want a few simple configurations like enabled, length of time, message, and msg color.

I've spent about two days looking for examples to show me how configurations are done, but they all seem to be client sided.

I don't expect to be spoon fed, I just need to be pointed in the right direction. How to read the config values, and how to save them?

Link to comment
Share on other sites

  • joelstoner changed the title to [1.16.5] Help with ServerSided Configuration

[SOLVED]

So I did a config class, and registered it, and now I'm getting a NPE during loading a single player world.

This is the stacktrace provided in crash-reports

Spoiler

---- Minecraft Crash Report ----
// I bet Cylons wouldn't have this problem.

Time: 5/12/21, 7:15 PM
Description: Exception in server tick loop

java.lang.NullPointerException: Exception in server tick loop
    at net.minecraftforge.fml.config.ModConfig.setConfigData(ModConfig.java:86) ~[forge:?] {re:classloading}
    at net.minecraftforge.fml.config.ConfigTracker.openConfig(ConfigTracker.java:105) ~[forge:?] {re:classloading}
    at net.minecraftforge.fml.config.ConfigTracker.lambda$loadConfigs$1(ConfigTracker.java:83) ~[forge:?] {re:classloading}
    at java.lang.Iterable.forEach(Iterable.java:75) ~[?:?] {}
    at java.util.Collections$SynchronizedCollection.forEach(Collections.java:2067) ~[?:?] {}
    at net.minecraftforge.fml.config.ConfigTracker.loadConfigs(ConfigTracker.java:83) ~[forge:?] {re:classloading}
    at net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerAboutToStart(ServerLifecycleHooks.java:95) ~[forge:?] {re:classloading}
    at net.minecraft.server.integrated.IntegratedServer.init(IntegratedServer.java:62) ~[forge:?] {re:classloading,pl:runtimedistcleaner:A}
    at net.minecraft.server.MinecraftServer.func_240802_v_(MinecraftServer.java:643) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    at net.minecraft.server.MinecraftServer.lambda$startServer$0(MinecraftServer.java:233) ~[forge:?] {re:classloading,pl:accesstransformer:B}
    at java.lang.Thread.run(Thread.java:834) [?:?] {}


A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------

-- System Details --
Details:
    Minecraft Version: 1.16.5
    Minecraft Version ID: 1.16.5
    Operating System: Windows 7 (amd64) version 6.1
    Java Version: 11.0.9.1, AdoptOpenJDK
    Java VM Version: OpenJDK 64-Bit Server VM (mixed mode), AdoptOpenJDK
    Memory: 1437107200 bytes (1370 MB) / 3160408064 bytes (3014 MB) up to 8564768768 bytes (8168 MB)
    CPUs: 6
    JVM Flags: 1 total; -XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump
    ModLauncher: 8.0.9+86+master.3cf110c
    ModLauncher launch target: fmluserdevclient
    ModLauncher naming: mcp
    ModLauncher services:
        /mixin-0.8.2.jar mixin PLUGINSERVICE
        /eventbus-4.0.0.jar eventbus PLUGINSERVICE
        /forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.5-launcher.jar object_holder_definalize PLUGINSERVICE
        /forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.5-launcher.jar runtime_enum_extender PLUGINSERVICE
        /forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.5-launcher.jar capability_inject_definalize PLUGINSERVICE
        /accesstransformers-3.0.1.jar accesstransformer PLUGINSERVICE
        /forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.5-launcher.jar runtimedistcleaner PLUGINSERVICE
        /mixin-0.8.2.jar mixin TRANSFORMATIONSERVICE
        /forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.5-launcher.jar fml TRANSFORMATIONSERVICE
    FML: 36.1
    Forge: net.minecraftforge:36.1.0
    FML Language Providers:
        javafml@36.1
        minecraft@1
    Mod List:
        client-extra.jar                                  |Minecraft                     |minecraft                     |1.16.5              |DONE      |a1:d4:5e:04:4f:d3:d6:e0:7b:37:97:cf:77:b0:de:ad:4a:47:ce:8c:96:49:5f:0a:cf:8c:ae:b2:6d:4b:8a:3f
        main                                              |Single Player Sleep Mod       |singleplayersleepmod          |1.16.5_1.0.1        |DONE      |NOSIGNATURE
        forge-1.16.5-36.1.0_mapped_snapshot_20210309-1.16.|Forge                         |forge                         |36.1.0              |DONE      |NOSIGNATURE
    Crash Report UUID: 491f47b5-6fe8-4db7-894c-e0a7b7fc37f9
    Player Count: 0 / 8; []
    Data Packs: vanilla, mod:singleplayersleepmod, mod:forge
    Type: Integrated Server (map_client.txt)
    Is Modded: Definitely; Client brand changed to 'forge'

This is my config class

Spoiler



package com.github.joelgodofwar.sps.server.config;

import org.apache.commons.lang3.tuple.Pair;

import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.IntValue;

public class SPSConfig {
	
	/**
     * General configuration that doesn't need to be synchronized but needs to be available before server startup
     */
    public static class Common {
        public final ForgeConfigSpec.ConfigValue<? extends String> str_singleplayersleep_SleepMessage;
        public final BooleanValue bool_singleplayersleep_Enabled;
        public final IntValue int_singleplayersleep_SleepLength;

        Common(ForgeConfigSpec.Builder builder)
        {
            builder.comment("General configuration settings")
                    .push("general");

            str_singleplayersleep_SleepMessage = builder
                    .comment("Defines the sleep message to be displayed when a player sleeps.",
                             "%1$s is a placeholder for the sleeping player's name.")
                    .translation("singleplayersleep.config.sleepmsg")
                    .define("str_singleplayersleep_SleepMessage", "%1$s went to bed. Sweet dreams!");

            bool_singleplayersleep_Enabled = builder
                    .comment("Enable or Disable this mod")
                    .translation("singleplayersleep.config.enabled")
                    .define("bool_singleplayersleep_Enabled", true);

            int_singleplayersleep_SleepLength = builder
                    .comment("Define the length of time to delay in ticks before changing the time.",
                    		"200(10 seconds) is default, as it is just over the vanilla length for single player.")
                    .translation("singleplayersleep.config.delay")
                    .defineInRange("int_singleplayersleep_SleepLength", 200, 0, Integer.MAX_VALUE);

            builder.pop();
        }

    }
    
    public static final ForgeConfigSpec commonSpec;
    public static final Common COMMON;
    static {
        final Pair<Common, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(Common::new);
        commonSpec = specPair.getRight();
        COMMON = specPair.getLeft();
    }
    
}

 

This is where I register the config

Spoiler



package com.github.joelgodofwar.sps;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.github.joelgodofwar.sps.server.config.SPSConfig;
import com.github.joelgodofwar.sps.server.events.InteractEventHandler;

import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

@Mod("singleplayersleepmod")
public class SinglePlayerSleepMod {
	
	// Directly reference a log4j logger.
    public static final Logger LOGGER = LogManager.getLogger();
    public static final String MOD_ID = "singleplayersleepmod";
    

    public SinglePlayerSleepMod() {
        // Register the setup method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        // Register the enqueueIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
        // Register the processIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
        // Register the doClientStuff method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
/** Also tried registering here first */
        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);
    }
    

    private void setup(final FMLCommonSetupEvent event){ // some preinit code
        LOGGER.info("SinglePlayerSleep Loading...");
        ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, null);
        
        //Config config = new Configuration(new File(event.getModConfigurationDirectory().getAbsolutePath() + "additional/path/to/your/config.cfg"));
    }

    private void enqueueIMC(final InterModEnqueueEvent event){ // Send InterModComms
        // some example code to dispatch IMC to another mod
        //InterModComms.sendTo("examplemod", "helloworld", () -> { LOGGER.info("Hello world from the MDK"); return "Hello world";});
    }

    private void processIMC(final InterModProcessEvent event){ // Receive InterModComms
        // some example code to receive and process InterModComms from other mods
        //LOGGER.info("Got IMC {}", event.getIMCStream().
        //        map(m->m.getMessageSupplier().get()).
        //        collect(Collectors.toList()));
    }

    @SuppressWarnings("resource")
	private void doClientStuff(final FMLClientSetupEvent event) { // Client side stuff
        // do something that can only be done on the client
        //LOGGER.info("Got game settings {}", event.getMinecraftSupplier().get().options);
        
    }

    // You can use SubscribeEvent and let the Event Bus discover methods to call
    @SubscribeEvent
    public void onServerStarting(FMLServerStartingEvent event) {
        // do something when the server starts
        //LOGGER.info("HELLO from server starting");
    }
    @SubscribeEvent
    public void doServerStuff(final FMLServerStartedEvent  event) {
    	LOGGER.info("Registering Events...");
    	MinecraftForge.EVENT_BUS.register(new InteractEventHandler());
    	ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SPSConfig.commonSpec); /** Here */
    	LOGGER.info("Loading Complete.");
    }
}

 

This is my en_us.json

Spoiler



{
  "singleplayersleepmod.sleepmsg": "%1$s went to bed. Sweet dreams!",
  "singleplayersleep.config.sleepmsg": "Set the sleep message.",
  "singleplayersleep.config.enabled": "Set if SinglePlayerSleep is enabled.",
  "singleplayersleep.config.delay": "Set delay in ticks before time is changed."
  
}

 

More than likely it is something I am missing.

I found that this part under FMLCommonSetupEvent was the NPE issue, replacing it with my config register was the fix.

ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, null);

 

Edited by joelstoner
Solved issue.
Link to comment
Share on other sites

On 5/12/2021 at 3:20 AM, diesieben07 said:

Forge manages most of the saving for you, correct. I suggest you look at ForgeConfig for an example.

I'm having an issue where the server isn't saving a config toml for my mod, so that people can change the settings.

Here is my config class

Spoiler

package com.github.joelgodofwar.sps.common.config;

import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.IntValue;

import org.apache.commons.lang3.tuple.Pair;

public class Config {
    public static final ServerConfig SERVER;
    public static final ForgeConfigSpec SERVER_SPEC;

    static {
        final Pair<ServerConfig, ForgeConfigSpec> specPair = new ForgeConfigSpec.Builder().configure(ServerConfig::new);
        SERVER_SPEC = specPair.getRight();
        SERVER = specPair.getLeft();
    }
    
    public static String str_singleplayersleep_SleepMessage;//public final ForgeConfigSpec.ConfigValue<? extends String> str_singleplayersleep_SleepMessage;
    public static Boolean bool_singleplayersleep_Enabled;
    public static Integer int_singleplayersleep_SleepLength;
    
    public static void load() {
    	str_singleplayersleep_SleepMessage = SERVER.str_singleplayersleep_SleepMessage.get();
    	bool_singleplayersleep_Enabled = SERVER.bool_singleplayersleep_Enabled.get();
    	int_singleplayersleep_SleepLength = SERVER.int_singleplayersleep_SleepLength.get();
    }
    
    public static class ServerConfig {
    	public final ForgeConfigSpec.ConfigValue<String> str_singleplayersleep_SleepMessage;//public final ForgeConfigSpec.ConfigValue<? extends String> str_singleplayersleep_SleepMessage;
        public final BooleanValue bool_singleplayersleep_Enabled;
        public final IntValue int_singleplayersleep_SleepLength;
    		

    		
    	ServerConfig(final ForgeConfigSpec.Builder builder) {
            builder.comment("General configuration settings")
            .push("settings");

    		str_singleplayersleep_SleepMessage = builder
    		        .comment("Defines the sleep message to be displayed when a player sleeps.",
    		                 "%1$s is a placeholder for the sleeping player's name.")
    		        .translation("singleplayersleep.config.sleepmsg")
    		        .define("str_singleplayersleep_SleepMessage", "%1$s went to bed. Sweet dreams!");
    		
    		bool_singleplayersleep_Enabled = builder
    		        .comment("Enable or Disable this mod")
    		        .translation("singleplayersleep.config.enabled")
    		        .define("bool_singleplayersleep_Enabled", true);
    		
    		int_singleplayersleep_SleepLength = builder
    		        .comment("Define the length of time to delay in ticks before changing the time.",
    		        		"200(10 seconds) is default, as it is just over the vanilla length for single player.")
    		        .translation("singleplayersleep.config.delay")
    		        .defineInRange("int_singleplayersleep_SleepLength", 200, 0, Integer.MAX_VALUE);
    		
    		builder.pop();
    		
    	}
    }
}

 

The Config is registered as

ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, Config.SERVER_SPEC, "singleplayersleepmod-server.toml");

 

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

Where is this code located? This should work fine...

Spoiler

@Mod("singleplayersleepmod")
public class SinglePlayerSleepMod {
	
	// Directly reference a log4j logger.
    public static final Logger LOGGER = LogManager.getLogger();
    public static final String MOD_ID = "singleplayersleepmod";
    InteractEventHandler IEventHandler = new InteractEventHandler();

    public SinglePlayerSleepMod() {
        // Register the setup method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        // Register the enqueueIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
        // Register the processIMC method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
        // Register the doClientStuff method for modloading
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
        ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, Config.SERVER_SPEC, "singleplayersleepmod-server.toml");
        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);
    }

 

 

Link to comment
Share on other sites

13 hours ago, diesieben07 said:

Your repository is missing the Gradle wrapper, you should include it to keep builds consistent. Additionally, your code does not compile.

Sorry I was in a hurry and forgot to upload the new build.gradle, that branch was just for this, I'll add the wrapper to the main branch.

It should compile now. When I get the configs working I'll clean up the code, and remove the unused classes, etc.

Edited by joelstoner
Forgot something.
Link to comment
Share on other sites

19 minutes ago, diesieben07 said:

Note: Deleting files and committing does not remove those files from your Git repo!

Also: Your code still does not compile.

I just uploaded everything that is not the launch files or the run directory, would a compiled jar work for debugging this issue? I'm wondering if it's related to the String.

Link to comment
Share on other sites

  • joelstoner changed the title to [1.16.5] Help with ServerSided Configuration [SOLVED]

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.