it works on forge. todo mixin until after everything's loaded and shoehorn in the loot func

This commit is contained in:
gamma-delta 2022-05-23 23:24:21 -05:00
parent 38a300cb46
commit ee3f34878e
42 changed files with 722 additions and 489 deletions

View file

@ -8,22 +8,14 @@ import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.api.mod.HexStatistics
import at.petrak.hexcasting.api.spell.Operator
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.SpellDatum
import at.petrak.hexcasting.api.spell.Widget
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.Mishap
import at.petrak.hexcasting.api.spell.mishaps.MishapDisallowedSpell
import at.petrak.hexcasting.api.spell.mishaps.MishapError
import at.petrak.hexcasting.api.spell.mishaps.MishapTooManyCloseParens
import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.math.HexDir
import at.petrak.hexcasting.api.spell.math.HexPattern
import at.petrak.hexcasting.api.spell.mishaps.*
import at.petrak.hexcasting.api.utils.ManaHelper
import at.petrak.hexcasting.xplat.IXplatAbstractions
import at.petrak.hexcasting.api.utils.asCompound
import at.petrak.hexcasting.api.utils.getList
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
@ -66,7 +58,7 @@ class CastingHarness private constructor(
var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, iotas)))
// Begin aggregating info
val info = TempControllerInfo(false, false)
var lastResolutionType = ResolvedPatternType.UNKNOWN
var lastResolutionType = ResolvedPatternType.UNRESOLVED
while (continuation is SpellContinuation.NotDone && !info.earlyExit) {
// Take the top of the continuation stack...
val next = continuation.frame
@ -116,7 +108,12 @@ class CastingHarness private constructor(
continuation,
null,
mishap.resolutionType(ctx),
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null))),
listOf(
OperatorSideEffect.DoMishap(
mishap,
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)
)
),
)
} catch (exception: Exception) {
exception.printStackTrace()
@ -124,7 +121,12 @@ class CastingHarness private constructor(
continuation,
null,
ResolvedPatternType.ERRORED,
listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)))
listOf(
OperatorSideEffect.DoMishap(
MishapError(exception),
Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null)
)
)
)
}
}
@ -145,7 +147,12 @@ class CastingHarness private constructor(
if (!HexConfig.server().isActionAllowed(operatorIdPair.second)) {
throw MishapDisallowedSpell()
}
val (cont2, stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(continuation, this.stack.toMutableList(), this.localIota, this.ctx)
val (cont2, stack2, local2, sideEffectsUnmut) = operatorIdPair.first.operate(
continuation,
this.stack.toMutableList(),
this.localIota,
this.ctx
)
this.localIota = local2
// Stick a poofy particle effect at the caster position
val sideEffects = sideEffectsUnmut.toMutableList()
@ -183,7 +190,12 @@ class CastingHarness private constructor(
continuation,
null,
ResolvedPatternType.ERRORED,
listOf(OperatorSideEffect.DoMishap(MishapError(exception), Mishap.Context(newPat, operatorIdPair?.second)))
listOf(
OperatorSideEffect.DoMishap(
MishapError(exception),
Mishap.Context(newPat, operatorIdPair?.second)
)
)
)
}
}
@ -200,8 +212,9 @@ class CastingHarness private constructor(
}
if (haskellProgrammersShakingandCryingRN is OperatorSideEffect.AttemptSpell &&
haskellProgrammersShakingandCryingRN.hasCastingSound) {
info.playSound = true
haskellProgrammersShakingandCryingRN.hasCastingSound
) {
info.playSound = true
}
}
}
@ -443,7 +456,10 @@ class CastingHarness private constructor(
}
val localTag = nbt.getCompound(TAG_LOCAL)
val localIota = if (localTag.size() == 1) SpellDatum.DeserializeFromNBT(localTag, ctx.world) else SpellDatum.make(Widget.NULL)
val localIota =
if (localTag.size() == 1) SpellDatum.DeserializeFromNBT(localTag, ctx.world) else SpellDatum.make(
Widget.NULL
)
val parenthesized = mutableListOf<SpellDatum<*>>()
val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)

View file

