[Solvejd]How to loop through a list for Configuration

Hi So I’m back. After much sabatical and Have taken some of what @pie_flavor has discussed with me. (@pie_flavor hey if I’m missing something you already told me pleeeease let me know. I have a ‘bit’ better grasp lol).

Anyways now that he knows I’m alive and trying to better my coding…let the BUTCHERY BEGIN! :smiley:

So I have a config system…that loops through a lot of the same things…So I’m trying to take 1598 lines of code…and condense them using Wildcarding, lists. Or whatever anyone can recommend I do? pretty much i want the configuration to loop through a given list like below.

List list = Arrays.asList(“BLAZE”,“CAVE_SPIDER”,“CREEPER”,“ENDER_CRYSTAL”,“ENDERMAN”,“GHAST”,
“MAGMA_CUBE”,“PIG_ZOMBIE”,“SILVERFISH”,“SKELETON”,“SLIME”,“SPIDER”,“WITCH”,“ZOMBIE”,“NONE”);

and for it to use that to create a config that looks like below.

Natural Spawning
"Controls the Spawning Normalness"
    Zombie
        Week 1
            # of Attempts to Make: ####
            % of each Attempt: %%%%%
        Week 2
            # of Attempts to Make: ####
            % of each Attempt: %%%%%
    Witch
        Week 1
            # of Attempts to Make: ####
            % of each Attempt: %%%%%
        Week 2
            # of Attempts to Make: ####
            % of each Attempt: %%%%%

Here’s the code that I currently use. for the craetion
Here

Thank you

Nodes that have lists are handled through node#getList and node#getListChildren. The first of these returns a list of objects with the provided TypeToken, while the second returns List<? extends ConfigurationNode>.

It is my opinion that lists should only be used when it is necessary to represent an order of objects or there is no unique key that each object can be represented by. In your case, I would personally use a map for the mob types and a list for the weeks (and change around the keys a bit, but that’s up to you). In hocon, that would look like this.

mobs {
    zombie=[
        {
            attempts=1
            chance=50.0
        },{
            attempts=3
            chance=30.0
        }
    ]
    witch=[
        {
            attempts=2
            chance=60.0
        },{
            attempts=5
            chance=25.0
        }
    ]
}

CommentedConfigurationNode mobs;
List<CommentedConfigurationNode> weeks = mobs.getNode("zombie").getChildrenList();
for (int i = 0; i < weeks.size(); i++) {
    CommentedConfigurationNode week = weeks.get(i); //week # i + 1
    int attempts = week.getNode("attempts").getInt();
    double chance = week.getNode("chance").getDouble();
}
//Most would probably use a custom serializer for this, but that's not the point of this example.

One last note (if I’m correct in what I think you’re doing) - never create a config manually in code. Instead, use the AssetAPI.

1 Like

OMG! YES! So then what would look cleaner? and run better the Map for mobtypes? or the one you mentioned above using node#getList?

Having actually looked at the config file provided now… I would do whatever I possibly can to reduce the size of that - anything is clearly than hundreds of lines of stuff. I would look into Sponge#getRegistry#getAllOf, an example of which is shown here. Past that, whatever style or convention you use is your choice, though I would recommend sticking to conventions as they’ll be more familiar to the users.

Why not?

K so, I think mapping is the way I want to go…like map all the entities then loop through each and with each of them I want 5 weeks each… then # of attempts…all of that should be set to 0 by default. So could someone give me a snippet of how to map? or an example that I can find so that I can use the logic to ‘wild card’ the entire process? thanks.

@RandomByte Why.

But in all seriousness, manually calling and setting nodes for the pure purpose of instantiating default values is less performant and isn’t how Configurate is designed. It’s certainly a personal preference, but one I have for good reasons and I believe many others share.

@Cleardragonf
I’ll share the iteration of EntityTypes. From there, I leave it to you to connect the pieces together to get what you’re looking for. Myself and many of the other developers are happy to help with the more Sponge related topics, but you should also be doing a fair amount of experimenting yourself as it’s the only way you’ll really understand how everything works. If you haven’t been combing through the SpongeDocs, now is a good time to start.

CommentedConfigurationNode mobs;
for (EntityType type : Sponge.getRegistry().getAllOf(EntityType.class)) {
    CommentedConfigurationNode mob = mobs.getNode(type.getId());
    //Process each mob accordingly
}
//Note that the id will be formatted like minecraft:slime.

The code I provided above with getInt() and getDouble() defaults to 0. For more information on why and how to define your own defaults, see the configuration nodes docs here.

Simon, out. :studio_microphone:

1 Like

Oh, lol, didn’t expect thaaat much data, In this case you are right. But for other smaller things I prefer this.

2 Likes

YES! Ok! now i get it!!! I was trying to figure out why I’d use a registry…ok…so it contains a list of all Entity Types, because of the Getall of Entity Type.Class!hmm oik Now to write some parts of this to see how it’ll look! Thank you so much!!!

@Cleardragonf Word of warning on the EntityType iteration: you’ll get every entity type in Minecraft. This will include things like falling blocks, experience types and even players - things you most certainly don’t want to control the spawning of. You can see what the default Sponge/Minecraft entity types are here.

You will want to filter what you get back from the Sponge.getRegistry().getAllOf(EntityType.class) call - one way you could do it is check that the return type of EntityType#getEntityClass() returns whether it’s of type Animal or Monster.

1 Like

I was just thinking if blocks and such feel under those!!! thank you for the Quick REsponse! Now to figure out a way to filter :thinking: lol.

