Skip to content

Commit

Permalink
[1.21] More API improvements (#251)
Browse files Browse the repository at this point in the history
* More API improvements

* Update RouterCompiledEvent.java

* Publish sources

* Set group and project name for includebuild

* Return success when removing
  • Loading branch information
Matyrobbrt authored Nov 17, 2024
1 parent 1f72de9 commit 49aa070
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 25 deletions.
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,16 @@ repositories {
}
}

group = project.mod_group_id

base {
archivesName = "${archive_base_name}-${mod_version}+mc${minecraft_version}"
}

java.toolchain.languageVersion = JavaLanguageVersion.of(21)
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
withSourcesJar()
}

runs {
// applies to all the run configs below
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ pluginManagement {
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
}

rootProject.name = 'modular-routers'
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package me.desht.modularrouters.api.event;

import me.desht.modularrouters.item.module.TargetedModule;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.neoforged.bus.api.Event;
import org.jetbrains.annotations.ApiStatus;

/**
* Event fired when a player attempts to add a new target to a module.
* <p>
* This event can be used to allow a module to target blocks it otherwise couldn't in conjunction with {@link ExecuteModuleEvent}.
*/
public final class AddModuleTargetEvent extends Event {
private final TargetedModule item;
private final UseOnContext context;
private boolean valid;

@ApiStatus.Internal
public AddModuleTargetEvent(TargetedModule item, UseOnContext context, boolean valid) {
this.item = item;
this.context = context;
this.valid = valid;
}

/**
* {@return the module type}
*/
public TargetedModule getModuleType() {
return item;
}

/**
* {@return the module stack}
*/
public ItemStack getModule() {
return context.getItemInHand();
}

/**
* {@return the context of the interaction}
*/
public UseOnContext getContext() {
return context;
}

/**
* {@return whether the targeted block is valid and may be selected}
*/
public boolean isValid() {
return valid;
}

/**
* Making the target {@code valid} allows the player to select the block and the router to process it.
* @see ExecuteModuleEvent
*/
public void setValid(boolean valid) {
this.valid = valid;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package me.desht.modularrouters.api.event;

import me.desht.modularrouters.block.tile.ModularRouterBlockEntity;
import net.neoforged.bus.api.Event;
import org.jetbrains.annotations.ApiStatus;

/**
* Called when a router is (re)compiled. Can be used to update state that's
* independent of an upgrade or module and must be refreshed even when the upgrade isn't present.
*
* @see Upgrades
* @see Modules
*/
public abstract sealed class RouterCompiledEvent extends Event {
private final ModularRouterBlockEntity router;

@ApiStatus.Internal
public RouterCompiledEvent(ModularRouterBlockEntity router) {
this.router = router;
}

/**
* {@return the router that is being compiled}
*/
public ModularRouterBlockEntity getRouter() {
return router;
}

/**
* Called when a router (re)compiles its upgrades. This <strong>will</strong> be called on
* the client-side too when the GUI is opened.
*/
public final static class Upgrades extends RouterCompiledEvent {
@ApiStatus.Internal
public Upgrades(ModularRouterBlockEntity router) {
super(router);
}
}

/**
* Called when a router (re)compiles its modules.
*/
public final static class Modules extends RouterCompiledEvent {
public Modules(ModularRouterBlockEntity router) {
super(router);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.collect.Sets;
import com.mojang.authlib.GameProfile;
import me.desht.modularrouters.ModularRouters;
import me.desht.modularrouters.api.event.RouterCompiledEvent;
import me.desht.modularrouters.block.CamouflageableBlock;
import me.desht.modularrouters.block.ModularRouterBlock;
import me.desht.modularrouters.config.ConfigHolder;
Expand Down Expand Up @@ -604,6 +605,7 @@ private void compileModules() {
if (cms.careAboutItemAttributes()) careAboutItemAttributes = true;
}
}
NeoForge.EVENT_BUS.post(new RouterCompiledEvent.Modules(this));
}
}

Expand Down Expand Up @@ -638,6 +640,8 @@ private void compileUpgrades() {
}
notifyWatchingPlayers();
}

NeoForge.EVENT_BUS.post(new RouterCompiledEvent.Upgrades(this));
}
}