@ -24,6 +24,7 @@ sealed interface ContinuationFrame {
* @return the result of this pattern step
*/
fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult
/**
* The OpHalt instruction wants us to "jump to" the END of the nearest meta-eval.
* In other words, we should consume Evaluate frames until we hit a FinishEval or Thoth frame.
@ -35,12 +36,16 @@ sealed interface ContinuationFrame {
* A list of patterns to be evaluated in sequence.
* @property list the *remaining* list of patterns to be evaluated
*/
data class Evaluate(val list: SpellList): ContinuationFrame {
data class Evaluate(val list: SpellList) : ContinuationFrame {
// Discard this frame and keep discarding frames.
override fun breakDownwards(stack: List<SpellDatum<*>>) = Pair(false, stack)
// Step the list of patterns, evaluating a single one.
override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult {
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastResult {
// If there are patterns left...
if (list.nonEmpty) {
val newCont = if (list.cdr.nonEmpty) { // yay TCO
@ -51,7 +56,7 @@ sealed interface ContinuationFrame {
return harness.getUpdate(list.car, level, newCont)
} else {
// If there are no patterns (e.g. empty Hermes), just return OK.
return CastResult(continuation, null, ResolvedPatternType.OK, listOf())
return CastResult(continuation, null, ResolvedPatternType.EVALUATED, listOf())
}
}
@ -61,13 +66,22 @@ sealed interface ContinuationFrame {
* A stack marker representing the end of a Hermes evaluation,
* so that we know when to stop removing frames during a Halt.
*/
class FinishEval(): ContinuationFrame {
class FinishEval() : ContinuationFrame {
// Don't do anything else to the stack, just finish the halt statement.
override fun breakDownwards(stack: List<SpellDatum<*>>) = Pair(true, stack)
// Evaluating it does nothing; it's only a boundary condition.
override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult {
return CastResult(continuation, FunctionalData(harness.stack.toList(), 0, listOf(), false), ResolvedPatternType.OK, listOf())
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastResult {
return CastResult(
continuation,
FunctionalData(harness.stack.toList(), 0, listOf(), false),
ResolvedPatternType.EVALUATED,
listOf()
)
}
}
@ -80,7 +94,12 @@ sealed interface ContinuationFrame {
* @property baseStack the stack state at Thoth entry
* @property acc concatenated list of final stack states after Thoth exit
*/
data class ForEach(val data: SpellList, val code: SpellList, val baseStack: List<SpellDatum<*>>?, val acc: MutableList<SpellDatum<*>>): ContinuationFrame {
data class ForEach(
val data: SpellList,
val code: SpellList,
val baseStack: List<SpellDatum<*>>?,
val acc: MutableList<SpellDatum<*>>
) : ContinuationFrame {
/** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */
override fun breakDownwards(stack: List<SpellDatum<*>>): Pair<Boolean, List<SpellDatum<*>>> {
@ -91,7 +110,11 @@ sealed interface ContinuationFrame {
}
/** Step the Thoth computation, enqueueing one code evaluation. */
override fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult {
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
): CastResult {
// If this isn't the very first Thoth step (i.e. no Thoth computations run yet)...
val stack = if (baseStack == null) {
// init stack to the harness stack...
@ -118,7 +141,12 @@ sealed interface ContinuationFrame {
}
val tStack = stack.toMutableList()
tStack.add(stackTop)
return CastResult(newCont, FunctionalData(tStack, 0, listOf(), false), ResolvedPatternType.OK, listOf())
return CastResult(
newCont,
FunctionalData(tStack, 0, listOf(), false),
ResolvedPatternType.EVALUATED,
listOf()
)
}
}
}

View file

@ -0,0 +1,35 @@
package at.petrak.hexcasting.common.lib;
import at.petrak.hexcasting.common.loot.AmethystReducerFunc;
import at.petrak.hexcasting.common.loot.PatternScrollFunc;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
public class HexLootFunctions {
public static void registerSerializers(BiConsumer<LootItemFunctionType, ResourceLocation> r) {
for (var e : LOOT_FUNCS.entrySet()) {
r.accept(e.getValue(), e.getKey());
}
}
private static final Map<ResourceLocation, LootItemFunctionType> LOOT_FUNCS = new LinkedHashMap<>();
public static final LootItemFunctionType PATTERN_SCROLL = register("pattern_scroll",
new LootItemFunctionType(new PatternScrollFunc.Serializer()));
public static final LootItemFunctionType AMETHYST_SHARD_REDUCER = register("amethyst_shard_reducer",
new LootItemFunctionType(new AmethystReducerFunc.Serializer()));
private static LootItemFunctionType register(String id, LootItemFunctionType lift) {
var old = LOOT_FUNCS.put(modLoc(id), lift);
if (old != null) {
throw new IllegalArgumentException("Typo? Duplicate id " + id);
}
return lift;
}
}

View file

@ -0,0 +1,52 @@
package at.petrak.hexcasting.common.loot;
import at.petrak.hexcasting.common.lib.HexLootFunctions;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction;
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
public class AmethystReducerFunc extends LootItemConditionalFunction {
public final double delta;
public AmethystReducerFunc(LootItemCondition[] lootItemConditions, double delta) {
super(lootItemConditions);
this.delta = delta;
}
@Override
protected ItemStack run(ItemStack stack, LootContext ctx) {
if (stack.getItem() == Items.AMETHYST_SHARD) {
if (stack.is(Items.AMETHYST_SHARD)) {
stack.setCount((int) (stack.getCount() * (1 + delta)));
}
}
return stack;
}
@Override
public LootItemFunctionType getType() {
return HexLootFunctions.AMETHYST_SHARD_REDUCER;
}
public static class Serializer extends LootItemConditionalFunction.Serializer<AmethystReducerFunc> {
@Override
public void serialize(JsonObject json, AmethystReducerFunc value, JsonSerializationContext ctx) {
super.serialize(json, value, ctx);
json.addProperty("delta", value.delta);
}
@Override
public AmethystReducerFunc deserialize(JsonObject object, JsonDeserializationContext ctx,
LootItemCondition[] conditions) {
var delta = GsonHelper.getAsDouble(object, "delta");
return new AmethystReducerFunc(conditions, delta);
}
}
}

View file

@ -0,0 +1,52 @@
package at.petrak.hexcasting.common.loot;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.storage.loot.LootPool;
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
import net.minecraft.world.level.storage.loot.entries.LootTableReference;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import java.util.function.Consumer;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
// https://github.com/VazkiiMods/Botania/blob/1.18.x/Xplat/src/main/java/vazkii/botania/common/loot/LootHandler.java
public class HexLootHandler {
public static final ResourceLocation FUNC_AMETHYST_SHARD_REDUCER = modLoc("amethyst_shard_reducer");
public static final ResourceLocation TABLE_INJECT_AMETHYST_CLUSTER = modLoc("inject/amethyst_cluster");
public static void lootLoad(ResourceLocation id,
Consumer<LootPool> addPool) {
if (id.equals(Blocks.AMETHYST_CLUSTER.getLootTable())) {
addPool.accept(getInjectPool(TABLE_INJECT_AMETHYST_CLUSTER));
} else if (
id.equals(new ResourceLocation("minecraft:chests/jungle_temple"))
|| id.equals(new ResourceLocation("minecraft:chests/simple_dungeon"))
|| id.equals(new ResourceLocation("minecraft:chests/village/village_cartographer"))
) {
addPool.accept(getInjectPool(modLoc("inject/scroll_loot_few")));
} else if (
id.equals(new ResourceLocation("minecraft:chests/bastion_treasure"))
|| id.equals(new ResourceLocation("minecraft:chests/shipwreck_map"))
) {
addPool.accept(getInjectPool(modLoc("inject/scroll_loot_some")));
} else if (id.equals(new ResourceLocation("minecraft:chests/stronghold_library"))
) {
addPool.accept(getInjectPool(modLoc("inject/scroll_loot_many")));
}
}
public static LootPool getInjectPool(ResourceLocation entry) {
return LootPool.lootPool()
.add(getInjectEntry(entry, 1))
.setBonusRolls(UniformGenerator.between(0, 1))
.build();
}
private static LootPoolEntryContainer.Builder<?> getInjectEntry(ResourceLocation table, int weight) {
return LootTableReference.lootTableReference(table)
.setWeight(weight);
}
}

View file

@ -0,0 +1,59 @@
package at.petrak.hexcasting.common.loot;
import at.petrak.hexcasting.api.PatternRegistry;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.common.items.ItemScroll;
import at.petrak.hexcasting.common.lib.HexLootFunctions;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction;
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
public class PatternScrollFunc extends LootItemConditionalFunction {
public PatternScrollFunc(LootItemCondition[] lootItemConditions) {
super(lootItemConditions);
}
@Override
protected ItemStack run(ItemStack stack, LootContext ctx) {
var rand = ctx.getRandom();
var worldLookup = PatternRegistry.getPerWorldPatterns(ctx.getLevel());
var keys = worldLookup.keySet().stream().toList();
var sig = keys.get(rand.nextInt(keys.size()));
var entry = worldLookup.get(sig);
var opId = entry.component1();
var startDir = entry.component2();
var tag = new CompoundTag();
tag.putString(ItemScroll.TAG_OP_ID, opId.toString());
tag.put(ItemScroll.TAG_PATTERN, HexPattern.FromAnglesSig(sig, startDir).serializeToNBT());
stack.getOrCreateTag().merge(tag);
return stack;
}
@Override
public LootItemFunctionType getType() {
return HexLootFunctions.PATTERN_SCROLL;
}
public static class Serializer extends LootItemConditionalFunction.Serializer<PatternScrollFunc> {
@Override
public void serialize(JsonObject json, PatternScrollFunc value, JsonSerializationContext ctx) {
super.serialize(json, value, ctx);
}
@Override
public PatternScrollFunc deserialize(JsonObject object, JsonDeserializationContext ctx,
LootItemCondition[] conditions) {
return new PatternScrollFunc(conditions);
}
}
}

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.xplat.datagen;
package at.petrak.hexcasting.datagen;
import at.petrak.hexcasting.common.lib.HexBlockTags;
import at.petrak.hexcasting.common.lib.HexBlocks;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.xplat.datagen;
package at.petrak.hexcasting.datagen;
import at.petrak.hexcasting.api.mod.HexItemTags;
import at.petrak.hexcasting.common.lib.HexBlockTags;

View file

@ -1,7 +1,11 @@
package at.petrak.hexcasting.xplat.datagen;
package at.petrak.hexcasting.datagen;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate;
import at.petrak.hexcasting.common.lib.HexBlocks;
import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.common.loot.HexLootHandler;
import at.petrak.hexcasting.common.loot.PatternScrollFunc;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -25,22 +29,24 @@ import net.minecraft.world.level.storage.loot.LootPool;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.LootTables;
import net.minecraft.world.level.storage.loot.entries.LootItem;
import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount;
import net.minecraft.world.level.storage.loot.functions.ApplyExplosionDecay;
import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction;
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.predicates.AlternativeLootItemCondition;
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
import net.minecraft.world.level.storage.loot.predicates.MatchTool;
import net.minecraft.world.level.storage.loot.predicates.*;
import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
public class HexLootTables extends LootTableProvider {
// steal it ALL from paucal
protected final DataGenerator generator;
@ -50,8 +56,9 @@ public class HexLootTables extends LootTableProvider {
this.generator = pGenerator;
}
protected void makeLootTables(Map<Block, LootTable.Builder> lootTables) {
dropSelf(lootTables, HexBlocks.EMPTY_IMPETUS,
protected void makeLootTables(Map<Block, LootTable.Builder> blockTables,
Map<ResourceLocation, LootTable.Builder> lootTables) {
dropSelf(blockTables, HexBlocks.EMPTY_IMPETUS,
HexBlocks.IMPETUS_RIGHTCLICK, HexBlocks.IMPETUS_LOOK, HexBlocks.IMPETUS_STOREDPLAYER,
HexBlocks.DIRECTRIX_REDSTONE, HexBlocks.EMPTY_DIRECTRIX,
HexBlocks.AKASHIC_RECORD, HexBlocks.AKASHIC_BOOKSHELF, HexBlocks.AKASHIC_CONNECTOR,
@ -64,24 +71,55 @@ public class HexLootTables extends LootTableProvider {
HexBlocks.AKASHIC_TRAPDOOR, HexBlocks.AKASHIC_STAIRS, HexBlocks.AKASHIC_PRESSURE_PLATE,
HexBlocks.AKASHIC_BUTTON);
makeSlabTable(lootTables, HexBlocks.AKASHIC_SLAB);
makeSlabTable(blockTables, HexBlocks.AKASHIC_SLAB);
makeLeafTable(lootTables, HexBlocks.AKASHIC_LEAVES1);
makeLeafTable(lootTables, HexBlocks.AKASHIC_LEAVES2);
makeLeafTable(lootTables, HexBlocks.AKASHIC_LEAVES3);
makeLeafTable(blockTables, HexBlocks.AKASHIC_LEAVES1);
makeLeafTable(blockTables, HexBlocks.AKASHIC_LEAVES2);
makeLeafTable(blockTables, HexBlocks.AKASHIC_LEAVES3);
var slatePool = LootPool.lootPool()
.setRolls(ConstantValue.exactly(1))
.add(LootItem.lootTableItem(HexBlocks.SLATE)
.apply(CopyNbtFunction.copyData(ContextNbtProvider.BLOCK_ENTITY)
.copy(BlockEntitySlate.TAG_PATTERN, "BlockEntityTag." + BlockEntitySlate.TAG_PATTERN)));
lootTables.put(HexBlocks.SLATE, LootTable.lootTable().withPool(slatePool));
blockTables.put(HexBlocks.SLATE, LootTable.lootTable().withPool(slatePool));
var doorPool = dropThisPool(HexBlocks.AKASHIC_DOOR, 1)
.when(new LootItemBlockStatePropertyCondition.Builder(HexBlocks.AKASHIC_DOOR).setProperties(
StatePropertiesPredicate.Builder.properties().hasProperty(DoorBlock.HALF, DoubleBlockHalf.LOWER)
));
lootTables.put(HexBlocks.AKASHIC_DOOR, LootTable.lootTable().withPool(doorPool));
blockTables.put(HexBlocks.AKASHIC_DOOR, LootTable.lootTable().withPool(doorPool));
var dustPool = LootPool.lootPool()
.add(LootItem.lootTableItem(HexItems.AMETHYST_DUST))
.apply(SetItemCountFunction.setCount(UniformGenerator.between(1, 4)))
.apply(ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE))
.when(MatchTool.toolMatches(
ItemPredicate.Builder.item().hasEnchantment(
new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY)))
.invert());
var isThatAnMFingBrandonSandersonReference = LootPool.lootPool()
.add(LootItem.lootTableItem(HexItems.CHARGED_AMETHYST))
.apply(SetItemCountFunction.setCount(ConstantValue.exactly(1)))
.when(MatchTool.toolMatches(
ItemPredicate.Builder.item().hasEnchantment(
new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY)))
.invert())
.when(BonusLevelTableCondition.bonusLevelFlatChance(Enchantments.BLOCK_FORTUNE,
0.25f, 0.35f, 0.5f, 0.75f, 1.0f));
lootTables.put(HexLootHandler.TABLE_INJECT_AMETHYST_CLUSTER, LootTable.lootTable()
.withPool(dustPool)
.withPool(isThatAnMFingBrandonSandersonReference));
String[] rarities = new String[]{
"few",
"some",
"many"
};
for (int i = 0; i < rarities.length; i++) {
var scrollPool = makeScrollAdder(i + 1);
lootTables.put(modLoc("inject/scroll_loot_" + rarities[i]), scrollPool);
}
}
private void makeLeafTable(Map<Block, LootTable.Builder> lootTables, Block block) {
@ -139,21 +177,34 @@ public class HexLootTables extends LootTableProvider {
lootTables.put(block, table);
}
// "stddev"
private LootTable.Builder makeScrollAdder(float stddev) {
var pool = LootPool.lootPool()
.setRolls(UniformGenerator.between(-stddev, stddev))
.add(LootItem.lootTableItem(HexItems.SCROLL))
.apply(() -> new PatternScrollFunc(new LootItemCondition[0]));
return LootTable.lootTable().withPool(pool);
}
@Override
public void run(HashCache cache) {
var lootTables = new HashMap<Block, LootTable.Builder>();
this.makeLootTables(lootTables);
var blockTables = new HashMap<Block, LootTable.Builder>();
var lootTables = new HashMap<ResourceLocation, LootTable.Builder>();
this.makeLootTables(blockTables, lootTables);
var tables = new HashMap<ResourceLocation, LootTable>();
for (var entry : lootTables.entrySet()) {
tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootContextParamSets.BLOCK).build());
for (var entry : blockTables.entrySet()) {
var old = lootTables.put(entry.getKey().getLootTable(),
entry.getValue().setParamSet(LootContextParamSets.BLOCK));
if (old != null) {
HexAPI.LOGGER.warn("Whoopsy, clobbered a loot table '{}': {}", entry.getKey(), old);
}
}
var outputFolder = this.generator.getOutputFolder();
tables.forEach((key, lootTable) -> {
lootTables.forEach((key, lootTable) -> {
Path path = outputFolder.resolve("data/" + key.getNamespace() + "/loot_tables/" + key.getPath() + ".json");
try {
DataProvider.save(GSON, cache, LootTables.serialize(lootTable), path);
DataProvider.save(GSON, cache, LootTables.serialize(lootTable.build()), path);
} catch (IOException e) {
e.printStackTrace();
}

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.xplat.datagen;
package at.petrak.hexcasting.datagen;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.crafting.Ingredient;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.xplat.datagen.recipe;
package at.petrak.hexcasting.datagen.recipe;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.api.advancements.OvercastTrigger;
@ -10,10 +10,10 @@ import at.petrak.hexcasting.common.recipe.SealFocusRecipe;
import at.petrak.hexcasting.common.recipe.SealSpellbookRecipe;
import at.petrak.hexcasting.common.recipe.ingredient.StateIngredientHelper;
import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient;
import at.petrak.hexcasting.datagen.IXplatIngredients;
import at.petrak.hexcasting.datagen.recipe.builders.BrainsweepRecipeBuilder;
import at.petrak.hexcasting.mixin.accessor.AccessorRecipeProvider;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import at.petrak.hexcasting.xplat.datagen.IXplatIngredients;
import at.petrak.hexcasting.xplat.datagen.recipe.builders.BrainsweepRecipeBuilder;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import net.minecraft.advancements.critereon.EntityPredicate;

View file

@ -1,4 +1,4 @@
package at.petrak.hexcasting.xplat.datagen.recipe.builders;
package at.petrak.hexcasting.datagen.recipe.builders;
import at.petrak.hexcasting.common.recipe.HexRecipeSerializers;
import at.petrak.hexcasting.common.recipe.ingredient.StateIngredient;

View file

@ -0,0 +1,17 @@
package at.petrak.hexcasting.mixin.accessor;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(LootTable.class)
public interface AccessorLootTable {
@Accessor("functions")
LootItemFunction[] hex$getFunctions();
@Accessor("functions")
@Mutable
void hex$setFunctions(LootItemFunction[] lifs);
}

View file

@ -0,0 +1,4 @@
{
"function": "hexcasting:amethyst_shard_reducer",
"delta": -2
}

View file

@ -6,6 +6,7 @@
"package": "at.petrak.hexcasting.mixin",
"mixins": [
"AccessorTagsProvider", "MixinMob", "MixinRaider", "MixinVillager", "MixinWitch", "accessor.AccessorLivingEntity",
"accessor.AccessorRecipeProvider", "accessor.AccessorUseOnContext", "accessor.CriteriaTriggersAccessor"
"accessor.AccessorLootTable", "accessor.AccessorRecipeProvider", "accessor.AccessorUseOnContext",
"accessor.CriteriaTriggersAccessor"
]
}

View file

@ -6,6 +6,7 @@ e125117befadda0785e370969a8e04eff070d057 data\hexcasting\loot_tables\blocks\amet
8aa3d09d72255aa4da497ab4225654961063a496 data\hexcasting\recipes\ancient_scroll_paper.json
fe5f10e9258f430859f1f1f87320a2b5c7b67654 data\hexcasting\recipes\dye_colorizer_green.json
7a535e710c96e39a17606a10bc1f153d7c57b8e7 data\hexcasting\advancements\recipes\hexcasting.creative_tab\akashic_pressure_plate.json
c9bf845be14c7fd2a2495265ba2d63d146166bae data\hexcasting\loot_tables\inject\amethyst_cluster.json
090b54b026f6fef2502295ddde5a60f5350e2ec6 data\hexcasting\advancements\recipes\hexcasting.creative_tab\artifact.json
49b6ea97ddc55ef3d7fa47582f268a07a35cadde data\hexcasting\loot_tables\blocks\slate.json
9fcc0862c99c50a1df9d3af95b2b3c2af28afa1b data\hexcasting\advancements\recipes\hexcasting.creative_tab\slate_block_from_slates.json
@ -20,6 +21,7 @@ add097a7a749bd1ebd5828216f013f6cd5b72b62 data\hexcasting\recipes\akashic_door.js
8e73ac3942a94096017e8c775724beafcbade37b data\hexcasting\advancements\recipes\hexcasting.creative_tab\pride_colorizer_12.json
5f1e9330dcdf927e128212678c8e262c6daa92f1 data\hexcasting\recipes\pride_colorizer_13.json
7351200c8e3eb24772852c578286384c8aab61bd data\hexcasting\advancements\recipes\hexcasting.creative_tab\empty_directrix.json
64aef53a076a34dbaaca0d3df8c671476729bec4 data\hexcasting\loot_tables\inject\scroll_loot_some.json
eb17a23e7a9543f33922c056cdf0d63def176bf2 data\hexcasting\advancements\recipes\hexcasting.creative_tab\uuid_colorizer.json
33fed8fb8e34df026e1eea0df8161c7f842a8648 data\hexcasting\recipes\dye_colorizer_black.json
bceac44311dc2771c3744c0cda299f03fb957350 data\hexcasting\loot_tables\blocks\scroll_paper_lantern.json
@ -30,6 +32,7 @@ b7c248d2627c2a2b398d1c50181c1e0863612424 data\hexcasting\recipes\empty_impetus.j
d5122f034678cc53a2921c65f30451caf708046c data\hexcasting\advancements\recipes\hexcasting.creative_tab\akashic_trapdoor.json
5d4811f78feefbef0a305555143f488b3dac7ac6 data\hexcasting\advancements\recipes\brainsweep\brainsweep\impetus_storedplayer.json
f3c6b6917e504e1c3d5d8875f7cce6f311e791d2 data\hexcasting\tags\items\akashic_logs.json
35a9b4beac7c6eddb990464eaeaebec2a9ab9951 data\hexcasting\loot_tables\inject\scroll_loot_many.json
6837c1fe0ab23167ca8475086b28115369227e0c data\hexcasting\advancements\recipes\hexcasting.creative_tab\dye_colorizer_light_gray.json
556d2e6068965e90c307a435b372ae761cd1c606 data\minecraft\tags\items\doors.json
fe8a7288aa27c07932a31c64ff8fadb943b278d5 data\hexcasting\recipes\dye_colorizer_pink.json
@ -238,6 +241,7 @@ f3c6b6917e504e1c3d5d8875f7cce6f311e791d2 data\minecraft\tags\items\logs_that_bur
ddd7bd92b9e1586cebd2cee658315a9336a80a76 data\hexcasting\advancements\recipes\hexcasting.creative_tab\amethyst_dust_packing.json
4d4caaea035ae4ee878843dd2455042b299b4e5e data\c\tags\items\amethyst_dusts.json
2d52419f3fcdc10643cdb8cef89858efc0ad4d11 data\hexcasting\advancements\recipes\hexcasting.creative_tab\wand_akashic.json
3147422bed290cb47ea3763dbdc6f0e96eed5c2a data\hexcasting\loot_tables\inject\scroll_loot_few.json
82be04125e60a28701de5bb6bc7855bb46fa9d0f data\hexcasting\advancements\recipes\hexcasting.creative_tab\pride_colorizer_0.json
cd3ca380294544b07e91ce85d97808c30ffa5d17 data\hexcasting\advancements\recipes\hexcasting.creative_tab\spellbook.json
c36caf44a941a4abc44a15141eba8fe634c76fb8 data\hexcasting\recipes\dye_colorizer_blue.json

View file

@ -0,0 +1,88 @@
{
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:amethyst_dust"
}
],
"conditions": [
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
}
],
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 4.0
},
"add": false
},
{
"function": "minecraft:apply_bonus",
"enchantment": "minecraft:fortune",
"formula": "minecraft:ore_drops"
}
]
},
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:charged_amethyst"
}
],
"conditions": [
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
},
{
"condition": "minecraft:table_bonus",
"enchantment": "minecraft:fortune",
"chances": [
0.25,
0.35,
0.5,
0.75,
1.0
]
}
],
"functions": [
{
"function": "minecraft:set_count",
"count": 1.0,
"add": false
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -1.0,
"max": 1.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -3.0,
"max": 3.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -2.0,
"max": 2.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -9,6 +9,7 @@ import at.petrak.hexcasting.common.command.PatternResLocArgument
import at.petrak.hexcasting.common.entities.HexEntities
import at.petrak.hexcasting.common.items.ItemJewelerHammer
import at.petrak.hexcasting.common.lib.*
import at.petrak.hexcasting.common.loot.HexLootHandler
import at.petrak.hexcasting.common.misc.Brainsweeping
import at.petrak.hexcasting.common.misc.PlayerPositionRecorder
import at.petrak.hexcasting.common.recipe.HexRecipeSerializers
@ -19,12 +20,14 @@ import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents
import net.fabricmc.fabric.api.event.player.AttackBlockCallback
import net.fabricmc.fabric.api.event.player.UseEntityCallback
import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback
import net.fabricmc.fabric.api.registry.FlammableBlockRegistry
import net.minecraft.commands.synchronization.ArgumentTypes
import net.minecraft.commands.synchronization.EmptyArgumentSerializer
import net.minecraft.core.Registry
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.InteractionResult
import net.minecraft.world.level.storage.loot.LootPool
import java.util.function.BiConsumer
object FabricHexInitializer : ModInitializer {
@ -64,6 +67,13 @@ object FabricHexInitializer : ModInitializer {
ServerTickEvents.END_WORLD_TICK.register(PlayerPositionRecorder::updateAllPlayers)
CommandRegistrationCallback.EVENT.register { dp, _ -> HexCommands.register(dp) }
LootTableLoadingCallback.EVENT.register { recman, manager, id, supplier, setter ->
HexLootHandler.lootLoad(
id,
{ b: LootPool -> supplier.withPool(b) },
)
}
}
fun initRegistries() {
@ -76,9 +86,10 @@ object FabricHexInitializer : ModInitializer {
HexEntities.registerEntities(bind(Registry.ENTITY_TYPE))
HexRecipeSerializers.registerSerializers(bind(Registry.RECIPE_SERIALIZER))
HexParticles.registerParticles(bind(Registry.PARTICLE_TYPE))
HexLootFunctions.registerSerializers(bind(Registry.LOOT_FUNCTION_TYPE))
// Done with soft implements in forge
val flameOn = FlammableBlockRegistry.getDefaultInstance()
for (log in listOf(

View file

@ -1,12 +1,12 @@
package at.petrak.hexcasting.fabric.datagen;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.datagen.HexBlockTagProvider;
import at.petrak.hexcasting.datagen.HexItemTagProvider;
import at.petrak.hexcasting.datagen.HexLootTables;
import at.petrak.hexcasting.datagen.IXplatIngredients;
import at.petrak.hexcasting.datagen.recipe.HexplatRecipes;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import at.petrak.hexcasting.xplat.datagen.HexBlockTagProvider;
import at.petrak.hexcasting.xplat.datagen.HexItemTagProvider;
import at.petrak.hexcasting.xplat.datagen.HexLootTables;
import at.petrak.hexcasting.xplat.datagen.IXplatIngredients;
import at.petrak.hexcasting.xplat.datagen.recipe.HexplatRecipes;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.minecraft.core.Registry;

View file

@ -1,4 +1,3 @@
637e118fc7c371db684d0d831a46833b5851e582 data/forge/loot_modifiers/global_loot_modifiers.json
4d4caaea035ae4ee878843dd2455042b299b4e5e data/forge/tags/items/dusts/amethyst.json
05e86742a71afd740f47639be62f93bc9898fcde data/forge/tags/items/gems.json
cf0ad981bebbb79414d955fb40fbf537fe88b89d data/hexcasting/advancements/recipes/brainsweep/brainsweep/akashic_record.json
@ -85,15 +84,6 @@ f32ccb2d36d773215d91dee46bec70a20af501c3 data/hexcasting/advancements/recipes/he
30950c6dd31102cf145f8f7d2979df0736a7ba1e data/hexcasting/advancements/recipes/hexcasting/wand_oak.json
f8d2872c4e692153049b6ae4879755a079954763 data/hexcasting/advancements/recipes/hexcasting/wand_spruce.json
3b2bcffe70bb1f732f06c2560cef66de6c273d62 data/hexcasting/advancements/recipes/hexcasting/wand_warped.json
70a8f77d38affa642afbfceebe129358737b09ac data/hexcasting/loot_modifiers/amethyst_cluster_charged.json
f746acc6b3e798d3b95f4ceb463c648b1f3ae8c3 data/hexcasting/loot_modifiers/amethyst_cluster_dust.json
a783e00f46a9ff0206e2495c15cea8ba57bdff31 data/hexcasting/loot_modifiers/amethyst_cluster_shard_reducer.json
e04be385fa9daa422e41a38ddd70fdd065107968 data/hexcasting/loot_modifiers/scroll_bastion.json
6569766d1579114149eb0a1154d05ec3c964b2a3 data/hexcasting/loot_modifiers/scroll_cartographer.json
afecba3144e00505977a4ab4de7940f949ab7818 data/hexcasting/loot_modifiers/scroll_dungeon.json
0e8c8a56161586a4021487b27059ca151465af67 data/hexcasting/loot_modifiers/scroll_jungle.json
50e7ad657a0ab43f3bd632120e09f109791aaf34 data/hexcasting/loot_modifiers/scroll_shipwreck.json
7ffa361bd8a108b504fe450749b42997dc898e5e data/hexcasting/loot_modifiers/scroll_stronghold_library.json
5b9b1c15c7a157aa56b3caa7d43a6ad1fa8f4710 data/hexcasting/loot_tables/blocks/akashic_bookshelf.json
811177c2ddc341f7a6d8704e1eb273f200aee3a1 data/hexcasting/loot_tables/blocks/akashic_button.json
ce79c9e183b57bfbdb75cd074d7ff6e48894d05c data/hexcasting/loot_tables/blocks/akashic_connector.json
@ -128,6 +118,10 @@ c521621c409275e219f72abf5c6089d60408e646 data/hexcasting/loot_tables/blocks/impe
bceac44311dc2771c3744c0cda299f03fb957350 data/hexcasting/loot_tables/blocks/scroll_paper_lantern.json
49b6ea97ddc55ef3d7fa47582f268a07a35cadde data/hexcasting/loot_tables/blocks/slate.json
584bd8806ef8df5f0e623ed727d6e54a61e60dea data/hexcasting/loot_tables/blocks/slate_block.json
c9bf845be14c7fd2a2495265ba2d63d146166bae data/hexcasting/loot_tables/inject/amethyst_cluster.json
3147422bed290cb47ea3763dbdc6f0e96eed5c2a data/hexcasting/loot_tables/inject/scroll_loot_few.json
35a9b4beac7c6eddb990464eaeaebec2a9ab9951 data/hexcasting/loot_tables/inject/scroll_loot_many.json
64aef53a076a34dbaaca0d3df8c671476729bec4 data/hexcasting/loot_tables/inject/scroll_loot_some.json
6b4459635b3d53cc2b6836fa97d29244a65b412d data/hexcasting/recipes/abacus.json
1f0c9a98d97fb81e1f504cdb6619a3dfab52ba5f data/hexcasting/recipes/ageing_scroll_paper_lantern.json
fa04d5bc32f5646cd67bc8e8b572bdb7849b735e data/hexcasting/recipes/akashic_bookshelf.json

View file

@ -1,14 +0,0 @@
{
"replace": false,
"entries": [
"hexcasting:amethyst_cluster_charged",
"hexcasting:amethyst_cluster_shard_reducer",
"hexcasting:scroll_bastion",
"hexcasting:amethyst_cluster_dust",
"hexcasting:scroll_dungeon",
"hexcasting:scroll_stronghold_library",
"hexcasting:scroll_jungle",
"hexcasting:scroll_cartographer",
"hexcasting:scroll_shipwreck"
]
}

View file

@ -1,41 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:blocks/amethyst_cluster"
},
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
},
{
"condition": "minecraft:table_bonus",
"enchantment": "minecraft:fortune",
"chances": [
0.25,
0.35,
0.5,
0.75,
1.0
]
}
],
"item": "hexcasting:charged_amethyst",
"functions": [
{
"function": "minecraft:set_count",
"count": 1.0,
"add": false
}
],
"type": "paucal:add_item"
}

View file

@ -1,39 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:blocks/amethyst_cluster"
},
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
}
],
"item": "hexcasting:amethyst_dust",
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 4.0
},
"add": false
},
{
"function": "minecraft:apply_bonus",
"enchantment": "minecraft:fortune",
"formula": "minecraft:ore_drops"
}
],
"type": "paucal:add_item"
}

View file

@ -1,23 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:blocks/amethyst_cluster"
},
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
}
],
"modifier": -2.0,
"type": "hexcasting:amethyst_shard_reducer"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/bastion_treasure"
}
],
"stddev": 2.0,
"type": "hexcasting:scrolls"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/village/village_cartographer"
}
],
"stddev": 1.0,
"type": "hexcasting:scrolls"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/simple_dungeon"
}
],
"stddev": 1.0,
"type": "hexcasting:scrolls"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/jungle_temple"
}
],
"stddev": 1.0,
"type": "hexcasting:scrolls"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/shipwreck_map"
}
],
"stddev": 1.0,
"type": "hexcasting:scrolls"
}

