-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added method for adding loot to chests
- Loading branch information
Showing
8 changed files
with
345 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 197 additions & 0 deletions
197
common/src/main/java/muramasa/antimatter/datagen/AntimatterLoot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
package muramasa.antimatter.datagen; | ||
|
||
import com.google.common.base.Preconditions; | ||
import com.google.gson.JsonDeserializationContext; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonSerializationContext; | ||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; | ||
import lombok.Getter; | ||
import muramasa.antimatter.Antimatter; | ||
import muramasa.antimatter.Ref; | ||
import muramasa.antimatter.mixin.LootPoolAccessor; | ||
import muramasa.antimatter.recipe.RecipeUtil; | ||
import muramasa.antimatter.util.AntimatterPlatformUtils; | ||
import muramasa.antimatter.util.ItemStackHashStrategy; | ||
import net.minecraft.core.Registry; | ||
import net.minecraft.nbt.CompoundTag; | ||
import net.minecraft.resources.ResourceLocation; | ||
import net.minecraft.util.GsonHelper; | ||
import net.minecraft.world.item.ItemStack; | ||
import net.minecraft.world.level.storage.loot.LootContext; | ||
import net.minecraft.world.level.storage.loot.LootPool; | ||
import net.minecraft.world.level.storage.loot.entries.LootItem; | ||
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; | ||
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction; | ||
import net.minecraft.world.level.storage.loot.functions.LootItemFunction; | ||
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType; | ||
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; | ||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; | ||
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; | ||
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; | ||
import org.apache.commons.lang3.ArrayUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.Consumer; | ||
|
||
public class AntimatterLoot { | ||
|
||
private static final Map<ResourceLocation, List<LootEntryItem>> lootEntryItems = new Object2ObjectOpenHashMap<>(); | ||
private static final Map<ResourceLocation, NumberProvider> rollValues = new Object2ObjectOpenHashMap<>(); | ||
|
||
private static final LootItemCondition[] NO_CONDITIONS = new LootItemCondition[0]; | ||
|
||
public static void onLootTableLoad(LootPool mainPool, ResourceLocation name) { | ||
if (mainPool == null) return; | ||
|
||
if (lootEntryItems.containsKey(name)) { | ||
List<LootEntryItem> entryItems = lootEntryItems.get(name); | ||
for (LootEntryItem entry : entryItems) { | ||
/*if (ConfigHolder.INSTANCE.dev.debug) { | ||
Antimatter.LOGGER.info("adding {} to lootTable {}", entry, name); | ||
}*/ | ||
|
||
try { | ||
LootPoolEntryContainer[] entries = ((LootPoolAccessor) mainPool).getEntries(); | ||
entries = ArrayUtils.add(entries, entry); | ||
((LootPoolAccessor) mainPool).setEntries(entries); | ||
} catch (RuntimeException e) { | ||
Antimatter.LOGGER.error("Couldn't add {} to lootTable {}: {}", entry, name, e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
if (rollValues.containsKey(name)) { | ||
NumberProvider rangeAdd = rollValues.get(name); | ||
NumberProvider range = ((LootPoolAccessor)mainPool).getRolls(); | ||
// mainPool.setRolls(UniformGenerator.between(range.getMin() + rangeAdd.getMin(), range.getMax() + | ||
// rangeAdd.getMax())); TODO additional rolls | ||
} | ||
} | ||
|
||
public static void addItem(@NotNull ResourceLocation lootTable, @NotNull ItemStack stack, int minAmount, | ||
int maxAmount, int weight) { | ||
RandomWeightLootFunction lootFunction = new RandomWeightLootFunction(stack, minAmount, maxAmount); | ||
String modid = Objects.requireNonNull(AntimatterPlatformUtils.INSTANCE.getIdFromItem(stack.getItem())).getNamespace(); | ||
String entryName = createEntryName(stack, modid, weight, lootFunction); | ||
LootEntryItem itemEntry = new LootEntryItem(stack, weight, lootFunction, entryName); | ||
lootEntryItems.computeIfAbsent(lootTable, $ -> new ArrayList<>()).add(itemEntry); | ||
} | ||
|
||
public static void addRolls(ResourceLocation tableLocation, int minAdd, int maxAdd) { | ||
rollValues.put(tableLocation, UniformGenerator.between(minAdd, maxAdd)); | ||
} | ||
|
||
private static final ItemStackHashStrategy HASH_STRATEGY = ItemStackHashStrategy.comparingAllButCount(); | ||
|
||
private static @NotNull String createEntryName(@NotNull ItemStack stack, @NotNull String modid, int weight, | ||
@NotNull RandomWeightLootFunction function) { | ||
int hashCode = Objects.hash(HASH_STRATEGY.hashCode(stack), modid, weight, function.getMinAmount(), | ||
function.getMaxAmount()); | ||
return String.format("#%s:loot_%s", modid, hashCode); | ||
} | ||
|
||
private static class LootEntryItem extends LootItem { | ||
|
||
private final ItemStack stack; | ||
private final String entryName; | ||
|
||
public LootEntryItem(@NotNull ItemStack stack, int weight, LootItemFunction lootFunction, | ||
@NotNull String entryName) { | ||
super(stack.getItem(), weight, 1, NO_CONDITIONS, new LootItemFunction[] { lootFunction }); | ||
this.stack = stack; | ||
this.entryName = entryName; | ||
} | ||
|
||
public void createItemStack(Consumer<ItemStack> stackConsumer, LootContext lootContext) { | ||
stackConsumer.accept(this.stack.copy()); | ||
} | ||
|
||
@Override | ||
public @NotNull String toString() { | ||
return "LootEntryItem{name=" + entryName + ", stack=" + stack.toString() + '}'; | ||
} | ||
} | ||
|
||
public static class RandomWeightLootFunction extends LootItemConditionalFunction implements LootItemFunction { | ||
|
||
public static final LootItemFunctionType TYPE = Registry.register(Registry.LOOT_FUNCTION_TYPE, | ||
new ResourceLocation(Ref.ID,"random_weight"), new LootItemFunctionType(new Serializer())); | ||
|
||
private final ItemStack stack; | ||
@Getter | ||
private final int minAmount; | ||
@Getter | ||
private final int maxAmount; | ||
|
||
public RandomWeightLootFunction(@NotNull ItemStack stack, int minAmount, int maxAmount) { | ||
super(NO_CONDITIONS); | ||
Preconditions.checkArgument(minAmount <= maxAmount, "minAmount must be <= maxAmount"); | ||
this.stack = stack; | ||
this.minAmount = minAmount; | ||
this.maxAmount = maxAmount; | ||
} | ||
|
||
public static void init() { | ||
// Do nothing here. This just ensures that TYPE is being set immediately when called. | ||
} | ||
|
||
@Override | ||
public LootItemFunctionType getType() { | ||
return TYPE; | ||
} | ||
|
||
@Override | ||
protected ItemStack run(ItemStack itemStack, LootContext context) { | ||
if (stack.getDamageValue() != 0) { | ||
itemStack.setDamageValue(stack.getDamageValue()); | ||
} | ||
CompoundTag tagCompound = stack.getTag(); | ||
if (tagCompound != null) { | ||
itemStack.setTag(tagCompound.copy()); | ||
} | ||
|
||
if (minAmount == maxAmount) { | ||
itemStack.setCount(minAmount); | ||
return itemStack; | ||
} | ||
|
||
int count = Math.min(minAmount + context.getRandom().nextInt(maxAmount - minAmount + 1), | ||
stack.getMaxStackSize()); | ||
itemStack.setCount(count); | ||
return itemStack; | ||
} | ||
|
||
public static class Serializer extends LootItemConditionalFunction.Serializer<RandomWeightLootFunction> { | ||
|
||
/** | ||
* Serialize the {@link SetItemCountFunction} by putting its data into the JsonObject. | ||
*/ | ||
public void serialize(JsonObject json, RandomWeightLootFunction setItemCountFunction, | ||
JsonSerializationContext serializationContext) { | ||
super.serialize(json, setItemCountFunction, serializationContext); | ||
json.add("min", serializationContext.serialize(setItemCountFunction.minAmount)); | ||
json.add("max", serializationContext.serialize(setItemCountFunction.maxAmount)); | ||
JsonObject stack = new JsonObject(); | ||
stack.addProperty("item", | ||
AntimatterPlatformUtils.INSTANCE.getIdFromItem(setItemCountFunction.stack.getItem()).toString()); | ||
stack.addProperty("count", setItemCountFunction.stack.getCount()); | ||
if (setItemCountFunction.stack.hasTag()) | ||
stack.addProperty("nbt", setItemCountFunction.stack.getTag().toString()); | ||
json.add("stack", stack); | ||
} | ||
|
||
public RandomWeightLootFunction deserialize(JsonObject object, | ||
JsonDeserializationContext deserializationContext, | ||
LootItemCondition[] conditions) { | ||
ItemStack stack = RecipeUtil.INSTANCE.getItemStack(object.getAsJsonObject("stack"), true); | ||
int min = GsonHelper.getAsInt(object, "min"); | ||
int max = GsonHelper.getAsInt(object, "max"); | ||
return new RandomWeightLootFunction(stack, min, max); | ||
} | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
common/src/main/java/muramasa/antimatter/mixin/LootPoolAccessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package muramasa.antimatter.mixin; | ||
|
||
import net.minecraft.world.level.storage.loot.LootPool; | ||
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer; | ||
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Mutable; | ||
import org.spongepowered.asm.mixin.gen.Accessor; | ||
|
||
@Mixin(LootPool.class) | ||
public interface LootPoolAccessor { | ||
@Accessor | ||
LootPoolEntryContainer[] getEntries(); | ||
|
||
@Accessor | ||
@Mutable | ||
void setEntries(LootPoolEntryContainer[] entries); | ||
|
||
@Accessor | ||
NumberProvider getRolls(); | ||
} |
118 changes: 118 additions & 0 deletions
118
common/src/main/java/muramasa/antimatter/util/ItemStackHashStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package muramasa.antimatter.util; | ||
|
||
import net.minecraft.world.item.ItemStack; | ||
|
||
import it.unimi.dsi.fastutil.Hash; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.Objects; | ||
|
||
/** | ||
* A configurable generator of hashing strategies, allowing for consideration of select properties of ItemStacks when | ||
* considering equality. | ||
*/ | ||
public interface ItemStackHashStrategy extends Hash.Strategy<ItemStack> { | ||
|
||
/** | ||
* @return a builder object for producing a custom ItemStackHashStrategy. | ||
*/ | ||
static ItemStackHashStrategyBuilder builder() { | ||
return new ItemStackHashStrategyBuilder(); | ||
} | ||
|
||
/** | ||
* Generates an ItemStackHash configured to compare every aspect of ItemStacks. | ||
* | ||
* @return the ItemStackHashStrategy as described above. | ||
*/ | ||
static ItemStackHashStrategy comparingAll() { | ||
return builder().compareItem(true) | ||
.compareCount(true) | ||
.compareTag(true) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Generates an ItemStackHash configured to compare every aspect of ItemStacks except the number | ||
* of items in the stack. | ||
* | ||
* @return the ItemStackHashStrategy as described above. | ||
*/ | ||
static ItemStackHashStrategy comparingAllButCount() { | ||
return builder().compareItem(true) | ||
.compareTag(true) | ||
.build(); | ||
} | ||
|
||
static ItemStackHashStrategy comparingItem() { | ||
return builder().compareItem(true) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Builder pattern class for generating customized ItemStackHashStrategy | ||
*/ | ||
class ItemStackHashStrategyBuilder { | ||
|
||
private boolean item, count, tag; | ||
|
||
/** | ||
* Defines whether the Item type should be considered for equality. | ||
* | ||
* @param choice {@code true} to consider this property, {@code false} to ignore it. | ||
* @return {@code this} | ||
*/ | ||
public ItemStackHashStrategyBuilder compareItem(boolean choice) { | ||
item = choice; | ||
return this; | ||
} | ||
|
||
/** | ||
* Defines whether stack size should be considered for equality. | ||
* | ||
* @param choice {@code true} to consider this property, {@code false} to ignore it. | ||
* @return {@code this} | ||
*/ | ||
public ItemStackHashStrategyBuilder compareCount(boolean choice) { | ||
count = choice; | ||
return this; | ||
} | ||
|
||
/** | ||
* Defines whether NBT Tags should be considered for equality. | ||
* | ||
* @param choice {@code true} to consider this property, {@code false} to ignore it. | ||
* @return {@code this} | ||
*/ | ||
public ItemStackHashStrategyBuilder compareTag(boolean choice) { | ||
tag = choice; | ||
return this; | ||
} | ||
|
||
/** | ||
* @return the ItemStackHashStrategy as configured by "compare" methods. | ||
*/ | ||
public ItemStackHashStrategy build() { | ||
return new ItemStackHashStrategy() { | ||
|
||
@Override | ||
public int hashCode(@Nullable ItemStack o) { | ||
return o == null || o.isEmpty() ? 0 : Objects.hash( | ||
item ? o.getItem() : null, | ||
count ? o.getCount() : null, | ||
tag ? o.getTag() : null); | ||
} | ||
|
||
@Override | ||
public boolean equals(@Nullable ItemStack a, @Nullable ItemStack b) { | ||
if (a == null || a.isEmpty()) return b == null || b.isEmpty(); | ||
if (b == null || b.isEmpty()) return false; | ||
|
||
return (!item || a.getItem() == b.getItem()) && | ||
(!count || a.getCount() == b.getCount()) && | ||
(!tag || Objects.equals(a.getTag(), b.getTag())); | ||
} | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.