Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.

Commit 7549f0b

Browse files
Add condition_add action
1 parent 7318c35 commit 7549f0b

8 files changed

Lines changed: 246 additions & 11 deletions

File tree

src/main/java/top/offsetmonkey538/loottablemodifier/api/resource/action/LootModifierActionTypes.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import net.minecraft.util.Identifier;
66
import org.jetbrains.annotations.ApiStatus;
77
import org.jetbrains.annotations.NotNull;
8+
import top.offsetmonkey538.loottablemodifier.api.resource.action.condition.ConditionAddAction;
89
import top.offsetmonkey538.loottablemodifier.api.resource.action.entry.EntryAddAction;
910
import top.offsetmonkey538.loottablemodifier.api.resource.action.entry.EntryRemoveAction;
1011
import top.offsetmonkey538.loottablemodifier.api.resource.action.pool.PoolAddAction;
@@ -45,6 +46,11 @@ private LootModifierActionTypes() {
4546
*/
4647
public static final LootModifierActionType ENTRY_ITEM_SET = register(id("entry_item_set"), EntryItemSetAction.CODEC);
4748

49+
/**
50+
* Type of {@link ConditionAddAction}
51+
*/
52+
public static final LootModifierActionType CONDITION_ADD = register(id("condition_add"), ConditionAddAction.CODEC);
53+
4854
private static LootModifierActionType register(final @NotNull Identifier id, final @NotNull MapCodec<? extends LootModifierAction> codec) {
4955
return Registry.register(LootModifierActionType.REGISTRY, id, new LootModifierActionType(codec));
5056
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package top.offsetmonkey538.loottablemodifier.api.resource.action.condition;
2+
3+
import com.google.common.collect.ImmutableList;
4+
import com.mojang.serialization.Codec;
5+
import com.mojang.serialization.MapCodec;
6+
import com.mojang.serialization.codecs.RecordCodecBuilder;
7+
import net.minecraft.loot.LootPool;
8+
import net.minecraft.loot.condition.LootCondition;
9+
import net.minecraft.loot.entry.LootPoolEntry;
10+
import org.jetbrains.annotations.Contract;
11+
import org.jetbrains.annotations.NotNull;
12+
import top.offsetmonkey538.loottablemodifier.api.resource.action.LootModifierAction;
13+
import top.offsetmonkey538.loottablemodifier.api.resource.action.LootModifierActionType;
14+
import top.offsetmonkey538.loottablemodifier.api.resource.action.LootModifierActionTypes;
15+
import top.offsetmonkey538.loottablemodifier.api.resource.util.LootModifierContext;
16+
import top.offsetmonkey538.loottablemodifier.duck.LootElementWithConditions;
17+
18+
import java.util.List;
19+
20+
/**
21+
* Adds the provided conditions to matched pools/
22+
*
23+
* @param conditions the conditions to add
24+
* @param includePools whether the conditions should be added to matched pools
25+
* @param includeEntries whether the conditions should be added to matched pools
26+
*/
27+
public record ConditionAddAction(List<LootCondition> conditions, boolean includePools, boolean includeEntries) implements LootModifierAction {
28+
public static final MapCodec<ConditionAddAction> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
29+
LootCondition.CODEC.listOf().fieldOf("conditions").forGetter(ConditionAddAction::conditions),
30+
Codec.BOOL.optionalFieldOf("includePools", true).forGetter(ConditionAddAction::includePools),
31+
Codec.BOOL.optionalFieldOf("includeEntries", true).forGetter(ConditionAddAction::includeEntries)
32+
).apply(instance, ConditionAddAction::new));
33+
34+
@Override
35+
public LootModifierActionType getType() {
36+
return LootModifierActionTypes.CONDITION_ADD;
37+
}
38+
39+
@Override
40+
public int apply(@NotNull LootModifierContext context) {
41+
final LootPool pool = context.pool();
42+
if (pool == null) return MODIFIED_NONE;
43+
44+
int returnValue = MODIFIED_NONE;
45+
46+
if (includePools && !context.poolAlreadyModified()) {
47+
final List<LootCondition> newConditions = ImmutableList.<LootCondition>builder()
48+
.addAll(pool.conditions)
49+
.addAll(conditions)
50+
.build();
51+
52+
((LootElementWithConditions) pool).loot_table_modifier$setConditions(newConditions);
53+
returnValue |= MODIFIED_POOL;
54+
}
55+
56+
57+
if (!includeEntries) return returnValue;
58+
59+
final LootPoolEntry entry = context.entry();
60+
if (entry == null) return returnValue | MODIFIED_NONE;
61+
62+
final List<LootCondition> newConditions = ImmutableList.<LootCondition>builder()
63+
.addAll(entry.conditions)
64+
.addAll(conditions)
65+
.build();
66+
67+
((LootElementWithConditions) entry).loot_table_modifier$setConditions(newConditions);
68+
69+
return MODIFIED_ENTRY;
70+
}
71+
72+
/**
73+
* Creates a builder for {@link ConditionAddAction}
74+
*
75+
* @return a new {@link ConditionAddAction.Builder}
76+
*/
77+
@Contract("->new")
78+
public static ConditionAddAction.Builder builder() {
79+
return new ConditionAddAction.Builder();
80+
}
81+
82+
/**
83+
* Builder for {@link ConditionAddAction}
84+
*/
85+
public static class Builder implements LootModifierAction.Builder {
86+
private Builder() {
87+
88+
}
89+
90+
private final ImmutableList.Builder<LootCondition> conditions = ImmutableList.builder();
91+
private boolean includePools = true, includeEntries = true;
92+
93+
/**
94+
* Adds a condition
95+
*
96+
* @param conditionBuilder The condition to add
97+
* @return this
98+
*/
99+
@Contract("_->this")
100+
public ConditionAddAction.Builder condition(LootCondition.Builder conditionBuilder) {
101+
this.conditions.add(conditionBuilder.build());
102+
return this;
103+
}
104+
105+
/**
106+
* The conditions will only be applied to matched pools
107+
*
108+
* @return this
109+
*/
110+
@Contract("->this")
111+
public ConditionAddAction.Builder onlyPools() {
112+
includePools = true;
113+
includeEntries = false;
114+
return this;
115+
}
116+
117+
/**
118+
* The conditions will only be applied to matched entries
119+
*
120+
* @return this
121+
*/
122+
@Contract("->this")
123+
public ConditionAddAction.Builder onlyEntries() {
124+
includeEntries = true;
125+
includePools = false;
126+
return this;
127+
}
128+
129+
@Override
130+
public ConditionAddAction build() {
131+
return new ConditionAddAction(conditions.build(), includePools, includeEntries);
132+
}
133+
}
134+
}