View file

@ -1,10 +0,0 @@
{
"conditions": [
{
"condition": "forge:loot_table_id",
"loot_table_id": "minecraft:chests/stronghold_library"
}
],
"stddev": 3.0,
"type": "hexcasting:scrolls"
}

View file

@ -0,0 +1,88 @@
{
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:amethyst_dust"
}
],
"conditions": [
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
}
],
"functions": [
{
"function": "minecraft:set_count",
"count": {
"type": "minecraft:uniform",
"min": 1.0,
"max": 4.0
},
"add": false
},
{
"function": "minecraft:apply_bonus",
"enchantment": "minecraft:fortune",
"formula": "minecraft:ore_drops"
}
]
},
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:charged_amethyst"
}
],
"conditions": [
{
"condition": "minecraft:inverted",
"term": {
"condition": "minecraft:match_tool",
"predicate": {
"enchantments": [
{
"enchantment": "minecraft:silk_touch"
}
]
}
}
},
{
"condition": "minecraft:table_bonus",
"enchantment": "minecraft:fortune",
"chances": [
0.25,
0.35,
0.5,
0.75,
1.0
]
}
],
"functions": [
{
"function": "minecraft:set_count",
"count": 1.0,
"add": false
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -1.0,
"max": 1.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -3.0,
"max": 3.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -0,0 +1,23 @@
{
"pools": [
{
"rolls": {
"type": "minecraft:uniform",
"min": -2.0,
"max": 2.0
},
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "hexcasting:scroll"
}
],
"functions": [
{
"function": "hexcasting:pattern_scroll"
}
]
}
]
}

