Skip to content

Commit 87299b5

Browse files
Merge pull request #49 from CodeMonkeysMods/Loot-Table-Update
Added Loot Table datagen. Added sticks to the short/tall grass loot table.
2 parents d05fccf + a61e73c commit 87299b5

8 files changed

Lines changed: 342 additions & 15 deletions

File tree

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
package com.tcm.MineTale;
22

3-
import com.tcm.MineTale.datagen.ModBlockTagProvider;
4-
import com.tcm.MineTale.datagen.ModLangProvider;
5-
import com.tcm.MineTale.datagen.ModModelProvider;
6-
import com.tcm.MineTale.datagen.ModRecipeProvider;
3+
import com.tcm.MineTale.datagen.*;
74

85
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
96
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
107

118
public class MineTaleDataGen implements DataGeneratorEntrypoint {
129

1310
/**
14-
* Initialize a data pack and register the mod's data providers.
11+
* Initialize a data pack and register the mod's data providers for data generation.
1512
*
16-
* Creates a data pack from the given Fabric data generator and adds the language
17-
* and model providers so they will run during data generation.
13+
* Registers language, model, recipe, block tag, and loot table providers so they
14+
* will run as part of the Fabric data generation pack created from the given generator.
1815
*
1916
* @param fabricDataGenerator the Fabric data generator used to create the data pack
2017
*/
@@ -26,5 +23,6 @@ public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
2623
pack.addProvider(ModModelProvider::new);
2724
pack.addProvider(ModRecipeProvider::new);
2825
pack.addProvider(ModBlockTagProvider::new);
26+
pack.addProvider(ModLootTableProvider::new);
2927
}
3028
}

src/client/java/com/tcm/MineTale/datagen/ModBlockTagProvider.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.tcm.MineTale.datagen;
22

3+
import com.jcraft.jorbis.Block;
34
import com.tcm.MineTale.registry.ModBlocks;
45
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
56
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
@@ -20,14 +21,24 @@ public ModBlockTagProvider(FabricDataOutput output, CompletableFuture<HolderLook
2021
}
2122

