Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement #474 and add a 'multitool' item type #681

Open
wants to merge 7 commits into
base: 1902
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package dev.latvian.mods.kubejs.item.custom;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import dev.latvian.mods.kubejs.item.MutableToolTier;
import dev.latvian.mods.kubejs.registry.KubeJSRegistries;
import dev.latvian.mods.kubejs.typings.Info;
import dev.latvian.mods.kubejs.typings.Param;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.TagKey;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.item.DiggerItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static java.math.RoundingMode.CEILING;

public class MultitoolItemJS extends DiggerItem {
public static class Builder extends HandheldItemBuilder {
protected boolean isAxe = false, isHoe = false, isPickaxe = false, isShovel = false;
protected final List<Float> speedValues = new ArrayList<>(5);
protected final List<Float> attackValues = new ArrayList<>(5);
protected final Set<TagKey<Block>> mineableTags = new HashSet<>();
public Builder(ResourceLocation i) {
super(i, 0, 0);
}
@Info(value = """
Adds a tool to the multi-tool.

Valid tool types include: 'axe', 'hoe', 'pickaxe', and 'shovel'.
AnAwesomGuy marked this conversation as resolved.
Show resolved Hide resolved
""", params =
@Param(name = "tool", value = "The name of the tool to add to the multi-tool. Will error if it is an unknown tool type."))
public Builder tool(String tool) {
// maybe swords and shears (after #673 is merged)?
return switch (tool) {
default -> throw new IllegalArgumentException("Unknown tool type '" + tool +
"', valid tool types are: 'axe', 'hoe', 'pickaxe', and 'shovel'!");
case "axe" -> {
isAxe = true;
yield addValues(6, -3.1f, BlockTags.MINEABLE_WITH_AXE);
}
case "hoe" -> {
isHoe = true;
yield addValues(-2, -1, BlockTags.MINEABLE_WITH_HOE);
}
case "pickaxe" -> {
isPickaxe = true;
yield addValues(1, -2.8f, BlockTags.MINEABLE_WITH_PICKAXE);
}
case "shovel" -> {
isShovel = true;
yield addValues(1.5f, -3, BlockTags.MINEABLE_WITH_SHOVEL);
}
};
}
AnAwesomGuy marked this conversation as resolved.
Show resolved Hide resolved
protected Builder addValues(float attack, float speed, @Nullable TagKey<Block> tag) {
attackValues.add(attack);
speedValues.add(speed);
if (tag != null)
mineableTags.add(tag);
return this;
}
@Override
public Builder attackDamageBaseline(float f) {
attackValues.clear();
attackValues.add(f);
return this;
}
@Override
public Builder speedBaseline(float f) {
speedValues.clear();
speedValues.add(f);
return this;
}
protected void setValues() {
// TOD0: find a way to make this better / more efficient
// i hate floating-point jank
BigDecimal attack = new BigDecimal("0"), speed = attack;
for (final float f : attackValues) {
attack = attack.add(new BigDecimal(Float.toString(f)));
}
attack = attack.divide(new BigDecimal(Integer.toString(attackValues.size())), 3, CEILING);
attackDamageBaseline = attack.add(attack.multiply(BigDecimal.valueOf(.08)))
.setScale(1, CEILING).floatValue();

for (final float f : speedValues) {
speed = speed.add(new BigDecimal(Float.toString(f)));
}
speed = speed.divide(new BigDecimal(Integer.toString(speedValues.size())), 3, CEILING);
speedBaseline = speed.add(speed.multiply(BigDecimal.valueOf(.05)))
.setScale(1, CEILING).floatValue();
}
@Override
public Item createObject() {
setValues();
return new MultitoolItemJS(attackDamageBaseline, speedBaseline, toolTier, createItemProperties(), this);
}
}
public final Set<TagKey<Block>> mineableTags;
protected boolean isAxe, isHoe, isPickaxe, isShovel;
private final Multimap<ResourceLocation, AttributeModifier> attributes;
private boolean modified = false;
public MultitoolItemJS(float attack, float speed, MutableToolTier tier, Properties properties, Builder builder) {
super(attack, speed, tier, null, properties);
defaultModifiers = ArrayListMultimap.create(defaultModifiers);
mineableTags = Set.copyOf(builder.mineableTags);
isAxe = builder.isAxe;
isHoe = builder.isHoe;
isPickaxe = builder.isPickaxe;
isShovel = builder.isShovel;
attributes = builder.attributes;
}
public boolean isAxe() {
return isAxe;
}
public boolean isHoe() {
return isHoe;
}
public boolean isPickaxe() {
return isPickaxe;
}
public boolean isShovel() {
return isShovel;
}
@Override
public float getDestroySpeed(ItemStack itemStack, BlockState blockState) {
return isInMineables(blockState) ? speed : 1f;
}
@Override
public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot equipmentSlot) {
if (!modified) {
modified = true;
attributes.forEach((r, m) -> defaultModifiers.put(KubeJSRegistries.attributes().get(r), m));
}
return super.getDefaultAttributeModifiers(equipmentSlot);
}
@Override
// right-clicking on dirt will till, unless sneaking, then it will turn it into a path
AnAwesomGuy marked this conversation as resolved.
Show resolved Hide resolved
public InteractionResult useOn(UseOnContext ctx) {
return (isAxe && Items.IRON_AXE.useOn(ctx) != InteractionResult.PASS) ||
(isShovel && (!isHoe || Optional.ofNullable(ctx.getPlayer())
.map(Entity::isCrouching).orElse(false)) && // player sneaking check
Items.IRON_SHOVEL.useOn(ctx) != InteractionResult.PASS) ||
(isHoe && Items.IRON_HOE.useOn(ctx) != InteractionResult.PASS) ||
(isPickaxe && Items.IRON_HOE.useOn(ctx) != InteractionResult.PASS) ?
InteractionResult.sidedSuccess(ctx.getLevel().isClientSide) : InteractionResult.PASS;
}
@Override
public boolean isCorrectToolForDrops(BlockState state) {
final int i = tier.getLevel();
if ((i < 3 && state.is(BlockTags.NEEDS_DIAMOND_TOOL)) ||
(i < 2 && state.is(BlockTags.NEEDS_IRON_TOOL)) ||
(i < 1 && state.is(BlockTags.NEEDS_STONE_TOOL))) return false;
AnAwesomGuy marked this conversation as resolved.
Show resolved Hide resolved

return isInMineables(state);
}
private boolean isInMineables(BlockState state) {
for (TagKey<Block> tag : mineableTags)
if (state.is(tag)) return true;
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package dev.latvian.mods.kubejs.fabric;

import dev.latvian.mods.kubejs.BuiltinKubeJSPlugin;
import dev.latvian.mods.kubejs.item.custom.MultitoolItemJS;
import dev.latvian.mods.kubejs.registry.RegistryInfo;
import dev.latvian.mods.kubejs.script.ScriptType;
import dev.latvian.mods.kubejs.util.ClassFilter;

public class BuiltinKubeJSFabricPlugin extends BuiltinKubeJSPlugin {
@Override
public void init() {
super.init();

RegistryInfo.ITEM.addType("multitool", MultitoolItemJS.Builder.class, MultitoolItemJS.Builder::new);
AnAwesomGuy marked this conversation as resolved.
Show resolved Hide resolved
}
@Override
public void registerClasses(ScriptType type, ClassFilter filter) {
super.registerClasses(type, filter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import dev.latvian.mods.kubejs.BuiltinKubeJSPlugin;
import dev.latvian.mods.kubejs.fluid.FluidStackJS;
import dev.latvian.mods.kubejs.integration.forge.jei.JEIEvents;
import dev.latvian.mods.kubejs.item.forge.custom.MultitoolItemJSForge;
import dev.latvian.mods.kubejs.registry.RegistryInfo;
import dev.latvian.mods.kubejs.script.BindingsEvent;
import dev.latvian.mods.kubejs.script.ScriptType;
import dev.latvian.mods.kubejs.util.ClassFilter;
Expand All @@ -14,6 +16,12 @@
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

public class BuiltinKubeJSForgePlugin extends BuiltinKubeJSPlugin {
@Override
public void init() {
super.init();

RegistryInfo.ITEM.addType("multitool", MultitoolItemJSForge.Builder.class, MultitoolItemJSForge.Builder::new);
}
@Override
public void registerEvents() {
super.registerEvents();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dev.latvian.mods.kubejs.item.forge.custom;

import dev.latvian.mods.kubejs.item.MutableToolTier;
import dev.latvian.mods.kubejs.item.custom.MultitoolItemJS;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.ToolAction;
import net.minecraftforge.common.ToolActions;

public class MultitoolItemJSForge extends MultitoolItemJS {
public static class Builder extends MultitoolItemJS.Builder {
public Builder(ResourceLocation i) {
super(i);
}
@Override
public Item createObject() {
setValues();
return new MultitoolItemJSForge(attackDamageBaseline, speedBaseline, toolTier, createItemProperties(), this);
}
}
public MultitoolItemJSForge(float attack, float speed, MutableToolTier tier, Properties properties, Builder builder) {
super(attack, speed, tier, properties, builder);
}
@Override
public boolean canPerformAction(ItemStack stack, ToolAction toolAction) {
return super.canPerformAction(stack, toolAction) ||
((isAxe && ToolActions.DEFAULT_AXE_ACTIONS.contains(toolAction)) ||
(isHoe && ToolActions.DEFAULT_HOE_ACTIONS.contains(toolAction)) ||
(isPickaxe && ToolActions.DEFAULT_PICKAXE_ACTIONS.contains(toolAction)) ||
(isShovel && ToolActions.DEFAULT_SHOVEL_ACTIONS.contains(toolAction)));
}
}