View file

@ -13,19 +13,20 @@ import at.petrak.hexcasting.common.command.PatternResLocArgument;
import at.petrak.hexcasting.common.entities.HexEntities;
import at.petrak.hexcasting.common.items.ItemJewelerHammer;
import at.petrak.hexcasting.common.lib.*;
import at.petrak.hexcasting.common.loot.HexLootHandler;
import at.petrak.hexcasting.common.misc.Brainsweeping;
import at.petrak.hexcasting.common.misc.PlayerPositionRecorder;
import at.petrak.hexcasting.common.recipe.HexRecipeSerializers;
import at.petrak.hexcasting.forge.cap.CapSyncers;
import at.petrak.hexcasting.forge.cap.ForgeCapabilityHandler;
import at.petrak.hexcasting.forge.datagen.HexForgeDataGenerators;
import at.petrak.hexcasting.forge.datagen.forge.lootmods.HexLootModifiers;
import at.petrak.hexcasting.forge.network.ForgePacketHandler;
import at.petrak.hexcasting.forge.network.MsgBrainsweepAck;
import at.petrak.hexcasting.forge.recipe.ForgeUnsealedIngredient;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import net.minecraft.commands.synchronization.ArgumentTypes;
import net.minecraft.commands.synchronization.EmptyArgumentSerializer;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@ -38,6 +39,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ToolActions;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.event.LootTableLoadEvent;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.TickEvent;
@ -98,8 +100,6 @@ public class ForgeHexInitializer {
bind(ForgeRegistries.PARTICLE_TYPES, HexParticles::registerParticles);
HexLootModifiers.LOOT_MODS.register(getModEventBus());
ArgumentTypes.register(HexAPI.MOD_ID + ":pattern", PatternResLocArgument.class,
new EmptyArgumentSerializer<>(PatternResLocArgument::id));
HexAdvancementTriggers.registerTriggers();
@ -137,6 +137,8 @@ public class ForgeHexInitializer {
HexRecipeSerializers.registerTypes();
CraftingHelper.register(modLoc("unsealed"), ForgeUnsealedIngredient.Serializer.INSTANCE);
HexStatistics.register();
HexLootFunctions.registerSerializers((lift, id) ->
Registry.register(Registry.LOOT_FUNCTION_TYPE, id, lift));
});
modBus.addListener((FMLLoadCompleteEvent evt) ->
@ -168,6 +170,10 @@ public class ForgeHexInitializer {
evBus.addListener((PlayerEvent.BreakSpeed evt) ->
evt.setCanceled(ItemJewelerHammer.shouldFailToBreak(evt.getPlayer(), evt.getState(), evt.getPos())));
evBus.addListener((LootTableLoadEvent evt) -> HexLootHandler.lootLoad(
evt.getName(),
evt.getTable()::addPool));
// === Events implemented in other ways on Fabric
// On Fabric this should be auto-synced

View file

@ -1,17 +1,16 @@
package at.petrak.hexcasting.forge.datagen;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.forge.datagen.forge.lootmods.HexLootModifiers;
import at.petrak.hexcasting.datagen.HexBlockTagProvider;
import at.petrak.hexcasting.datagen.HexItemTagProvider;
import at.petrak.hexcasting.datagen.HexLootTables;
import at.petrak.hexcasting.datagen.IXplatIngredients;
import at.petrak.hexcasting.datagen.recipe.HexplatRecipes;
import at.petrak.hexcasting.forge.datagen.xplat.HexAdvancements;
import at.petrak.hexcasting.forge.datagen.xplat.HexBlockStatesAndModels;
import at.petrak.hexcasting.forge.datagen.xplat.HexItemModels;
import at.petrak.hexcasting.forge.mixin.ForgeAccessorTagsProvider;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import at.petrak.hexcasting.xplat.datagen.HexBlockTagProvider;
import at.petrak.hexcasting.xplat.datagen.HexItemTagProvider;
import at.petrak.hexcasting.xplat.datagen.HexLootTables;
import at.petrak.hexcasting.xplat.datagen.IXplatIngredients;
import at.petrak.hexcasting.xplat.datagen.recipe.HexplatRecipes;
import net.minecraft.data.DataGenerator;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.ItemTags;
@ -67,8 +66,6 @@ public class HexForgeDataGenerators {
var itemTagProvider = new HexItemTagProvider(gen, blockTagProvider, IXplatAbstractions.INSTANCE.tags());
((ForgeAccessorTagsProvider) itemTagProvider).hex$setExistingFileHelper(efh);
gen.addProvider(itemTagProvider);
gen.addProvider(new HexLootModifiers(gen));
}
}

View file

@ -1,50 +0,0 @@
package at.petrak.hexcasting.forge.datagen.forge.lootmods;
import com.google.gson.JsonObject;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.common.loot.LootModifier;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class AmethystShardReducerModifier extends LootModifier {
private final double modifier;
public AmethystShardReducerModifier(double modifier, LootItemCondition[] conditions) {
super(conditions);
this.modifier = modifier;
}
@NotNull
@Override
protected List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context) {
for (var stack : generatedLoot) {
if (stack.is(Items.AMETHYST_SHARD)) {
stack.setCount((int) (stack.getCount() * (1 + modifier)));
}
}
return generatedLoot;
}
public static class Serializer extends GlobalLootModifierSerializer<AmethystShardReducerModifier> {
@Override
public AmethystShardReducerModifier read(ResourceLocation location, JsonObject json,
LootItemCondition[] conditions) {
var modifier = GsonHelper.getAsDouble(json, "modifier");
return new AmethystShardReducerModifier(modifier, conditions);
}
@Override
public JsonObject write(AmethystShardReducerModifier instance) {
var obj = this.makeConditions(instance.conditions);
obj.addProperty("modifier", instance.modifier);
return obj;
}
}
}