2223
/**
23-
* Populates the BlockTags.LOGS tag with this mod's log blocks.
24+
* Populate block tags with this mod's blocks.
2425
*
25-
* Registers each mod-defined log block so they are included in the game's LOGS tag mapping.
26+
* Adds mod-defined blocks to relevant vanilla block tags (for example
27+
* MINEABLE_WITH_PICKAXE, MINEABLE_WITH_AXE, and LOGS) so they are included
28+
* in the game's tag mappings.
2629
*
27-
* @param provider a registry lookup provider used to resolve holders during tag population
30+
* @param provider registry lookup provider used to resolve holders during tag population
2831
*/
2932
@Override
3033
protected void addTags(HolderLookup.Provider provider) {
34+
valueLookupBuilder(BlockTags.MINEABLE_WITH_PICKAXE)
35+
.add(ModBlocks.FURNACE_WORKBENCH_BLOCK_T1)
36+
.add(ModBlocks.FURNACE_WORKBENCH_BLOCK_T2)
37+
.add(ModBlocks.ARMORERS_WORKBENCH_BLOCK);
38+
valueLookupBuilder(BlockTags.MINEABLE_WITH_AXE)
39+
.add(ModBlocks.CAMPFIRE_WORKBENCH_BLOCK)
40+
.add(ModBlocks.WORKBENCH_WORKBENCH_BLOCK);
41+
3142
valueLookupBuilder(BlockTags.LOGS)
3243
.add(ModBlocks.AMBER_LOG)
3344
.add(ModBlocks.BAMBOO_LOG)
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package com.tcm.MineTale.datagen;
2+
3+
import com.tcm.MineTale.block.workbenches.AbstractWorkbench;
4+
import com.tcm.MineTale.registry.ModBlocks;
5+
import com.tcm.MineTale.registry.ModItems;
6+
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
7+
import net.fabricmc.fabric.api.datagen.v1.provider.FabricBlockLootTableProvider;
8+
import net.minecraft.advancements.criterion.StatePropertiesPredicate;
9+
import net.minecraft.core.HolderLookup;
10+
import net.minecraft.core.registries.Registries;
11+
import net.minecraft.world.item.Item;
12+
import net.minecraft.world.item.enchantment.Enchantment;
13+
import net.minecraft.world.item.enchantment.Enchantments;
14+
import net.minecraft.world.level.block.Block;
15+
import net.minecraft.world.level.block.state.properties.ChestType;
16+
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
17+
import net.minecraft.world.level.storage.loot.LootPool;
18+
import net.minecraft.world.level.storage.loot.LootTable;
19+
import net.minecraft.world.level.storage.loot.entries.LootItem;
20+
import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer;
21+
import net.minecraft.world.level.storage.loot.functions.ApplyBonusCount;
22+
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction;
23+
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition;
24+
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
25+
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
26+
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
27+
28+
import java.util.concurrent.CompletableFuture;
29+
30+
public class ModLootTableProvider extends FabricBlockLootTableProvider {
31+
/**
32+
* Creates a ModLootTableProvider used to generate the mod's block loot tables.
33+
*
34+
* Initializes the provider with the data output target and a future registry lookup used to resolve game registries during loot table generation.
35+
*
36+
* @param dataOutput the data output target for generated data
37+
* @param registryLookup a future that provides a HolderLookup.Provider for resolving registries needed while generating loot tables
38+
*/
39+
public ModLootTableProvider(FabricDataOutput dataOutput, CompletableFuture<HolderLookup.Provider> registryLookup) {
40+
super(dataOutput, registryLookup);
41+
}
42+
43+
/**
44+
* Registers loot tables for the mod's workbench blocks.
45+
*
46+
* Each added loot table causes the block to drop itself (one item) only when the block's state
47+
* matches the required DoubleBlockHalf (LOWER) and ChestType (LEFT or SINGLE) for that block,
48+
* and the drop is subject to explosion survival/decay.
49+
*/
50+
@Override
51+
public void generate() {
52+
///Block Drops Itself
53+
this.add(ModBlocks.ARMORERS_WORKBENCH_BLOCK,
54+
LootTable.lootTable() // Use the static factory method to start the builder
55+
.withPool(LootPool.lootPool()
56+
.setRolls(ConstantValue.exactly(1.0F))
57+
.add(LootItem.lootTableItem(ModBlocks.ARMORERS_WORKBENCH_BLOCK))
58+
.when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.ARMORERS_WORKBENCH_BLOCK)
59+
.setProperties(StatePropertiesPredicate.Builder.properties()
60+
.hasProperty(AbstractWorkbench.HALF, DoubleBlockHalf.LOWER)
61+
.hasProperty(AbstractWorkbench.TYPE, ChestType.LEFT)
62+
)
63+
)
64+
.when(ExplosionCondition.survivesExplosion())
65+
)
66+
);
67+
68+
this.add(ModBlocks.CAMPFIRE_WORKBENCH_BLOCK,
69+
LootTable.lootTable() // Use the static factory method to start the builder
70+
.withPool(LootPool.lootPool()
71+
.setRolls(ConstantValue.exactly(1.0F))
72+
.add(LootItem.lootTableItem(ModBlocks.CAMPFIRE_WORKBENCH_BLOCK))
73+
.when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.CAMPFIRE_WORKBENCH_BLOCK)
74+
.setProperties(StatePropertiesPredicate.Builder.properties()
75+
.hasProperty(AbstractWorkbench.HALF, DoubleBlockHalf.LOWER)
76+
.hasProperty(AbstractWorkbench.TYPE, ChestType.SINGLE)
77+
)
78+
)
79+
.when(ExplosionCondition.survivesExplosion())
80+
)
81+
);
82+
83+
this.add(ModBlocks.WORKBENCH_WORKBENCH_BLOCK,
84+
LootTable.lootTable() // Use the static factory method to start the builder
85+
.withPool(LootPool.lootPool()
86+
.setRolls(ConstantValue.exactly(1.0F))
87+
.add(LootItem.lootTableItem(ModBlocks.WORKBENCH_WORKBENCH_BLOCK))
88+
.when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.WORKBENCH_WORKBENCH_BLOCK)
89+
.setProperties(StatePropertiesPredicate.Builder.properties()
90+
.hasProperty(AbstractWorkbench.HALF, DoubleBlockHalf.LOWER)
91+
.hasProperty(AbstractWorkbench.TYPE, ChestType.LEFT)
92+
)
93+
)
94+
.when(ExplosionCondition.survivesExplosion())
95+
)
96+
);
97+
98+
this.add(ModBlocks.FURNACE_WORKBENCH_BLOCK_T1,
99+
LootTable.lootTable() // Use the static factory method to start the builder
100+
.withPool(LootPool.lootPool()
101+
.setRolls(ConstantValue.exactly(1.0F))
102+
.add(LootItem.lootTableItem(ModBlocks.FURNACE_WORKBENCH_BLOCK_T1))
103+
.when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.FURNACE_WORKBENCH_BLOCK_T1)
104+
.setProperties(StatePropertiesPredicate.Builder.properties()
105+
.hasProperty(AbstractWorkbench.HALF, DoubleBlockHalf.LOWER)
106+
.hasProperty(AbstractWorkbench.TYPE, ChestType.LEFT)
107+
)
108+
)
109+
.when(ExplosionCondition.survivesExplosion())
110+
)
111+
);
112+
113+
this.add(ModBlocks.FURNACE_WORKBENCH_BLOCK_T2,
114+
LootTable.lootTable() // Use the static factory method to start the builder
115+
.withPool(LootPool.lootPool()
116+
.setRolls(ConstantValue.exactly(1.0F))
117+
.add(LootItem.lootTableItem(ModBlocks.FURNACE_WORKBENCH_BLOCK_T2))
118+
.when(LootItemBlockStatePropertyCondition.hasBlockStateProperties(ModBlocks.FURNACE_WORKBENCH_BLOCK_T2)
119+
.setProperties(StatePropertiesPredicate.Builder.properties()
120+
.hasProperty(AbstractWorkbench.HALF, DoubleBlockHalf.LOWER)
121+
.hasProperty(AbstractWorkbench.TYPE, ChestType.LEFT)
122+
)
123+
)
124+
.when(ExplosionCondition.survivesExplosion())
125+
)
126+
);
127+
}
128+
129+
130+
/// For Ore Drops
131+
/**
132+
* Create a loot table builder that drops the specified item in multiple quantities with Silk Touch, Fortune bonus, and explosion decay applied.
133+
*
134+
* @param drop the source block used for Silk Touch dispatch and explosion-decay context
135+
* @param item the item to drop from the ore
136+
* @return a LootTable.Builder that drops `item` in a base count between 2 and 5, augmented by the Fortune enchantment, with Silk Touch handling and explosion decay applied
137+
*/
138+
public LootTable.Builder AverageOreDrops(Block drop, Item item) {
139+
HolderLookup.RegistryLookup<Enchantment> impl = this.registries.lookupOrThrow(Registries.ENCHANTMENT);
140+
return this.createSilkTouchDispatchTable(drop, this.applyExplosionDecay(drop, ((LootPoolSingletonContainer.Builder<?>)
141+
LootItem.lootTableItem(item).apply(SetItemCountFunction.setCount(UniformGenerator.between(2, 5))))
142+
.apply(ApplyBonusCount.addOreBonusCount(impl.getOrThrow(Enchantments.FORTUNE)))));
143+
}
144+
145+
/**
146+
* Creates a loot table builder for an ore that yields the specified item with Silk Touch and Fortune handling.
147+
*
148+
* The table gives a base drop count of exactly 1 (before Fortune), increases the count with Fortune, returns the
149+
* ore block when mined with Silk Touch, and applies explosion decay to the drop.
150+
*
151+
* @param drop the ore block (returned when Silk Touch is used)
152+
* @param item the item to drop when the ore is mined without Silk Touch
153+
* @return a LootTable.Builder configured to drop the specified item with Fortune bonuses, Silk Touch dispatch,
154+
* and explosion decay
155+
*/
156+
public LootTable.Builder SingleOreDrops(Block drop, Item item) {
157+
HolderLookup.RegistryLookup<Enchantment> impl = this.registries.lookupOrThrow(Registries.ENCHANTMENT);
158+
return this.createSilkTouchDispatchTable(drop, this.applyExplosionDecay(drop, ((LootPoolSingletonContainer.Builder<?>)
159+
LootItem.lootTableItem(item).apply(SetItemCountFunction.setCount(ConstantValue.exactly(1))))
160+
.apply(ApplyBonusCount.addOreBonusCount(impl.getOrThrow(Enchantments.FORTUNE)))));
161+
}
162+
163+
/**
164+
* Builds a loot table for a "light" ore block that supports Silk Touch, Fortune bonuses, and explosion decay.
165+
*
166+
* @param drop the ore block whose loot table is being created
167+
* @param item the item to drop from the ore when not Silk Touched
168+
* @return a LootTable.Builder that drops {@code item} in quantities of 1–2 (before Fortune), applies Fortune bonus,
169+
* dispatches to Silk Touch drops when applicable, and respects explosion decay
170+
*/
171+
public LootTable.Builder LightOreDrops(Block drop, Item item) {
172+
HolderLookup.RegistryLookup<Enchantment> impl = this.registries.lookupOrThrow(Registries.ENCHANTMENT);
173+
return this.createSilkTouchDispatchTable(drop, this.applyExplosionDecay(drop, ((LootPoolSingletonContainer.Builder<?>)
174+
LootItem.lootTableItem(item).apply(SetItemCountFunction.setCount(UniformGenerator.between(1, 2))))
175+
.apply(ApplyBonusCount.addOreBonusCount(impl.getOrThrow(Enchantments.FORTUNE)))));
176+
}
177+
}

