Skip to content

Commit 18c9e85

Browse files
Matyrobbrtdesht
authored andcommitted
[1.21] More API improvements (#251)
* More API improvements * Update RouterCompiledEvent.java * Publish sources * Set group and project name for includebuild * Return success when removing
1 parent be1cb04 commit 18c9e85

File tree

6 files changed

+170
-25
lines changed

6 files changed

+170
-25
lines changed

build.gradle

+6-1
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,16 @@ repositories {
5353
}
5454
}
5555

56+
group = project.mod_group_id
57+
5658
base {
5759
archivesName = "${archive_base_name}-${mod_version}+mc${minecraft_version}"
5860
}
5961

60-
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
62+
java {
63+
toolchain.languageVersion = JavaLanguageVersion.of(21)
64+
withSourcesJar()
65+
}
6166

6267
runs {
6368
// applies to all the run configs below

settings.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ pluginManagement {
1212
plugins {
1313
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
1414
}
15+
16+
rootProject.name = 'modular-routers'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package me.desht.modularrouters.api.event;
2+
3+
import me.desht.modularrouters.item.module.TargetedModule;
4+
import net.minecraft.world.item.ItemStack;
5+
import net.minecraft.world.item.context.UseOnContext;
6+
import net.neoforged.bus.api.Event;
7+
import org.jetbrains.annotations.ApiStatus;
8+
9+
/**
10+
* Event fired when a player attempts to add a new target to a module.
11+
* <p>
12+
* This event can be used to allow a module to target blocks it otherwise couldn't in conjunction with {@link ExecuteModuleEvent}.
13+
*/
14+
public final class AddModuleTargetEvent extends Event {
15+
private final TargetedModule item;
16+
private final UseOnContext context;
17+
private boolean valid;
18+
19+
@ApiStatus.Internal
20+
public AddModuleTargetEvent(TargetedModule item, UseOnContext context, boolean valid) {
21+
this.item = item;
22+
this.context = context;
23+
this.valid = valid;
24+
}
25+
26+
/**
27+
* {@return the module type}
28+
*/
29+
public TargetedModule getModuleType() {
30+
return item;
31+
}
32+
33+
/**
34+
* {@return the module stack}
35+
*/
36+
public ItemStack getModule() {
37+
return context.getItemInHand();
38+
}
39+
40+
/**
41+
* {@return the context of the interaction}
42+
*/
43+
public UseOnContext getContext() {
44+
return context;
45+
}
46+
47+
/**
48+
* {@return whether the targeted block is valid and may be selected}
49+
*/
50+
public boolean isValid() {
51+
return valid;
52+
}
53+
54+
/**
55+
* Making the target {@code valid} allows the player to select the block and the router to process it.
56+
* @see ExecuteModuleEvent
57+
*/
58+
public void setValid(boolean valid) {
59+
this.valid = valid;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package me.desht.modularrouters.api.event;
2+
3+
import me.desht.modularrouters.block.tile.ModularRouterBlockEntity;
4+
import net.neoforged.bus.api.Event;
5+
import org.jetbrains.annotations.ApiStatus;
6+
7+
/**
8+
* Called when a router is (re)compiled. Can be used to update state that's
9+
* independent of an upgrade or module and must be refreshed even when the upgrade isn't present.
10+
*
11+
* @see Upgrades
12+
* @see Modules
13+
*/
14+
public abstract sealed class RouterCompiledEvent extends Event {
15+
private final ModularRouterBlockEntity router;
16+
17+
@ApiStatus.Internal
18+
public RouterCompiledEvent(ModularRouterBlockEntity router) {
19+
this.router = router;
20+
}
21+
22+
/**
23+
* {@return the router that is being compiled}
24+
*/
25+
public ModularRouterBlockEntity getRouter() {
26+
return router;
27+
}
28+
29+
/**
30+
* Called when a router (re)compiles its upgrades. This <strong>will</strong> be called on
31+
* the client-side too when the GUI is opened.
32+
*/
33+
public final static class Upgrades extends RouterCompiledEvent {
34+
@ApiStatus.Internal
35+
public Upgrades(ModularRouterBlockEntity router) {
36+
super(router);
37+
}
38+
}
39+
40+
/**
41+
* Called when a router (re)compiles its modules.
42+
*/
43+
public final static class Modules extends RouterCompiledEvent {
44+
public Modules(ModularRouterBlockEntity router) {
45+
super(router);
46+
}
47+
}
48+
}

src/main/java/me/desht/modularrouters/block/tile/ModularRouterBlockEntity.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.Sets;
44
import com.mojang.authlib.GameProfile;
55
import me.desht.modularrouters.ModularRouters;
6+
import me.desht.modularrouters.api.event.RouterCompiledEvent;
67
import me.desht.modularrouters.block.CamouflageableBlock;
78
import me.desht.modularrouters.block.ModularRouterBlock;
89
import me.desht.modularrouters.config.ConfigHolder;
@@ -592,6 +593,7 @@ private void compileModules() {
592593
if (cms.careAboutItemAttributes()) careAboutItemAttributes = true;
593594
}
594595
}
596+
NeoForge.EVENT_BUS.post(new RouterCompiledEvent.Modules(this));
595597
}
596598
}
597599

@@ -626,6 +628,8 @@ private void compileUpgrades() {
626628
}
627629
notifyWatchingPlayers();
628630
}
631+
632+
NeoForge.EVENT_BUS.post(new RouterCompiledEvent.Upgrades(this));
629633
}
630634
}
631635