View file

@ -1,97 +0,0 @@
package at.petrak.hexcasting.forge.datagen.forge.lootmods;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.paucal.api.forge.datagen.lootmod.PaucalAddItemModifier;
import at.petrak.paucal.api.forge.datagen.lootmod.PaucalLootMods;
import net.minecraft.advancements.critereon.EnchantmentPredicate;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.advancements.critereon.MinMaxBounds;
import net.minecraft.data.DataGenerator;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount;
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction;
import net.minecraft.world.level.storage.loot.predicates.BonusLevelTableCondition;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraft.world.level.storage.loot.predicates.MatchTool;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import net.minecraftforge.common.data.GlobalLootModifierProvider;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.common.loot.LootTableIdCondition;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class HexLootModifiers extends GlobalLootModifierProvider {
public static final DeferredRegister<GlobalLootModifierSerializer<?>> LOOT_MODS = DeferredRegister.create(
ForgeRegistries.Keys.LOOT_MODIFIER_SERIALIZERS, HexAPI.MOD_ID);
private static final RegistryObject<PatternScrollModifier.Serializer> SCROLLS_IN_CHESTS = LOOT_MODS.register(
"scrolls", PatternScrollModifier.Serializer::new);
private static final RegistryObject<AmethystShardReducerModifier.Serializer> AMETHYST_SHARD_REDUCER = LOOT_MODS.register(
"amethyst_shard_reducer", AmethystShardReducerModifier.Serializer::new);
public HexLootModifiers(DataGenerator gen) {
super(gen, HexAPI.MOD_ID);
}
@Override
protected void start() {
ResourceLocation amethystCluster = new ResourceLocation("minecraft:blocks/amethyst_cluster");
// 4? that's a lot!
add("amethyst_cluster_shard_reducer", AMETHYST_SHARD_REDUCER.get(), new AmethystShardReducerModifier(
-2, new LootItemCondition[]{
LootTableIdCondition.builder(amethystCluster).build(),
MatchTool.toolMatches(
ItemPredicate.Builder.item().hasEnchantment(
new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY)))
.invert().build()
}));
add("amethyst_cluster_dust", PaucalLootMods.ADD_ITEM.get(), new PaucalAddItemModifier(
HexItems.AMETHYST_DUST, new LootItemFunction[]{
SetItemCountFunction.setCount(UniformGenerator.between(1, 4)).build(),
ApplyBonusCount.addOreBonusCount(Enchantments.BLOCK_FORTUNE).build()
}, new LootItemCondition[]{
LootTableIdCondition.builder(amethystCluster).build(),
MatchTool.toolMatches(
ItemPredicate.Builder.item().hasEnchantment(
new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY)))
.invert().build(),
}
));
add("amethyst_cluster_charged", PaucalLootMods.ADD_ITEM.get(), new PaucalAddItemModifier(
HexItems.CHARGED_AMETHYST, 1, new LootItemCondition[]{
LootTableIdCondition.builder(amethystCluster).build(),
MatchTool.toolMatches(
ItemPredicate.Builder.item().hasEnchantment(
new EnchantmentPredicate(Enchantments.SILK_TOUCH, MinMaxBounds.Ints.ANY)))
.invert().build(),
BonusLevelTableCondition.bonusLevelFlatChance(Enchantments.BLOCK_FORTUNE,
0.25f, 0.35f, 0.5f, 0.75f, 1.0f).build()
}));
add("scroll_jungle", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(new ResourceLocation("minecraft:chests/jungle_temple")).build()
}, 1.0));
add("scroll_bastion", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(new ResourceLocation("minecraft:chests/bastion_treasure")).build()
}, 2.0));
add("scroll_dungeon", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(new ResourceLocation("minecraft:chests/simple_dungeon")).build()
}, 1.0));
add("scroll_stronghold_library", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(new ResourceLocation("minecraft:chests/stronghold_library")).build()
}, 3.0));
// Why is there not a village library chest
add("scroll_cartographer", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(
new ResourceLocation("minecraft:chests/village/village_cartographer")).build()
}, 1.0));
add("scroll_shipwreck", SCROLLS_IN_CHESTS.get(), new PatternScrollModifier(new LootItemCondition[]{
LootTableIdCondition.builder(new ResourceLocation("minecraft:chests/shipwreck_map")).build()
}, 1.0));
}
}