src/main/java/com/tcm/MineTale/MineTale.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.tcm.MineTale;
22

3+
import com.tcm.MineTale.util.ModLootTableModifiers;
34
import net.fabricmc.api.ModInitializer;
45
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
56
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
@@ -72,6 +73,8 @@ public void onInitialize() {
7273

7374
RecipeSynchronization.synchronizeRecipeSerializer(ModRecipes.FURNACE_SERIALIZER);
7475

76+
ModLootTableModifiers.modifyLootTables();
77+
7578
// Register the payload type and codec so the game knows how to handle it
7679
PayloadTypeRegistry.playC2S().register(CraftRequestPayload.TYPE, CraftRequestPayload.CODEC);
7780

@@ -129,10 +132,19 @@ public void onInitialize() {
129132
});
130133
});
131134

132-
LOGGER.info("Hello Fabric world!");
135+
LOGGER.info("MineTale Loaded!");
133136
}
134137

135-
private boolean hasIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
138+
/**
139+
* Determines whether the player (and nearby pullable chests, if the workbench allows) collectively contain all item ingredients required by the given workbench recipe.
140+
*
141+
* This check requires the player's open container to be an AbstractWorkbenchContainerMenu; if it is not, the method returns `false`. It examines the player's non-equipment inventory and, when the workbench permits pulling, the contents of nearby inventories. Each recipe ingredient must be satisfied by a distinct matching item instance from those inventories.
142+
*
143+
* @param player the server player whose inventories are checked
144+
* @param recipe the workbench recipe whose ingredient requirements are being validated
145+
* @return `true` if all ingredients of the recipe can be satisfied from the player and allowed nearby inventories, `false` otherwise
146+
*/
147+
private boolean hasIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
136148
if (!(player.containerMenu instanceof AbstractWorkbenchContainerMenu menu)) return false;
137149
AbstractWorkbenchEntity be = menu.getBlockEntity();
138150

0 commit comments

Comments
 (0)