com.yungnickyoung.minecraft.yungsapi.api.world.randomize.ItemRandomizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of YungsApi-1.21-Fabric Show documentation
Show all versions of YungsApi-1.21-Fabric Show documentation
A common API for YUNG's Minecraft mods
The newest version!
package com.yungnickyoung.minecraft.yungsapi.api.world.randomize;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import com.yungnickyoung.minecraft.yungsapi.YungsApiCommon;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import net.minecraft.class_156;
import net.minecraft.class_1792;
import net.minecraft.class_1802;
import net.minecraft.class_2487;
import net.minecraft.class_2499;
import net.minecraft.class_5819;
import net.minecraft.class_7923;
/**
* Describes a set of Items and the probability of each Item in the set being chosen.
* This is very useful for easily adding random variation to things like armor stands during world generation.
*/
public class ItemRandomizer {
public static final Codec CODEC = RecordCodecBuilder.create((instance) -> instance
.group(
Entry.CODEC.listOf().fieldOf("entries").forGetter((randomizer) -> randomizer.entries),
class_7923.field_41178.method_39673().fieldOf("defaultItem").forGetter((randomizer) -> randomizer.defaultItem))
.apply(instance, ItemRandomizer::new));
/**
* Map of Items to their corresponding probabilities.
* The total sum of all the probabilities should not exceed 1.
*/
private List entries = new ArrayList<>();
/**
* The default Item is used for any leftover probability ranges.
* For example, if the total sum of all the probabilities of the entries is 0.6, then
* there is a 0.4 chance of the defaultItem being selected.
*/
private class_1792 defaultItem = class_1802.field_8162;
/**
* Saves this ItemRandomizer to a new CompoundTag.
* @return The CompoundTag
*/
public class_2487 saveTag() {
class_2487 compoundTag = new class_2487();
// Save default blockstate
compoundTag.method_10569("defaultItemId", class_7923.field_41178.method_10206(this.defaultItem));
// Save entries
class_2499 entriesTag = class_156.method_654(new class_2499(), (tag) -> {
this.entries.forEach((entry) -> {
class_2487 entryTag = new class_2487();
entryTag.method_10569("entryItemId", class_7923.field_41178.method_10206(entry.item));
entryTag.method_10548("entryChance", entry.probability);
tag.add(entryTag);
});
});
compoundTag.method_10566("entries", entriesTag);
return compoundTag;
}
/**
* Constructs a new ItemRandomizer from a CompoundTag.
* @param compoundTag The CompoundTag
*/
public ItemRandomizer(class_2487 compoundTag) {
this.defaultItem = class_7923.field_41178.method_10200(compoundTag.method_10550("defaultItemId"));
this.entries = new ArrayList<>();
class_2499 entriesTag = compoundTag.method_10554("entries", 10);
entriesTag.forEach(entryTag -> {
class_2487 entryCompoundTag = ((class_2487) entryTag);
class_1792 item = class_7923.field_41178.method_10200(entryCompoundTag.method_10550("entryItemId"));
float chance = entryCompoundTag.method_10583("entryChance");
this.addItem(item, chance);
});
}
/**
* Constructs a new ItemRandomizer from a list of Entries and a default Item.
* @param entries List of Entries
* @param defaultItem The default Item
*/
public ItemRandomizer(List entries, class_1792 defaultItem) {
this.entries = entries;
this.defaultItem = defaultItem;
}
/**
* Constructs a new ItemRandomizer with only a default Item.
* @param defaultItem The default Item
*/
public ItemRandomizer(class_1792 defaultItem) {
this.defaultItem = defaultItem;
}
/**
* Constructs a new ItemRandomizer with no default Item nor entries.
*/
public ItemRandomizer() {
}
/**
* Convenience factory function to construct an ItemRandomizer from a list of Items.
* Each Item will have equal probability of being chosen.
*/
public static ItemRandomizer from(class_1792... items) {
ItemRandomizer randomizer = new ItemRandomizer();
float chance = 1f / items.length;
for (class_1792 item : items) {
randomizer.addItem(item, chance);
}
return randomizer;
}
/**
* Adds an Item with given chance of being selected.
* @return The modified ItemRandomizer
*/
public ItemRandomizer addItem(class_1792 item, float chance) {
// Abort if Item already a part of this randomizer
if (entries.stream().anyMatch(entry -> entry.item.equals(item))) {
YungsApiCommon.LOGGER.warn("WARNING: duplicate item {} added to ItemRandomizer!", item.toString());
return this;
}
// Attempt to add Item to entries
float currTotal = entries.stream().map(entry -> entry.probability).reduce(Float::sum).orElse(0f);
float newTotal = currTotal + chance;
if (newTotal > 1) { // Total probability cannot exceed 1
YungsApiCommon.LOGGER.warn("WARNING: item {} added to ItemRandomizer exceeds max probabiltiy of 1!", item.toString());
return this;
}
entries.add(new Entry(item, chance));
return this;
}
/**
* Randomly selects an Item from this ItemRandomizer.
* The random provided should be one used in generation of your structure or feature,
* to ensure reproducibility for the same world seed.
*/
public class_1792 get(Random random) {
float target = random.nextFloat();
float currBottom = 0;
for (Entry entry : entries) {
if (currBottom <= target && target < currBottom + entry.probability) {
return entry.item;
}
currBottom += entry.probability;
}
// No match found
return this.defaultItem;
}
/**
* Randomly selects an Item from this ItemRandomizer.
* The RandomSource provided should be one used in generation of your structure or feature,
* to ensure reproducibility for the same world seed.
*/
public class_1792 get(class_5819 randomSource) {
float target = randomSource.method_43057();
float currBottom = 0;
for (Entry entry : entries) {
if (currBottom <= target && target < currBottom + entry.probability) {
return entry.item;
}
currBottom += entry.probability;
}
// No match found
return this.defaultItem;
}
/**
* Sets the default Item.
* The default Item is used for any leftover probability ranges.
*/
public void setDefaultItem(class_1792 item) {
this.defaultItem = item;
}
/**
* Returns a Map of Items to their corresponding probabilities.
* Does not include the default Item.
* @return The Map
*/
public Map getEntriesAsMap() {
Map map = new HashMap<>();
this.entries.forEach(entry -> map.put(entry.item, entry.probability));
return map;
}
/**
* Returns a List of Entries.
* @return The List
*/
public List getEntries() {
return entries;
}
/**
* Returns the default Item.
* @return The default Item
*/
public class_1792 getDefaultItem() {
return defaultItem;
}
/**
* Represents an Item and its corresponding probability of being chosen.
*/
public static class Entry {
public static Codec CODEC = RecordCodecBuilder.create(instance -> instance
.group(
class_7923.field_41178.method_39673().fieldOf("item").forGetter((entry) -> entry.item),
Codec.floatRange(0.0F, 1.0F).fieldOf("probability").forGetter(entry -> entry.probability))
.apply(instance, Entry::new));
public class_1792 item;
public float probability;
public Entry(class_1792 item, float probability) {
this.item = item;
this.probability = probability;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Entry) {
return this.item.equals(((Entry) obj).item);
} else if (obj instanceof class_1792) {
return this.item.equals(obj);
}
return false;
}
}
}