View file

@ -1,84 +0,0 @@
package at.petrak.hexcasting.forge.datagen.forge.lootmods;
import at.petrak.hexcasting.api.PatternRegistry;
import at.petrak.hexcasting.api.spell.math.HexPattern;
import at.petrak.hexcasting.common.items.ItemScroll;
import at.petrak.hexcasting.common.lib.HexItems;
import com.google.gson.JsonObject;
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.predicates.LootItemCondition;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.common.loot.LootModifier;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.List;
public class PatternScrollModifier extends LootModifier {
private final double countStddev;
public PatternScrollModifier(LootItemCondition[] conditions, double countStddev) {
super(conditions);
this.countStddev = countStddev;
}
@NotNull
@Override
protected List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context) {
var rand = context.getRandom();
var worldLookup = PatternRegistry.getPerWorldPatterns(context.getLevel());
var allOpIds = worldLookup.keySet().stream().toList();
// Don't generate more than one of the same pattern
var seenPats = new HashSet<String>();
var scrollAmt = rand.nextGaussian(0.0, this.countStddev);
for (int i = 0; i < scrollAmt; i++) {
if (seenPats.size() == allOpIds.size()) {
break;
}
String pattern;
do {
pattern = allOpIds.get(rand.nextInt(allOpIds.size()));
} while (seenPats.contains(pattern));
seenPats.add(pattern);
var entry = worldLookup.get(pattern);
var opId = entry.component1();
var startDir = entry.component2();
var tag = new CompoundTag();
tag.putString(ItemScroll.TAG_OP_ID, opId.toString());
tag.put(ItemScroll.TAG_PATTERN,
HexPattern.FromAnglesSig(pattern, startDir).serializeToNBT());
var stack = new ItemStack(HexItems.SCROLL);
stack.setTag(tag);
generatedLoot.add(stack);
seenPats.add(pattern);
}
return generatedLoot;
}
public static class Serializer extends GlobalLootModifierSerializer<PatternScrollModifier> {
@Override
public PatternScrollModifier read(ResourceLocation location, JsonObject json,
LootItemCondition[] conditions) {
var stddev = GsonHelper.getAsFloat(json, "stddev");
return new PatternScrollModifier(conditions, stddev);
}
@Override
public JsonObject write(PatternScrollModifier instance) {
var obj = this.makeConditions(instance.conditions);
obj.addProperty("stddev", instance.countStddev);
return obj;
}
}
}