Skip to content

Commit

Permalink
Add Jade integration for item pipe contents
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n committed Mar 8, 2024
1 parent 7256f24 commit 2cf9f34
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 14 deletions.
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ repositories {
includeGroup "mezz.jei"
}
}
maven {
url "https://www.cursemaven.com"
content {
includeGroup "curse.maven"
}
}
}

dependencies {
Expand Down Expand Up @@ -79,7 +85,7 @@ dependencies {
throw new GradleException("Invalid runtime_itemlist_mod value: " + project.runtime_itemlist_mod)
}

runtimeOnly("mcp.mobius.waila:wthit:neo-${project.wthit_version}")
implementation("curse.maven:jade-324717:${project.jade_file_id}")
}

processResources {
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ neogradle.subsystems.parchment.mappingsVersion=2023.12.26-nightly-SNAPSHOT

# In-dev runtime mods
rei_version=14.0.688
wthit_version=10.1.0

jei_minecraft_version=1.20.4
jei_version=17.0.0.37
Expand All @@ -40,3 +39,5 @@ emi_version=1.1.0
# Set to emi, jei, or rei to pick which tooltip mod gets picked at runtime
# for the dev environment.
runtime_itemlist_mod=emi

jade_file_id=5109393
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Modern Dynamics
* Copyright (C) 2021 shartte & Technici4n
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.technici4n.moderndynamics.compat.jade;

import dev.technici4n.moderndynamics.attachment.attached.ItemAttachedIo;
import dev.technici4n.moderndynamics.network.item.ItemHost;
import dev.technici4n.moderndynamics.pipe.PipeBlockEntity;
import dev.technici4n.moderndynamics.util.ItemVariant;
import dev.technici4n.moderndynamics.util.MdId;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import snownee.jade.api.Accessor;
import snownee.jade.api.view.ClientViewGroup;
import snownee.jade.api.view.IClientExtensionProvider;
import snownee.jade.api.view.IServerExtensionProvider;
import snownee.jade.api.view.ItemView;
import snownee.jade.api.view.ViewGroup;

public enum ItemPipeServerProvider implements IServerExtensionProvider<PipeBlockEntity, ItemStack>, IClientExtensionProvider<ItemStack, ItemView> {
INSTANCE;

@Override
public ResourceLocation getUid() {
return MdId.of("item_pipe");
}

@Override
public @Nullable List<ViewGroup<ItemStack>> getGroups(Accessor<?> accessor, PipeBlockEntity pipe) {
// Send attachment data here
var itemHost = pipe.findHost(ItemHost.class);
if (itemHost == null) {
return null;
}

List<ViewGroup<ItemStack>> groups = new ArrayList<>();

for (var side : Direction.values()) {
if (pipe.getAttachment(side) instanceof ItemAttachedIo io) {
if (io.isStuffed()) {
var group = new ViewGroup<ItemStack>(new ArrayList<>());
group.views.addAll(variantMapToStacks(io.getStuffedItems()));
group.id = "stuffed_" + side.getName();
groups.add(group);
}
}
}

// Always add a dummy group.
// We need to run on the client side to add client traveling items on the client side,
// even if the server doesn't provide any stack.
var dummyGroup = new ViewGroup<ItemStack>(new ArrayList<>());
dummyGroup.views.add(ItemStack.EMPTY);
dummyGroup.id = "dummy";
groups.add(dummyGroup);

return groups;
}

private static Collection<ItemStack> variantMapToStacks(Map<ItemVariant, Integer> map) {
List<ItemStack> stacks = new ArrayList<>();
for (var entry : map.entrySet()) {
stacks.add(entry.getKey().toStack(entry.getValue()));
}
stacks.sort(Comparator.comparingInt(ItemStack::getCount).reversed());
return stacks;
}

@Override
public List<ClientViewGroup<ItemView>> getClientGroups(Accessor<?> accessor, List<ViewGroup<ItemStack>> serverGroups) {
if (!(accessor.getTarget() instanceof PipeBlockEntity pipe)) {
return List.of();
}

List<ClientViewGroup<ItemView>> clientGroups = new ArrayList<>();

// Stuffed items
var posInBlock = pipe.getPosInBlock(accessor.getHitResult());
var hitAttachmentSide = pipe.hitTestAttachments(posInBlock);
if (hitAttachmentSide != null) {
var attachmentItem = pipe.getAttachmentItem(hitAttachmentSide);
if (attachmentItem != null) {
// Find corresponding server group
serverGroups.stream()
.filter(vg -> vg.id != null && vg.id.equals("stuffed_" + hitAttachmentSide.getName()))
.findFirst()
.ifPresent(group -> {
var clientGroup = new ClientViewGroup<ItemView>(new ArrayList<>());
for (var stack : group.views) {
clientGroup.views.add(new ItemView(stack));
}
clientGroup.title = Component.translatable("gui.moderndynamics.tooltip.stuffed", attachmentItem.getDescription())
.withStyle(Style.EMPTY.withColor(ChatFormatting.RED).withBold(true));
clientGroups.add(clientGroup);
});
}
}

// Pipe contents, only if nothing is stuffed
if (!clientGroups.isEmpty()) {
return clientGroups;
}
for (var host : pipe.getHosts()) {
if (host instanceof ItemHost itemHost) {
Map<ItemVariant, Integer> items = new HashMap<>();
for (var item : itemHost.getClientTravelingItems()) {
items.merge(item.variant(), item.amount(), Integer::sum);
}

var clientGroup = new ClientViewGroup<ItemView>(new ArrayList<>());
for (var stack : variantMapToStacks(items)) {
clientGroup.views.add(new ItemView(stack));
}
if (!clientGroup.views.isEmpty()) {
clientGroups.add(clientGroup);
}
}
}

return clientGroups;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Modern Dynamics
* Copyright (C) 2021 shartte & Technici4n
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package dev.technici4n.moderndynamics.compat.jade;

import dev.technici4n.moderndynamics.pipe.PipeBlockEntity;
import snownee.jade.api.IWailaClientRegistration;
import snownee.jade.api.IWailaCommonRegistration;
import snownee.jade.api.IWailaPlugin;
import snownee.jade.api.WailaPlugin;

@WailaPlugin
public class MdJadePlugin implements IWailaPlugin {
@Override
public void register(IWailaCommonRegistration registration) {
registration.registerItemStorage(ItemPipeServerProvider.INSTANCE, PipeBlockEntity.class);
}

@Override
public void registerClient(IWailaClientRegistration registration) {
registration.registerItemStorageClient(ItemPipeServerProvider.INSTANCE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.jetbrains.annotations.Nullable;

public record PipeModelData(byte pipeConnections, byte inventoryConnections,
AttachmentModelData @Nullable [] attachments) {
@Nullable AttachmentModelData[] attachments) {

public static ModelProperty<PipeModelData> PIPE_DATA = new ModelProperty<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ public void writeClientNbt(CompoundTag tag) {
CompoundTag compound = new CompoundTag();
compound.putInt("id", travelingItem.id);
compound.put("v", travelingItem.variant.toNbt());
compound.putLong("a", travelingItem.amount);
compound.putInt("a", travelingItem.amount);
compound.putDouble("td", travelingItem.getPathLength() - 1);
compound.putDouble("d", travelingItem.traveledDistance);
int currentBlock = (int) Math.floor(travelingItem.traveledDistance);
Expand All @@ -525,7 +525,7 @@ public void readClientNbt(CompoundTag tag) {
var newItem = new ClientTravelingItem(
compound.getInt("id"),
ItemVariant.fromNbt(compound.getCompound("v")),
compound.getLong("a"),
compound.getInt("a"),
compound.getDouble("td"),
compound.getDouble("d"),
Direction.from3DDataValue(compound.getByte("in")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
public final class ClientTravelingItem {
public final int id;
private final ItemVariant variant;
private final long amount;
private final int amount;
public final double totalPathDistance;
public double traveledDistance;
public Direction in;
public Direction out;
final double speed;

public ClientTravelingItem(int id, ItemVariant variant, long amount, double totalPathDistance, double traveledDistance, Direction in,
public ClientTravelingItem(int id, ItemVariant variant, int amount, double totalPathDistance, double traveledDistance, Direction in,
Direction out, double speed) {
this.id = id;
this.variant = variant;
Expand All @@ -47,7 +47,7 @@ public ItemVariant variant() {
return variant;
}

public long amount() {
public int amount() {
return amount;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import dev.technici4n.moderndynamics.util.DropHelper;
import dev.technici4n.moderndynamics.util.ShapeHelper;
import dev.technici4n.moderndynamics.util.WrenchHelper;
import java.util.Objects;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
Expand All @@ -39,6 +40,7 @@
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
Expand Down Expand Up @@ -79,6 +81,16 @@ public final NodeHost[] getHosts() {
return hosts;
}

@Nullable
public final <T> T findHost(Class<T> hostClass) {
for (var host : getHosts()) {
if (hostClass.isInstance(host)) {
return hostClass.cast(host);
}
}
return null;
}

private boolean hasAttachment(Direction side) {
if (isClientSide()) {
var pipeData = getPipeModelData();
Expand All @@ -105,6 +117,21 @@ public final AttachedAttachment getAttachment(Direction side) {
return null;
}

@Nullable
public Item getAttachmentItem(Direction side) {
if (isClientSide()) {
var pipeModelData = getPipeModelData();
if (pipeModelData != null) {
var attachment = pipeModelData.attachments()[side.get3DDataValue()];
return attachment == null ? null : attachment.item();
}
return null;
} else {
var attachment = getAttachment(side);
return attachment == null ? null : attachment.getItem();
}
}

@Override
public void sync() {
super.sync();
Expand Down Expand Up @@ -332,7 +359,7 @@ protected void updateConnection(Direction side, boolean addConnection) {

public InteractionResult onUse(Player player, InteractionHand hand, BlockHitResult hitResult) {
var stack = player.getItemInHand(hand);
Vec3 posInBlock = hitResult.getLocation().subtract(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
Vec3 posInBlock = getPosInBlock(hitResult);

if (WrenchHelper.isWrench(stack)) {
// If the core was hit, add back the pipe on the target side
Expand Down Expand Up @@ -444,6 +471,10 @@ public InteractionResult onUse(Player player, InteractionHand hand, BlockHitResu
return InteractionResult.PASS;
}

public Vec3 getPosInBlock(HitResult hitResult) {
return hitResult.getLocation().subtract(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
}

@Nullable
public Direction hitTestAttachments(Vec3 posInBlock) {
// Handle click on attachment
Expand All @@ -459,11 +490,9 @@ public Direction hitTestAttachments(Vec3 posInBlock) {
}

public ItemStack overridePickBlock(HitResult hitResult) {
Vec3 posInBlock = hitResult.getLocation().subtract(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
Direction side = hitTestAttachments(posInBlock);
var pipeModelData = getPipeModelData();
if (pipeModelData != null) {
return side != null ? new ItemStack(pipeModelData.attachments()[side.get3DDataValue()].item()) : ItemStack.EMPTY;
Direction side = hitTestAttachments(getPosInBlock(hitResult));
if (side != null) {
return Objects.requireNonNull(getAttachmentItem(side), "Failed to get attachment item").getDefaultInstance();
}
return ItemStack.EMPTY;
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/assets/moderndynamics/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"block.moderndynamics.machine_extender": "Machine Extender",
"block.moderndynamics.mv_cable": "MV EU Cable",
"block.moderndynamics.superconductor_cable": "Superconductor EU Cable",
"config.jade.moderndynamics.item_pipe": "Item Pipes",
"gui.moderndynamics.rei.upgrade_category": "Modern Dynamics Upgrades",
"gui.moderndynamics.setting.filter_damage.ignore_damage": "Ignore Damage",
"gui.moderndynamics.setting.filter_damage.respect_damage": "Match Damage",
Expand Down Expand Up @@ -53,6 +54,7 @@
"gui.moderndynamics.tooltip.slot.upgrade": "Upgrade Slot",
"gui.moderndynamics.tooltip.slot.upgrade_desc1": "Press U on an Attractor/Extractor/Filter",
"gui.moderndynamics.tooltip.slot.upgrade_desc2": "in EMI/JEI/REI to view available upgrades.",
"gui.moderndynamics.tooltip.stuffed": "Stuffed %s",
"gui.moderndynamics.tooltip.upgrade_addFilterSlots": "Filter Slots: %s",
"gui.moderndynamics.tooltip.upgrade_addFluidTransfer": "Base Fluid Transfer: %s",
"gui.moderndynamics.tooltip.upgrade_addItemCount": "Max Moved Items: %s",
Expand Down

0 comments on commit 2cf9f34

Please sign in to comment.