@@ -1063,7 +1067,7 @@ public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
10631067
if (inSlot.isEmpty() || slot == i) continue;
10641068
// can't have the same upgrade in more than one slot
10651069
// incompatible upgrades can't coexist
1066-
if (stack.getItem() == inSlot.getItem() || !((UpgradeItem) inSlot.getItem()).isCompatibleWith(item)) {
1070+
if (stack.getItem() == inSlot.getItem() || !((UpgradeItem) inSlot.getItem()).isCompatibleWith(item) || !item.isCompatibleWith((UpgradeItem) inSlot.getItem())) {
10671071
return false;
10681072
}
10691073
}

src/main/java/me/desht/modularrouters/item/module/TargetedModule.java

+48-23
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.Sets;
44
import me.desht.modularrouters.ModularRouters;
5+
import me.desht.modularrouters.api.event.AddModuleTargetEvent;
56
import me.desht.modularrouters.block.tile.ModularRouterBlockEntity;
67
import me.desht.modularrouters.client.util.ClientUtil;
78
import me.desht.modularrouters.config.ConfigHolder;
@@ -31,6 +32,8 @@
3132
import net.minecraft.world.item.ItemStack;
3233
import net.minecraft.world.item.context.UseOnContext;
3334
import net.minecraft.world.level.Level;
35+
import net.neoforged.neoforge.common.NeoForge;
36+
import org.jetbrains.annotations.ApiStatus;
3437

