Skip to content

Commit c216d7f

Browse files
xppleEarthcomputer
andauthored
Add the cpredictbrushables command (#752)
* Add the cpredictbrushables command * Rename function * Update mc_feature_java * Increase click glow duration * Add cancel button to search start message * Add feedback for unsuccessful brushable block search; better message for non-infinite search --------- Co-authored-by: joe <[email protected]>
1 parent 56e2fbe commit c216d7f

File tree

6 files changed

+224
-2
lines changed

6 files changed

+224
-2
lines changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ org.gradle.jvmargs=-Xmx2G
2727
simplewaypoints_version=1.0.0-alpha.4
2828
seedfinding_core_version=1.210.0
2929
seedfinding_biome_version=1.171.1
30-
seedfinding_feature_version=1.171.10
30+
seedfinding_feature_version=1.171.11
3131
seedfinding_seed_version=1.171.2
3232
latticg_version=1.07
3333
mapping_io_version=0.7.1

src/main/java/net/earthcomputer/clientcommands/ClientCommands.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ public static void registerCommands(CommandDispatcher<FabricClientCommandSource>
175175
// PlayerInfoCommand.register(dispatcher);
176176
PluginsCommand.register(dispatcher);
177177
PosCommand.register(dispatcher);
178+
PredictBrushablesCommand.register(dispatcher);
178179
RelogCommand.register(dispatcher);
179180
RenderCommand.register(dispatcher);
180181
ReplyCommand.register(dispatcher);

src/main/java/net/earthcomputer/clientcommands/command/ClientCommandHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static Component getGlowCoordsTextComponent(BlockPos pos) {
7373
}
7474

7575
public static Component getGlowButtonTextComponent(BlockPos pos) {
76-
return getCommandTextComponent(Component.translatable("commands.client.glow"), String.format("/cglow block %d %d %d 10", pos.getX(), pos.getY(), pos.getZ()));
76+
return getCommandTextComponent(Component.translatable("commands.client.glow"), String.format("/cglow block %d %d %d 60", pos.getX(), pos.getY(), pos.getZ()));
7777
}
7878

7979
public static Component getGlowButtonTextComponent(Entity entity) {
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package net.earthcomputer.clientcommands.command;
2+
3+
import com.mojang.brigadier.Command;
4+
import com.mojang.brigadier.CommandDispatcher;
5+
import com.mojang.brigadier.context.CommandContext;
6+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
7+
import com.seedfinding.mcfeature.loot.LootContext;
8+
import com.seedfinding.mcfeature.loot.LootTable;
9+
import com.seedfinding.mcfeature.loot.MCLootTables;
10+
import com.seedfinding.mcfeature.loot.item.ItemStack;
11+
import net.earthcomputer.clientcommands.task.RenderDistanceScanTask;
12+
import net.earthcomputer.clientcommands.task.TaskManager;
13+
import net.earthcomputer.clientcommands.util.SeedfindingUtil;
14+
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
15+
import net.minecraft.SharedConstants;
16+
import net.minecraft.client.Minecraft;
17+
import net.minecraft.client.multiplayer.ClientLevel;
18+
import net.minecraft.client.player.LocalPlayer;
19+
import net.minecraft.core.BlockPos;
20+
import net.minecraft.core.Holder;
21+
import net.minecraft.core.SectionPos;
22+
import net.minecraft.core.component.DataComponents;
23+
import net.minecraft.network.chat.Component;
24+
import net.minecraft.network.chat.MutableComponent;
25+
import net.minecraft.tags.BiomeTags;
26+
import net.minecraft.util.Mth;
27+
import net.minecraft.util.RandomSource;
28+
import net.minecraft.world.effect.MobEffectInstance;
29+
import net.minecraft.world.entity.Entity;
30+
import net.minecraft.world.item.alchemy.PotionContents;
31+
import net.minecraft.world.item.component.ItemLore;
32+
import net.minecraft.world.item.component.SuspiciousStewEffects;
33+
import net.minecraft.world.level.biome.Biome;
34+
import net.minecraft.world.level.biome.Biomes;
35+
import net.minecraft.world.level.block.Blocks;
36+
import net.minecraft.world.level.block.BrushableBlock;
37+
import net.minecraft.world.level.block.state.BlockState;
38+
39+
import java.util.ArrayList;
40+
import java.util.List;
41+
import java.util.function.Supplier;
42+
import java.util.stream.Stream;
43+
44+
import static net.earthcomputer.clientcommands.command.ClientCommandHelper.*;
45+
import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*;
46+
47+
public class PredictBrushablesCommand {
48+
public static final Flag<Boolean> FLAG_KEEP_SEARCHING = Flag.ofFlag("keep-searching").build();
49+
50+
public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
51+
var cpredictbrushables = dispatcher.register(literal("cpredictbrushables")
52+
.executes(PredictBrushablesCommand::predictBrushables));
53+
FLAG_KEEP_SEARCHING.addToCommand(dispatcher, cpredictbrushables, ctx -> true);
54+
}
55+
56+
private static int predictBrushables(CommandContext<FabricClientCommandSource> ctx) throws CommandSyntaxException {
57+
boolean keepSearching = getFlag(ctx, FLAG_KEEP_SEARCHING);
58+
String taskName = TaskManager.addTask("cpredictbrushables", new PredictBrushablesTask(keepSearching));
59+
if (keepSearching) {
60+
sendFeedback(Component.translatable("commands.cpredictbrushables.starting.keepSearching", getCommandTextComponent("commands.client.cancel", "/ctask stop " + taskName)));
61+
} else {
62+
sendFeedback(Component.translatable("commands.cpredictbrushables.starting"));
63+
}
64+
65+
return Command.SINGLE_SUCCESS;
66+
}
67+
68+
private static final class PredictBrushablesTask extends RenderDistanceScanTask {
69+
private boolean found = false;
70+
71+
PredictBrushablesTask(boolean keepSearching) {
72+
super(keepSearching);
73+
}
74+
75+
@Override
76+
protected void scanBlock(Entity cameraEntity, BlockPos pos) {
77+
Minecraft minecraft = Minecraft.getInstance();
78+
LocalPlayer player = minecraft.player;
79+
ClientLevel level = minecraft.level;
80+
assert level != null;
81+
BlockState blockState = level.getBlockState(pos);
82+
83+
// best effort, may be inaccurate
84+
Supplier<LootTable> lootTableSupplier;
85+
long lootSeed;
86+
87+
if (blockState.is(Blocks.SUSPICIOUS_SAND)) {
88+
Holder<Biome> biome = level.getBiome(pos);
89+
if (biome.is(Biomes.DESERT)) {
90+
// either desert well or desert pyramid, check for water
91+
boolean hasWater = Stream.of(pos.atY(pos.getY() + 1), pos.atY(pos.getY() + 2))
92+
.map(level::getBlockState)
93+
.anyMatch(s -> s.is(Blocks.WATER));
94+
lootTableSupplier = hasWater ? MCLootTables.DESERT_WELL_ARCHAEOLOGY : MCLootTables.DESERT_PYRAMID_ARCHAEOLOGY;
95+
lootSeed = pos.asLong();
96+
} else if (biome.is(BiomeTags.HAS_OCEAN_RUIN_WARM)) {
97+
lootTableSupplier = MCLootTables.OCEAN_RUIN_WARM_ARCHAEOLOGY;
98+
RandomSource randomSource = RandomSource.create(Mth.getSeed(pos));
99+
lootSeed = randomSource.nextLong();
100+
} else {
101+
return;
102+
}
103+
} else if (blockState.is(Blocks.SUSPICIOUS_GRAVEL)) {
104+
Holder<Biome> biome = level.getBiome(pos);
105+
if (biome.is(BiomeTags.HAS_OCEAN_RUIN_COLD)) {
106+
lootTableSupplier = MCLootTables.OCEAN_RUIN_COLD_ARCHAEOLOGY;
107+
RandomSource randomSource = RandomSource.create(Mth.getSeed(pos));
108+
lootSeed = randomSource.nextLong();
109+
} else if (biome.is(BiomeTags.HAS_TRAIL_RUINS)) {
110+
// TODO: check for rare or common loot
111+
// Common loot is generated in TRAIL_RUINS_HOUSES_ARCHAEOLOGY,
112+
// TRAIL_RUINS_ROADS_ARCHAEOLOGY and TRAIL_RUINS_TOWER_TOP_ARCHAEOLOGY
113+
// Rare is generated in TRAIL_RUINS_HOUSES_ARCHAEOLOGY
114+
// Ignored for now
115+
return;
116+
} else {
117+
return;
118+
}
119+
} else {
120+
return;
121+
}
122+
123+
LootContext context = new LootContext(lootSeed, SeedfindingUtil.getMCVersion())
124+
.withLuck((int) player.getLuck());
125+
126+
List<ItemStack> items = lootTableSupplier.get().generate(context);
127+
for (ItemStack item : items) {
128+
var mcItemStack = SeedfindingUtil.fromSeedfindingItem(item, level.registryAccess());
129+
mcItemStack.set(DataComponents.LORE, getItemLore(mcItemStack));
130+
ClientCommandHelper.sendFeedback(Component.translatable("commands.cpredictbrushables.foundBrushableBlock", blockState.getBlock().getName(), ClientCommandHelper.getLookCoordsTextComponent(pos), mcItemStack.getDisplayName(), ClientCommandHelper.getGlowButtonTextComponent(pos)));
131+
}
132+
133+
found = true;
134+
}
135+
136+
// use lore to display effects
137+
private static ItemLore getItemLore(net.minecraft.world.item.ItemStack itemStack) {
138+
SuspiciousStewEffects effects = itemStack.get(DataComponents.SUSPICIOUS_STEW_EFFECTS);
139+
if (effects == null) {
140+
return ItemLore.EMPTY;
141+
}
142+
List<Component> components = new ArrayList<>();
143+
for (SuspiciousStewEffects.Entry entry : effects.effects()) {
144+
MobEffectInstance mobEffectInstance = entry.createEffectInstance();
145+
MutableComponent description = PotionContents.getPotionDescription(mobEffectInstance.getEffect(), mobEffectInstance.getAmplifier());
146+
Component line = Component.translatable("commands.cpredictbrushables.stewEffect", description, entry.duration() / SharedConstants.TICKS_PER_SECOND);
147+
components.add(line);
148+
}
149+
return new ItemLore(components);
150+
}
151+
152+
@Override
153+
protected void onBlockStateUpdate(ClientLevel level, BlockPos pos, BlockState oldState, BlockState newState) {
154+
}
155+
156+
@Override
157+
protected boolean canScanChunkSection(Entity cameraEntity, SectionPos pos) {
158+
return hasBlockState(pos, s -> s.getBlock() instanceof BrushableBlock) && super.canScanChunkSection(cameraEntity, pos);
159+
}
160+
161+
@Override
162+
public void onCompleted() {
163+
super.onCompleted();
164+
if (!found) {
165+
sendError(Component.translatable("commands.cpredictbrushables.notFound"));
166+
}
167+
}
168+
}
169+
}

src/main/java/net/earthcomputer/clientcommands/util/SeedfindingUtil.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@
44
import com.google.common.collect.HashBiMap;
55
import com.seedfinding.mcbiome.biome.Biomes;
66
import com.seedfinding.mccore.version.MCVersion;
7+
import com.seedfinding.mcfeature.loot.effect.Effect;
8+
import com.seedfinding.mcfeature.loot.effect.Effects;
79
import net.minecraft.Util;
810
import net.minecraft.core.Holder;
911
import net.minecraft.core.Registry;
1012
import net.minecraft.core.RegistryAccess;
13+
import net.minecraft.core.component.DataComponents;
1114
import net.minecraft.core.registries.BuiltInRegistries;
1215
import net.minecraft.core.registries.Registries;
1316
import net.minecraft.resources.ResourceKey;
1417
import net.minecraft.resources.ResourceLocation;
18+
import net.minecraft.world.effect.MobEffect;
19+
import net.minecraft.world.effect.MobEffects;
1520
import net.minecraft.world.item.Item;
1621
import net.minecraft.world.item.ItemStack;
1722
import net.minecraft.world.item.Items;
23+
import net.minecraft.world.item.component.SuspiciousStewEffects;
1824
import net.minecraft.world.item.enchantment.Enchantment;
1925
import net.minecraft.world.item.enchantment.Enchantments;
2026
import net.minecraft.world.level.Level;
@@ -65,6 +71,40 @@ public class SeedfindingUtil {
6571
map.put(Enchantments.VANISHING_CURSE, "vanishing_curse");
6672
});
6773

74+
private static final BiMap<Holder<MobEffect>, Effect> SEEDFINDING_EFFECTS = Util.make(HashBiMap.create(), map -> {
75+
map.put(MobEffects.SPEED, Effects.MOVEMENT_SPEED);
76+
map.put(MobEffects.SLOWNESS, Effects.MOVEMENT_SLOWDOWN);
77+
map.put(MobEffects.HASTE, Effects.DIG_SPEED);
78+
map.put(MobEffects.MINING_FATIGUE, Effects.DIG_SLOWDOWN);
79+
map.put(MobEffects.STRENGTH, Effects.DAMAGE_BOOST);
80+
map.put(MobEffects.INSTANT_HEALTH, Effects.HEAL);
81+
map.put(MobEffects.INSTANT_DAMAGE, Effects.HARM);
82+
map.put(MobEffects.JUMP_BOOST, Effects.JUMP);
83+
map.put(MobEffects.NAUSEA, Effects.CONFUSION);
84+
map.put(MobEffects.REGENERATION, Effects.REGENERATION);
85+
map.put(MobEffects.RESISTANCE, Effects.DAMAGE_RESISTANCE);
86+
map.put(MobEffects.FIRE_RESISTANCE, Effects.FIRE_RESISTANCE);
87+
map.put(MobEffects.WATER_BREATHING, Effects.WATER_BREATHING);
88+
map.put(MobEffects.INVISIBILITY, Effects.INVISIBILITY);
89+
map.put(MobEffects.BLINDNESS, Effects.BLINDNESS);
90+
map.put(MobEffects.NIGHT_VISION, Effects.NIGHT_VISION);
91+
map.put(MobEffects.HUNGER, Effects.HUNGER);
92+
map.put(MobEffects.WEAKNESS, Effects.WEAKNESS);
93+
map.put(MobEffects.POISON, Effects.POISON);
94+
map.put(MobEffects.WITHER, Effects.WITHER);
95+
map.put(MobEffects.HEALTH_BOOST, Effects.HEALTH_BOOST);
96+
map.put(MobEffects.ABSORPTION, Effects.ABSORPTION);
97+
map.put(MobEffects.SATURATION, Effects.SATURATION);
98+
map.put(MobEffects.GLOWING, Effects.GLOWING);
99+
map.put(MobEffects.LEVITATION, Effects.LEVITATION);
100+
map.put(MobEffects.LUCK, Effects.LUCK);
101+
map.put(MobEffects.UNLUCK, Effects.UNLUCK);
102+
map.put(MobEffects.SLOW_FALLING, Effects.SLOW_FALLING);
103+
map.put(MobEffects.CONDUIT_POWER, Effects.CONDUIT_POWER);
104+
map.put(MobEffects.DOLPHINS_GRACE, Effects.DOLPHINS_GRACE);
105+
map.put(MobEffects.BAD_OMEN, Effects.BAD_OMEN);
106+
});
107+
68108
private SeedfindingUtil() {
69109
}
70110

@@ -101,6 +141,12 @@ public static ItemStack fromSeedfindingItem(com.seedfinding.mcfeature.loot.item.
101141
ret.enchant(enchantment, enchAndLevel.getSecond());
102142
});
103143
}
144+
145+
for (var effectAndDuration : stack.getItem().getEffects()) {
146+
Holder<MobEffect> effectHolder = Objects.requireNonNull(SEEDFINDING_EFFECTS.inverse().get(effectAndDuration.getFirst()), () -> "missing seedfinding effect " + effectAndDuration.getFirst());
147+
SuspiciousStewEffects.Entry entry = new SuspiciousStewEffects.Entry(effectHolder, effectAndDuration.getSecond());
148+
ret.update(DataComponents.SUSPICIOUS_STEW_EFFECTS, SuspiciousStewEffects.EMPTY, entry, SuspiciousStewEffects::withEffectAdded);
149+
}
104150
return ret;
105151
}
106152

src/main/resources/assets/clientcommands/lang/en_us.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@
234234
"commands.cpos.level.the_end": "the End",
235235
"commands.cpos.level.the_nether": "the Nether",
236236

237+
"commands.cpredictbrushables.foundBrushableBlock": "Found %s at %s with item %s %s",
238+
"commands.cpredictbrushables.notFound": "No brushable blocks found",
239+
"commands.cpredictbrushables.starting": "Searching for brushable blocks",
240+
"commands.cpredictbrushables.starting.keepSearching": "Infinitely searching for brushable blocks [%s]",
241+
"commands.cpredictbrushables.stewEffect": "%s (%s seconds)",
242+
237243
"commands.crelog.failed": "Failed to relog",
238244

239245
"commands.crender.entities.success": "Entity rendering rules have been updated",

0 commit comments

Comments
 (0)