src/main/java/top/offsetmonkey538/loottablemodifier/datagen/LootTableModifierDatagen.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import net.minecraft.item.Items;
1010
import net.minecraft.loot.LootPool;
1111
import net.minecraft.loot.LootTable;
12+
import net.minecraft.loot.condition.KilledByPlayerLootCondition;
1213
import net.minecraft.loot.context.LootContextTypes;
1314
import net.minecraft.loot.entry.ItemEntry;
1415
import net.minecraft.loot.function.SetCountLootFunction;
@@ -19,6 +20,7 @@
1920
import net.minecraft.registry.RegistryWrapper;
2021
import top.offsetmonkey538.loottablemodifier.api.datagen.LootModifierProvider;
2122
import top.offsetmonkey538.loottablemodifier.api.resource.LootModifier;
23+
import top.offsetmonkey538.loottablemodifier.api.resource.action.condition.ConditionAddAction;
2224
import top.offsetmonkey538.loottablemodifier.api.resource.action.entry.EntryAddAction;
2325
import top.offsetmonkey538.loottablemodifier.api.resource.action.entry.EntryRemoveAction;
2426
import top.offsetmonkey538.loottablemodifier.api.resource.predicate.table.TablePredicate;
@@ -176,6 +178,22 @@ protected void generate(RegistryWrapper.WrapperLookup lookup) {
176178
EntryRemoveAction.builder()
177179
)
178180
);
181+
addModifier(
182+
id("squid_ink_sac_only_from_player"),
183+
LootModifier.builder()
184+
.conditionally(
185+
TablePredicate.builder()
186+
.name(EntityType.SQUID)
187+
.and(EntryItemPredicate.builder(Items.INK_SAC))
188+
)
189+
.action(
190+
ConditionAddAction.builder()
191+
.onlyPools()
192+
.condition(
193+
KilledByPlayerLootCondition.builder()
194+
)
195+
)
196+
);
179197
}
180198
}
181199

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package top.offsetmonkey538.loottablemodifier.duck;
2+
3+
import net.minecraft.loot.condition.LootCondition;
4+
5+
import java.util.List;
6+
7+
public interface LootElementWithConditions {
8+
void loot_table_modifier$setConditions(List<LootCondition> conditions);
9+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package top.offsetmonkey538.loottablemodifier.mixin;
2+
3+
import net.minecraft.loot.condition.LootCondition;
4+
import net.minecraft.loot.context.LootContext;
5+
import net.minecraft.loot.entry.LootPoolEntry;
6+
import net.minecraft.util.Util;
7+
import org.spongepowered.asm.mixin.*;
8+
import top.offsetmonkey538.loottablemodifier.duck.LootElementWithConditions;
9+
10+
import java.util.List;
11+
import java.util.function.Predicate;
12+
13+
@Mixin(LootPoolEntry.class)
14+
public class LootPoolEntryMixin implements LootElementWithConditions {
15+
16+
@Shadow
17+
@Final
18+
@Mutable
19+
public List<LootCondition> conditions;
20+
21+
@Shadow
22+
@Final
23+
@Mutable
24+
private Predicate<LootContext> conditionPredicate;
25+
26+
@Override
27+
@Unique
28+
public void loot_table_modifier$setConditions(List<LootCondition> conditions) {
29+
this.conditions = conditions;
30+
this.conditionPredicate = Util.allOf(conditions);
31+
}
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package top.offsetmonkey538.loottablemodifier.mixin;
2+
3+
import net.minecraft.loot.LootPool;
4+
import net.minecraft.loot.condition.LootCondition;
5+
import net.minecraft.loot.context.LootContext;
6+
import net.minecraft.util.Util;
7+
import org.spongepowered.asm.mixin.*;
8+
import top.offsetmonkey538.loottablemodifier.duck.LootElementWithConditions;
9+
10+
import java.util.List;
11+
import java.util.function.Predicate;
12+
13+
@Mixin(LootPool.class)
14+
public class LootPoolMixin implements LootElementWithConditions {
15+
16+
@Shadow
17+
@Final
18+
@Mutable
19+
public List<LootCondition> conditions;
20+
21+
@Shadow
22+
@Final
23+
@Mutable
24+
private Predicate<LootContext> predicate;
25+
26+
@Override
27+
@Unique
28+
public void loot_table_modifier$setConditions(List<LootCondition> conditions) {
29+
this.conditions = conditions;
30+
this.predicate = Util.allOf(conditions);
31+
}
32+
}

src/main/resources/loot-table-modifier.accesswidener

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
accessWidener v1 named
22

3+
# TODO: get rid of these and use mixin insteadddd
4+
35
accessible field net/minecraft/loot/LootTable pools Ljava/util/List;
46
accessible field net/minecraft/loot/LootTable functions Ljava/util/List;
57

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
{
2-
"required": true,
3-
"package": "top.offsetmonkey538.loottablemodifier.mixin",
4-
"compatibilityLevel": "JAVA_17",
5-
"mixins": [
6-
"ItemEntryAccessor",
7-
"LootPoolAccessor",
8-
"LootTableAccessor",
9-
"ReloadableRegistriesMixin"
10-
],
11-
"injectors": {
12-
"defaultRequire": 1
2+
"required": true,
3+
"package": "top.offsetmonkey538.loottablemodifier.mixin",
4+
"compatibilityLevel": "JAVA_17",
5+
"mixins": [
6+
"ItemEntryAccessor",
7+
"LootPoolAccessor",
8+
"LootPoolEntryMixin",
9+
"LootPoolMixin",
10+
"LootTableAccessor",
11+
"ReloadableRegistriesMixin"
12+
],
13+
"injectors": {
14+
"defaultRequire": 1
1315
}
1416
}

0 commit comments

Comments
 (0)