K…yea so here’s what I have so Far :smiley: now for the filter…

	 			String ConfigWeek = "WEEK " + DayCounter.getCustWeek();
					for (EntityType type : Sponge.getRegistry().getAllOf(EntityType.class)){
						config1.getNode("==========Natural Spawn==========", type, ConfigWeek, "# of Attempts:").getInt();
						config1.getNode("==========Natural Spawn==========", type, ConfigWeek, "% per Attempt:").getDouble();
					}

Try something like this:

        List<Class<? extends Entity>> classes = ImmutableList.of(
                Animal.class, Monster.class // add any interfaces you want to match against here
        );
        Collection<EntityType> cet = Sponge.getRegistry().getAllOf(EntityType.class).stream()
                // Match any classes that implement a class listed in "classes"
                .filter(x -> classes.stream().anyMatch(y -> y.isAssignableFrom(x.getEntityClass())))
                .collect(Collectors.toList());

        for (EntityType et : cet) {
            ///
        }

I suggested Animals and Monsters because from the context, I think that’s what you’re interested in controlling, you can see the entities that implement these by looking at the javadocs.

Make sure you know what this returns and how it works before using it!

2 Likes

hmmm…lol i see why you say taht because this is the first line i get :wink:

"SpongeEntityType{id=minecraft:blaze, name=blaze, translation=SpongeTranslation{id=entity.Blaze.name}, modid=minecraft, class=net.minecraft.entity.monster.EntityBlaze}" {

lol
…quick question while I have it on mind…would Mod Entities fall under the Registery? or is that Sponge side only and I’d have to add them manually?

Also…I notice things like Ghast, Enderdragon etc are missing…is this on purpose? and if so might I ask what Class they would fall under?

I see that the Ghast is suppose to be under the Monster.class…however when I generate my list for the Configuration. It’s not there…is this something that’s temporarily broke?

In case anyone wants to see this is what I eventually came up with thanks to all the help from everyone one this topic today :smiley:

public class NewConfigurationManager {
private static NewConfigurationManager instance = new NewConfigurationManager();

public static NewConfigurationManager getInstance(){
	return instance;
}
private File configDir;

//The Configuration Folder for this Plugin
public void NewConfigurationManger2(File configDir){
	this.configDir = configDir;
}

private ConfigurationLoader<CommentedConfigurationNode>configLoader1;

//the in memory version of the node comments
private CommentedConfigurationNode config1;
public void enable()
{
	File SpawnControl = new File(this.configDir, "Spawn Control.conf");
	
	this.configLoader1 = HoconConfigurationLoader.builder().setFile(SpawnControl).build();
	
	try{
		//create a new folder for HOBS config if it does not exist
		if(!this.configDir.isDirectory()){
			this.configDir.mkdirs();
		}

		//create a new file if the Spawn Control config does not exist
		if(!SpawnControl.isFile()){
			try{
				SpawnControl.createNewFile();				
				loadSpawnControl();
			        List<Class<? extends Entity>> classes = ImmutableList.of(
			                Animal.class, Monster.class // add any interfaces you want to match against here
			        );
			        Collection<EntityType> cet = Sponge.getRegistry().getAllOf(EntityType.class).stream()
			                // Match any classes that implement a class listed in "classes"
			                .filter(x -> classes.stream().anyMatch(y -> y.isAssignableFrom(x.getEntityClass())))
			                .collect(Collectors.toList());
			        //NEEDS WORK - Custom Drops....
				        for (EntityType et : cet) {
				        		for (int i = 1; i< 6; i++) {
				        			String week = "WEEK " + i;
				        			if (i == 5){
				        				week = "HOB Night";
				        			}
				        			config1.getNode(et.getName(), week, "==========Natural Spawning==========", "# of Attempts: ").setComment("This is the Number of Entities HOB will attempt to spawn").setValue(0);
				        			config1.getNode(et.getName(), week, "==========Natural Spawning==========", "% per Attempt: ").setComment("This is the Chance of each Attempt at Succeeding").setValue(00.00);
				        			config1.getNode(et.getName(), week, "=========Custom  Properties=========", "Custom Health", "Enabled: ").setComment("Enable this to Overright Vanilla Health").setValue(false);
				        			config1.getNode(et.getName(), week, "=========Custom  Properties=========", "Custom Health", "Health: ").setComment("Set the Amount of health.(Reminder each Heart is = 2)").setValue(20);
				        			config1.getNode(et.getName(), week, "============Custom Drops============", "Enable Custom Drops: ").setComment("True = Custom Drops, False = Vanilla").setValue(false);
				        			config1.getNode(et.getName(), week, "============Custom Drops============", "List of Items and Amount").setComment("List out the Minecraft ID(ie. minecraft:Iron_sword) and the Number of them").setValue("None");
				        		}
				        		
			        }

				saveSpawnControl();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
		//load the configs
		this.config1 = this.configLoader1.load();
	}catch (IOException e){
		return;
	}
}

public void loadSpawnControl(){
	try{
		config1 = configLoader1.load();
	}catch(IOException e){
		e.printStackTrace();
	}
}
public void saveSpawnControl(){
	try{
		configLoader1.save(config1);
	}catch(IOException e){
		e.printStackTrace();
	}
}	
public CommentedConfigurationNode getSpawnControl(){
	return config1;
}
}

Mod entities fall under the registry, yes.

Don’t use et.getName() in your config path, use et.getId().

1 Like

Just for my sake, is this because it’s a better convention since I want it to grab mods too?

No, it’s not a ‘better convention’ it’s better because it’s correct, the names can change based on locale, and there is no guarantee a name will be unique.

1 Like