3538
import java.util.List;
3639
import java.util.Set;
@@ -50,25 +53,37 @@ protected TargetedModule(Item.Properties props, BiFunction<ModularRouterBlockEnt
5053
@Override
5154
public InteractionResult useOn(UseOnContext ctx) {
5255
if (ctx.getPlayer() != null && ctx.getPlayer().isShiftKeyDown()) {
53-
if (isValidTarget(ctx)) {
54-
if (getMaxTargets() == 1) {
56+
if (getMaxTargets() == 1) {
57+
if (canSelectTarget(ctx)) {
5558
handleSingleTarget(ctx.getItemInHand(), ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
56-
} else {
57-
handleMultiTarget(ctx.getItemInHand(), ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
59+
return InteractionResult.SUCCESS;
5860
}
59-
return InteractionResult.SUCCESS;
6061
} else {
61-
return super.useOn(ctx);
62+
var res = handleMultiTarget(ctx.getItemInHand(), ctx, ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
63+
if (res == InteractionResult.PASS) return res;
6264
}
65+
return super.useOn(ctx);
6366
} else {
6467
return InteractionResult.PASS;
6568
}
6669
}
6770

71+
/**
72+
* <strong>Override-only</strong> method that checks whether this module can have the block of the context selected.
73+
* <p>Note: it is not guaranteed that the module will only have blocks that pass this test selected, see {@link AddModuleTargetEvent}.
74+
*/
75+
@ApiStatus.OverrideOnly
6876
protected boolean isValidTarget(UseOnContext ctx) {
6977
return InventoryUtils.getInventory(ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace()).isPresent();
7078
}
7179

80+
/**
81+
* Checks if the module can select the target of the {@code context}.
82+
*/
83+
public boolean canSelectTarget(UseOnContext context) {
84+
return NeoForge.EVENT_BUS.post(new AddModuleTargetEvent(this, context, isValidTarget(context))).isValid();
85+
}
86+
7287
private void handleSingleTarget(ItemStack stack, Player player, Level world, BlockPos pos, Direction face) {
7388
if (!world.isClientSide) {
7489
setTarget(stack, world, pos, face);
@@ -82,34 +97,44 @@ private void handleSingleTarget(ItemStack stack, Player player, Level world, Blo
8297
}
8398
}
8499

85-
private void handleMultiTarget(ItemStack stack, Player player, Level world, BlockPos pos, Direction face) {
86-
if (!world.isClientSide) {
87-
boolean removing = false;
88-
String invName = BlockUtil.getBlockName(world, pos);
89-
GlobalPos gPos = MiscUtil.makeGlobalPos(world, pos);
90-
ModuleTarget tgt = new ModuleTarget(gPos, face, invName);
91-
Set<ModuleTarget> targets = getTargets(stack, true);
92-
if (targets.contains(tgt)) {
93-
targets.remove(tgt);
94-
removing = true;
95-
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetRemoved", targets.size(), getMaxTargets())
96-
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);
97-
} else if (targets.size() < getMaxTargets()) {
100+
private InteractionResult handleMultiTarget(ItemStack stack, UseOnContext context, Player player, Level world, BlockPos pos, Direction face) {
101+
Set<ModuleTarget> targets = getTargets(stack, !world.isClientSide);
102+
String invName = BlockUtil.getBlockName(world, pos);
103+
GlobalPos gPos = MiscUtil.makeGlobalPos(world, pos);
104+
ModuleTarget tgt = new ModuleTarget(gPos, face, invName);
105+
106+
// Allow removing targets without checking if they're valid
107+
if (targets.contains(tgt)) {
108+
if (world.isClientSide) return InteractionResult.SUCCESS;
109+
targets.remove(tgt);
110+
111+
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetRemoved", targets.size(), getMaxTargets())
112+
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);
113+
world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS, ConfigHolder.common.sound.bleepVolume.get().floatValue(), 1.1f);
114+
setTargetList(stack, targets);
115+
return InteractionResult.SUCCESS;
116+
}
117+
118+
if (canSelectTarget(context)) {
119+
if (world.isClientSide) return InteractionResult.SUCCESS;
120+
if (targets.size() < getMaxTargets()) {
98121
targets.add(tgt);
99122
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetAdded", targets.size(), getMaxTargets())
100123
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);
124+
125+
world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS,
126+
ConfigHolder.common.sound.bleepVolume.get().floatValue(), 1.3f);
127+
setTargetList(stack, targets);
101128
} else {
102129
// too many targets already
103130
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.tooManyTargets", getMaxTargets())
104131
.withStyle(ChatFormatting.RED), true);
105132
world.playSound(null, pos, ModSounds.ERROR.get(), SoundSource.BLOCKS, 1.0f, 1.3f);
106-
return;
107133
}
108134

109-
world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS,
110-
ConfigHolder.common.sound.bleepVolume.get().floatValue(), removing ? 1.1f : 1.3f);
111-
setTargetList(stack, targets);
135+
return InteractionResult.SUCCESS;
112136
}
137+
return InteractionResult.PASS;
113138
}
114139

115140

0 commit comments

Comments
 (0)