Expand Down Expand Up @@ -1075,7 +1079,7 @@ public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
if (inSlot.isEmpty() || slot == i) continue;
// can't have the same upgrade in more than one slot
// incompatible upgrades can't coexist
if (stack.getItem() == inSlot.getItem() || !((UpgradeItem) inSlot.getItem()).isCompatibleWith(item)) {
if (stack.getItem() == inSlot.getItem() || !((UpgradeItem) inSlot.getItem()).isCompatibleWith(item) || !item.isCompatibleWith((UpgradeItem) inSlot.getItem())) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.common.collect.Sets;
import me.desht.modularrouters.ModularRouters;
import me.desht.modularrouters.api.event.AddModuleTargetEvent;
import me.desht.modularrouters.block.tile.ModularRouterBlockEntity;
import me.desht.modularrouters.client.util.ClientUtil;
import me.desht.modularrouters.config.ConfigHolder;
Expand Down Expand Up @@ -32,6 +33,8 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.neoforged.neoforge.common.NeoForge;
import org.jetbrains.annotations.ApiStatus;

import java.util.List;
import java.util.Set;
Expand All @@ -51,25 +54,37 @@ protected TargetedModule(Item.Properties props, BiFunction<ModularRouterBlockEnt
@Override
public InteractionResult useOn(UseOnContext ctx) {
if (ctx.getPlayer() != null && ctx.getPlayer().isShiftKeyDown()) {
if (isValidTarget(ctx)) {
if (getMaxTargets() == 1) {
if (getMaxTargets() == 1) {
if (canSelectTarget(ctx)) {
handleSingleTarget(ctx.getItemInHand(), ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
} else {
handleMultiTarget(ctx.getItemInHand(), ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
return InteractionResult.SUCCESS;
}
return InteractionResult.SUCCESS;
} else {
return super.useOn(ctx);
var res = handleMultiTarget(ctx.getItemInHand(), ctx, ctx.getPlayer(), ctx.getLevel(), ctx.getClickedPos(), ctx.getClickedFace());
if (res == InteractionResult.PASS) return res;
}
return super.useOn(ctx);
} else {
return InteractionResult.PASS;
}
}

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

/**
* Checks if the module can select the target of the {@code context}.
*/
public boolean canSelectTarget(UseOnContext context) {
return NeoForge.EVENT_BUS.post(new AddModuleTargetEvent(this, context, isValidTarget(context))).isValid();
}

private void handleSingleTarget(ItemStack stack, Player player, Level world, BlockPos pos, Direction face) {
if (!world.isClientSide) {
setTarget(stack, world, pos, face);
Expand All @@ -83,34 +98,44 @@ private void handleSingleTarget(ItemStack stack, Player player, Level world, Blo
}
}

private void handleMultiTarget(ItemStack stack, Player player, Level world, BlockPos pos, Direction face) {
if (!world.isClientSide) {
boolean removing = false;
String invName = BlockUtil.getBlockName(world, pos);
GlobalPos gPos = MiscUtil.makeGlobalPos(world, pos);
ModuleTarget tgt = new ModuleTarget(gPos, face, invName);
Set<ModuleTarget> targets = getTargets(stack, true);
if (targets.contains(tgt)) {
targets.remove(tgt);
removing = true;
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetRemoved", targets.size(), getMaxTargets())
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);
} else if (targets.size() < getMaxTargets()) {
private InteractionResult handleMultiTarget(ItemStack stack, UseOnContext context, Player player, Level world, BlockPos pos, Direction face) {
Set<ModuleTarget> targets = getTargets(stack, !world.isClientSide);
String invName = BlockUtil.getBlockName(world, pos);
GlobalPos gPos = MiscUtil.makeGlobalPos(world, pos);
ModuleTarget tgt = new ModuleTarget(gPos, face, invName);

// Allow removing targets without checking if they're valid
if (targets.contains(tgt)) {
if (world.isClientSide) return InteractionResult.SUCCESS;
targets.remove(tgt);

player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetRemoved", targets.size(), getMaxTargets())
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);
world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS, ConfigHolder.common.sound.bleepVolume.get().floatValue(), 1.1f);
setTargetList(stack, targets);
return InteractionResult.SUCCESS;
}

if (canSelectTarget(context)) {
if (world.isClientSide) return InteractionResult.SUCCESS;
if (targets.size() < getMaxTargets()) {
targets.add(tgt);
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.targetAdded", targets.size(), getMaxTargets())
.append(tgt.getTextComponent()).withStyle(ChatFormatting.YELLOW), true);

world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS,
ConfigHolder.common.sound.bleepVolume.get().floatValue(), 1.3f);
setTargetList(stack, targets);
} else {
// too many targets already
player.displayClientMessage(Component.translatable("modularrouters.chatText.misc.tooManyTargets", getMaxTargets())
.withStyle(ChatFormatting.RED), true);
world.playSound(null, pos, ModSounds.ERROR.get(), SoundSource.BLOCKS, 1.0f, 1.3f);
return;
}

world.playSound(null, pos, ModSounds.SUCCESS.get(), SoundSource.BLOCKS,
ConfigHolder.common.sound.bleepVolume.get().floatValue(), removing ? 1.1f : 1.3f);
setTargetList(stack, targets);
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}


Expand Down

0 comments on commit 49aa070

Please sign in to comment.