Made network cards configurable as to what faces they connect to. Closes #53.
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
package li.cil.oc2.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
import li.cil.oc2.client.gui.widget.Texture;
|
||||
import li.cil.oc2.client.renderer.ModRenderType;
|
||||
import li.cil.oc2.common.item.Items;
|
||||
import li.cil.oc2.common.item.NetworkInterfaceCardItem;
|
||||
import li.cil.oc2.common.network.Network;
|
||||
import li.cil.oc2.common.network.message.NetworkInterfaceCardConfigurationMessage;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.InventoryMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static li.cil.oc2.common.util.TranslationUtils.key;
|
||||
import static li.cil.oc2.common.util.TranslationUtils.text;
|
||||
|
||||
public final class NetworkInterfaceCardScreen extends Screen {
|
||||
private static final String SIDE_STATE_TEXT = key("gui.{mod}.network_interface_card.side_state");
|
||||
private static final Component CONNECTIVITY_ENABLED_TEXT = text("gui.{mod}.network_interface_card.connectivity.enabled");
|
||||
private static final Component CONNECTIVITY_DISABLED_TEXT = text("gui.{mod}.network_interface_card.connectivity.disabled");
|
||||
private static final Component INFO_TEXT = text("gui.{mod}.network_interface_card.info");
|
||||
|
||||
public static final int UI_WIDTH = Sprites.NETWORK_INTERFACE_CARD_SCREEN.width;
|
||||
public static final int UI_HEIGHT = Sprites.NETWORK_INTERFACE_CARD_SCREEN.height;
|
||||
public static final int BLOCK_LEFT = UI_WIDTH / 2;
|
||||
public static final int BLOCK_TOP = 53;
|
||||
public static final int INFO_TEXT_LEFT = 8;
|
||||
public static final int INFO_TEXT_TOP = 104;
|
||||
public static final int INFO_TEXT_WIDTH = UI_WIDTH - 16;
|
||||
public static final int MAX_BLOCK_PITCH = 30;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private final Player player;
|
||||
private final InteractionHand hand;
|
||||
|
||||
private final ComputerBlockItemRenderer computerBlockItemRenderer = new ComputerBlockItemRenderer();
|
||||
|
||||
private Vector3f blockRotation = new Vector3f(-30, 45, 0);
|
||||
private int left, top;
|
||||
@Nullable private Direction focusedSide;
|
||||
private boolean isDraggingBlock, hasDraggedBlock;
|
||||
private double dragStartX, dragStartY;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public NetworkInterfaceCardScreen(final Player player, final InteractionHand hand) {
|
||||
super(Items.NETWORK_INTERFACE_CARD.get().getDescription());
|
||||
this.player = player;
|
||||
this.hand = hand;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
left = (width - UI_WIDTH) / 2;
|
||||
top = (height - UI_HEIGHT) / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
final ItemStack heldItem = player.getItemInHand(hand);
|
||||
if (!heldItem.is(Items.NETWORK_INTERFACE_CARD.get())) {
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(final double mouseX, final double mouseY, final int button) {
|
||||
final boolean result = super.mouseClicked(mouseX, mouseY, button);
|
||||
|
||||
if (!result && isMouseInBlockArea(mouseX, mouseY) && button == 0) {
|
||||
isDraggingBlock = true;
|
||||
hasDraggedBlock = false;
|
||||
dragStartX = mouseX;
|
||||
dragStartY = mouseY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(final double mouseX, final double mouseY, final int button) {
|
||||
if (isDraggingBlock && button == 0) {
|
||||
isDraggingBlock = false;
|
||||
if (!hasDraggedBlock && focusedSide != null) {
|
||||
final NetworkInterfaceCardConfigurationMessage message = new NetworkInterfaceCardConfigurationMessage(hand, focusedSide, !getConfiguration(focusedSide));
|
||||
Network.INSTANCE.sendToServer(message);
|
||||
Minecraft.getInstance().getSoundManager()
|
||||
.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1));
|
||||
}
|
||||
}
|
||||
|
||||
return super.mouseReleased(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(final double mouseX, final double mouseY, final int activeButton, final double deltaX, final double deltaY) {
|
||||
if (isDraggingBlock && activeButton == 0) {
|
||||
if (!hasDraggedBlock) {
|
||||
final double dx = mouseX - dragStartX;
|
||||
final double dy = mouseY - dragStartY;
|
||||
final double delta = Math.sqrt(dx * dx + dy * dy);
|
||||
hasDraggedBlock = delta > 3;
|
||||
}
|
||||
if (hasDraggedBlock) {
|
||||
blockRotation = new Vector3f(
|
||||
Mth.clamp(blockRotation.x() - (float) deltaY, -MAX_BLOCK_PITCH, MAX_BLOCK_PITCH),
|
||||
Mth.wrapDegrees(blockRotation.y() + (float) deltaX),
|
||||
blockRotation.z()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(final PoseStack stack, final int mouseX, final int mouseY, final float partialTicks) {
|
||||
renderBackground(stack);
|
||||
Sprites.NETWORK_INTERFACE_CARD_SCREEN.draw(stack, left, top);
|
||||
|
||||
super.render(stack, mouseX, mouseY, partialTicks);
|
||||
|
||||
final int blockX = left + BLOCK_LEFT;
|
||||
final int blockY = top + BLOCK_TOP;
|
||||
focusedSide = computerBlockItemRenderer.getFocusedSide(blockX - mouseX, blockY - mouseY, blockRotation);
|
||||
computerBlockItemRenderer.render(blockX, blockY, blockRotation);
|
||||
|
||||
if (focusedSide != null) {
|
||||
final Component enabledComponent = getConfiguration(focusedSide) ? CONNECTIVITY_ENABLED_TEXT : CONNECTIVITY_DISABLED_TEXT;
|
||||
final TranslatableComponent tooltip = new TranslatableComponent(SIDE_STATE_TEXT, enabledComponent);
|
||||
renderTooltip(stack, tooltip, mouseX, mouseY);
|
||||
}
|
||||
|
||||
font.drawWordWrap(INFO_TEXT, left + INFO_TEXT_LEFT, top + INFO_TEXT_TOP, INFO_TEXT_WIDTH, 0xAAAAAA);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPauseScreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean isMouseInBlockArea(final double mouseX, final double mouseY) {
|
||||
return mouseX >= left + 37 && mouseX <= left + (37 + 102) &&
|
||||
mouseY >= top + 10 && mouseY <= top + (10 + 102);
|
||||
}
|
||||
|
||||
private boolean getConfiguration(@Nullable final Direction side) {
|
||||
return side != null && NetworkInterfaceCardItem.getSideConfiguration(player.getItemInHand(hand), side);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private final class ComputerBlockItemRenderer {
|
||||
public static final int BLOCK_RENDER_SIZE = 48;
|
||||
|
||||
private final ItemStack computerItemStack = new ItemStack(Items.COMPUTER.get());
|
||||
private final ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
|
||||
private final BakedModel model = itemRenderer.getModel(computerItemStack, null, null, 0);
|
||||
|
||||
@Nullable
|
||||
private Direction getFocusedSide(final float mouseX, final float mouseY, final Vector3f rotation) {
|
||||
// Rotate ray inversely around block to represent visual block rotation.
|
||||
final Quaternion quaternion = Quaternion.fromXYZDegrees(rotation);
|
||||
quaternion.conj();
|
||||
|
||||
// Move ray in screen space to mouse position.
|
||||
final float relMouseX = -mouseX / (float) BLOCK_RENDER_SIZE;
|
||||
final float relMouseY = -mouseY / (float) BLOCK_RENDER_SIZE;
|
||||
|
||||
final Vector3f source = new Vector3f();
|
||||
source.add(relMouseX, relMouseY, 1);
|
||||
source.transform(quaternion);
|
||||
|
||||
final Vector3f target = new Vector3f();
|
||||
target.add(relMouseX, relMouseY, -1);
|
||||
target.transform(quaternion);
|
||||
|
||||
// Intersect rotated ray with bounding box representing block.
|
||||
final AABB aabb = new AABB(-0.5, -0.5, -0.5, 0.5, 0.5, 0.5);
|
||||
return aabb.clip(new Vec3(source), new Vec3(target))
|
||||
.map(hit -> Direction.getNearest(hit.x, -hit.y(), hit.z()))
|
||||
.filter(side -> side != Direction.SOUTH)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public void render(final int x, final int y, final Vector3f rotation) {
|
||||
RenderSystem.setShaderTexture(0, InventoryMenu.BLOCK_ATLAS);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
||||
|
||||
final Vector3f renderRotation = rotation.copy();
|
||||
renderRotation.add(0, 180, 0);
|
||||
|
||||
final PoseStack stack = RenderSystem.getModelViewStack();
|
||||
stack.pushPose();
|
||||
stack.translate(x, y, 0);
|
||||
stack.mulPose(Quaternion.fromXYZDegrees(renderRotation));
|
||||
stack.scale(BLOCK_RENDER_SIZE, -BLOCK_RENDER_SIZE, BLOCK_RENDER_SIZE);
|
||||
RenderSystem.applyModelViewMatrix();
|
||||
|
||||
final MultiBufferSource.BufferSource bufferSource = Minecraft.getInstance().renderBuffers().bufferSource();
|
||||
renderBlock(bufferSource);
|
||||
renderOverlays(stack, bufferSource);
|
||||
bufferSource.endBatch();
|
||||
|
||||
stack.popPose();
|
||||
RenderSystem.applyModelViewMatrix();
|
||||
}
|
||||
|
||||
private void renderBlock(final MultiBufferSource.BufferSource bufferSource) {
|
||||
itemRenderer.render(computerItemStack, ItemTransforms.TransformType.NONE, false, new PoseStack(), bufferSource, 0xF000F0, OverlayTexture.NO_OVERLAY, model);
|
||||
}
|
||||
|
||||
private void renderOverlays(final PoseStack poseStack, final MultiBufferSource.BufferSource bufferSource) {
|
||||
for (final Direction side : Direction.values()) {
|
||||
// South face of computers is the front face (screen) and there's no connectivity allowed there.
|
||||
if (side == Direction.SOUTH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
poseStack.pushPose();
|
||||
poseStack.setIdentity();
|
||||
|
||||
poseStack.translate(-side.getStepX() * 0.51, side.getStepY() * 0.51, -side.getStepZ() * 0.51);
|
||||
|
||||
final Vector3f sideRotation = switch (side) {
|
||||
case DOWN -> new Vector3f(-90, 0, 0);
|
||||
case UP -> new Vector3f(90, 0, 0);
|
||||
case NORTH -> new Vector3f(0, 180, 0);
|
||||
case WEST -> new Vector3f(0, -90, 0);
|
||||
case EAST -> new Vector3f(0, 90, 0);
|
||||
default -> throw new IllegalStateException("Unexpected value: " + side);
|
||||
};
|
||||
poseStack.mulPose(Quaternion.fromXYZDegrees(sideRotation));
|
||||
|
||||
poseStack.translate(-0.5, -0.5, 0);
|
||||
|
||||
if (getConfiguration(side)) {
|
||||
renderOverlay(poseStack, bufferSource, Textures.BLOCK_FACE_ENABLED_TEXTURE);
|
||||
} else {
|
||||
renderOverlay(poseStack, bufferSource, Textures.BLOCK_FACE_DISABLED_TEXTURE);
|
||||
}
|
||||
|
||||
if (side == focusedSide) {
|
||||
renderOverlay(poseStack, bufferSource, Textures.BLOCK_FACE_FOCUSED_TEXTURE);
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderOverlay(final PoseStack poseStack, final MultiBufferSource.BufferSource bufferSource, final Texture texture) {
|
||||
final VertexConsumer buffer = bufferSource.getBuffer(ModRenderType.getOverlay(texture.location));
|
||||
|
||||
buffer.vertex(poseStack.last().pose(), 0, 0, 0).uv(0, 0).endVertex();
|
||||
buffer.vertex(poseStack.last().pose(), 0, 1, 0).uv(0, 1).endVertex();
|
||||
buffer.vertex(poseStack.last().pose(), 1, 1, 0).uv(1, 1).endVertex();
|
||||
buffer.vertex(poseStack.last().pose(), 1, 0, 0).uv(1, 0).endVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ public final class Sprites {
|
||||
public static final Sprite ROBOT_CONTAINER = new Sprite(ROBOT_CONTAINER_TEXTURE);
|
||||
public static final Sprite TERMINAL_SCREEN = new Sprite(TERMINAL_SCREEN_TEXTURE);
|
||||
public static final Sprite BUS_INTERFACE_SCREEN = new Sprite(BUS_INTERFACE_SCREEN_TEXTURE);
|
||||
public static final Sprite NETWORK_INTERFACE_CARD_SCREEN = new Sprite(NETWORK_INTERFACE_CARD_SCREEN_TEXTURE);
|
||||
|
||||
public static final Sprite TERMINAL_FOCUSED = new Sprite(TERMINAL_FOCUSED_TEXTURE);
|
||||
public static final Sprite SLOT_SELECTION = new Sprite(SLOT_SELECTION_TEXTURE, 18, 18, 0, 0);
|
||||
|
||||
@@ -7,11 +7,15 @@ public final class Textures {
|
||||
public static final Texture ROBOT_CONTAINER_TEXTURE = new Texture("textures/gui/widget/robot_container.png", 176, 197);
|
||||
public static final Texture TERMINAL_SCREEN_TEXTURE = new Texture("textures/gui/widget/terminal_screen.png", 336, 208);
|
||||
public static final Texture BUS_INTERFACE_SCREEN_TEXTURE = new Texture("textures/gui/widget/bus_interface_screen.png", 240, 30);
|
||||
public static final Texture NETWORK_INTERFACE_CARD_SCREEN_TEXTURE = new Texture("textures/gui/widget/network_interface_card_screen.png", 176, 130);
|
||||
|
||||
public static final Texture TERMINAL_FOCUSED_TEXTURE = new Texture("textures/gui/overlay/terminal_focused.png", 336, 208);
|
||||
public static final Texture SLOT_SELECTION_TEXTURE = new Texture("textures/gui/overlay/slot_selection.png", 18, 270);
|
||||
public static final Texture INFO_ICON_TEXTURE = new Texture("textures/gui/overlay/slot_info.png", 28, 28);
|
||||
public static final Texture WARN_ICON_TEXTURE = new Texture("textures/gui/overlay/slot_warn.png", 28, 28);
|
||||
public static final Texture BLOCK_FACE_FOCUSED_TEXTURE = new Texture("textures/gui/overlay/block_face_focused.png", 16, 16);
|
||||
public static final Texture BLOCK_FACE_ENABLED_TEXTURE = new Texture("textures/gui/overlay/block_face_enabled.png", 16, 16);
|
||||
public static final Texture BLOCK_FACE_DISABLED_TEXTURE = new Texture("textures/gui/overlay/block_face_disabled.png", 16, 16);
|
||||
|
||||
public static final Texture HOTBAR_TEXTURE = new Texture("textures/gui/widget/hotbar.png", 224, 26);
|
||||
public static final Texture SIDEBAR_2_TEXTURE = new Texture("textures/gui/widget/sidebar_2.png", 19, 34);
|
||||
|
||||
@@ -47,6 +47,24 @@ public abstract class ModRenderType extends RenderType {
|
||||
state);
|
||||
}
|
||||
|
||||
public static RenderType getOverlay(final ResourceLocation location) {
|
||||
final TextureStateShard texture = new TextureStateShard(location, false, true);
|
||||
final RenderType.CompositeState state = RenderType.CompositeState.builder()
|
||||
.setShaderState(RenderStateShard.POSITION_TEX_SHADER)
|
||||
.setTextureState(texture)
|
||||
.setOutputState(TRANSLUCENT_TARGET)
|
||||
.setTransparencyState(ADDITIVE_TRANSPARENCY)
|
||||
.createCompositeState(false);
|
||||
return create(
|
||||
API.MOD_ID + "/overlay",
|
||||
DefaultVertexFormat.POSITION_TEX,
|
||||
VertexFormat.Mode.QUADS,
|
||||
256,
|
||||
false,
|
||||
true,
|
||||
state);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private ModRenderType(final String name, final VertexFormat format, final VertexFormat.Mode drawMode, final int bufferSize, final boolean useDelegate, final boolean needsSorting, final Runnable setupTask, final Runnable clearTask) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import li.cil.oc2.common.bus.device.util.IdentityProxy;
|
||||
import li.cil.oc2.common.bus.device.util.OptionalAddress;
|
||||
import li.cil.oc2.common.bus.device.util.OptionalInterrupt;
|
||||
import li.cil.oc2.common.capabilities.Capabilities;
|
||||
import li.cil.oc2.common.item.NetworkInterfaceCardItem;
|
||||
import li.cil.oc2.common.serialization.NBTSerialization;
|
||||
import li.cil.oc2.common.util.NBTTagIds;
|
||||
import li.cil.sedna.device.virtio.VirtIONetworkDevice;
|
||||
@@ -51,7 +52,7 @@ public final class NetworkInterfaceCardItemDevice extends IdentityProxy<ItemStac
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(final Capability<T> cap, @Nullable final Direction side) {
|
||||
if (cap == Capabilities.NETWORK_INTERFACE && side != null) {
|
||||
if (cap == Capabilities.NETWORK_INTERFACE && NetworkInterfaceCardItem.getSideConfiguration(identity, side)) {
|
||||
return LazyOptional.of(() -> networkInterface).cast();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public final class Items {
|
||||
new FloppyItem(512 * Constants.KILOBYTE));
|
||||
|
||||
public static final RegistryObject<Item> REDSTONE_INTERFACE_CARD = register("redstone_interface_card");
|
||||
public static final RegistryObject<Item> NETWORK_INTERFACE_CARD = register("network_interface_card");
|
||||
public static final RegistryObject<Item> NETWORK_INTERFACE_CARD = register("network_interface_card", NetworkInterfaceCardItem::new);
|
||||
public static final RegistryObject<Item> FILE_IMPORT_EXPORT_CARD = register("file_import_export_card");
|
||||
public static final RegistryObject<Item> SOUND_CARD = register("sound_card");
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package li.cil.oc2.common.item;
|
||||
|
||||
import li.cil.oc2.client.gui.NetworkInterfaceCardScreen;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.util.ItemStackUtils;
|
||||
import li.cil.oc2.common.util.NBTTagIds;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResultHolder;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static li.cil.oc2.common.util.TooltipUtils.withColor;
|
||||
import static li.cil.oc2.common.util.TranslationUtils.text;
|
||||
|
||||
public final class NetworkInterfaceCardItem extends ModItem {
|
||||
private static final String SIDE_CONFIGURATION_TAG_NAME = "sides";
|
||||
private static final Component IS_CONFIGURED_TEXT = withColor(text("item.{mod}.network_interface_card.is_configured"), ChatFormatting.GREEN);
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void setSideConfiguration(final ItemStack stack, final Direction side, final boolean enabled) {
|
||||
final int index = side.get3DDataValue();
|
||||
|
||||
final CompoundTag tag = ItemStackUtils.getOrCreateModDataTag(stack);
|
||||
final byte[] values;
|
||||
if (tag.contains(SIDE_CONFIGURATION_TAG_NAME, NBTTagIds.TAG_BYTE_ARRAY) &&
|
||||
tag.getByteArray(SIDE_CONFIGURATION_TAG_NAME).length == Constants.BLOCK_FACE_COUNT) {
|
||||
values = tag.getByteArray(SIDE_CONFIGURATION_TAG_NAME);
|
||||
} else {
|
||||
values = new byte[Constants.BLOCK_FACE_COUNT];
|
||||
Arrays.fill(values, (byte) 1);
|
||||
}
|
||||
|
||||
values[index] = (byte) (enabled ? 1 : 0);
|
||||
|
||||
tag.putByteArray(SIDE_CONFIGURATION_TAG_NAME, values);
|
||||
}
|
||||
|
||||
public static boolean getSideConfiguration(final ItemStack stack, @Nullable final Direction side) {
|
||||
if (side == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int index = side.get3DDataValue();
|
||||
|
||||
final CompoundTag tag = ItemStackUtils.getModDataTag(stack);
|
||||
if (tag.contains(SIDE_CONFIGURATION_TAG_NAME, NBTTagIds.TAG_BYTE_ARRAY)) {
|
||||
final byte[] values = tag.getByteArray(SIDE_CONFIGURATION_TAG_NAME);
|
||||
if (index < values.length) {
|
||||
return values[index] != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean hasConfiguration(final ItemStack stack) {
|
||||
final byte[] values = ItemStackUtils.getModDataTag(stack).getByteArray(SIDE_CONFIGURATION_TAG_NAME);
|
||||
for (final byte value : values) {
|
||||
if (value == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@Override
|
||||
public void appendHoverText(final ItemStack stack, @Nullable final Level level, final List<Component> tooltip, final TooltipFlag flag) {
|
||||
super.appendHoverText(stack, level, tooltip, flag);
|
||||
if (NetworkInterfaceCardItem.hasConfiguration(stack)) {
|
||||
tooltip.add(IS_CONFIGURED_TEXT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResultHolder<ItemStack> use(final Level level, final Player player, final InteractionHand hand) {
|
||||
final ItemStack itemStack = player.getItemInHand(hand);
|
||||
|
||||
if (player.getLevel().isClientSide()) {
|
||||
if (itemStack.is(Items.NETWORK_INTERFACE_CARD.get())) {
|
||||
openConfigurationScreen(player, hand);
|
||||
}
|
||||
}
|
||||
|
||||
return InteractionResultHolder.sidedSuccess(itemStack, player.getLevel().isClientSide());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void openConfigurationScreen(final Player player, final InteractionHand hand) {
|
||||
Minecraft.getInstance().setScreen(new NetworkInterfaceCardScreen(player, hand));
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,8 @@ public final class Network {
|
||||
registerMessage(ClientCanceledImportFileMessage.class, ClientCanceledImportFileMessage::new, NetworkDirection.PLAY_TO_SERVER);
|
||||
|
||||
registerMessage(BusCableFacadeMessage.class, BusCableFacadeMessage::new, NetworkDirection.PLAY_TO_CLIENT);
|
||||
|
||||
registerMessage(NetworkInterfaceCardConfigurationMessage.class, NetworkInterfaceCardConfigurationMessage::new, NetworkDirection.PLAY_TO_SERVER);
|
||||
}
|
||||
|
||||
public static <T> void sendToClientsTrackingChunk(final T message, final LevelChunk chunk) {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package li.cil.oc2.common.network.message;
|
||||
|
||||
import li.cil.oc2.common.item.Items;
|
||||
import li.cil.oc2.common.item.NetworkInterfaceCardItem;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
public final class NetworkInterfaceCardConfigurationMessage extends AbstractMessage {
|
||||
private InteractionHand hand;
|
||||
private Direction side;
|
||||
private boolean value;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public NetworkInterfaceCardConfigurationMessage(final InteractionHand hand, final Direction side, final boolean value) {
|
||||
this.hand = hand;
|
||||
this.side = side;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public NetworkInterfaceCardConfigurationMessage(final FriendlyByteBuf buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void fromBytes(final FriendlyByteBuf buffer) {
|
||||
hand = buffer.readEnum(InteractionHand.class);
|
||||
side = buffer.readEnum(Direction.class);
|
||||
value = buffer.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(final FriendlyByteBuf buffer) {
|
||||
buffer.writeEnum(hand);
|
||||
buffer.writeEnum(side);
|
||||
buffer.writeBoolean(value);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void handleMessage(final NetworkEvent.Context context) {
|
||||
final ServerPlayer player = context.getSender();
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack itemStack = player.getItemInHand(hand);
|
||||
if (!itemStack.is(Items.NETWORK_INTERFACE_CARD.get())) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkInterfaceCardItem.setSideConfiguration(itemStack, side, value);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ The network interface card (NIC) allows [computers](../block/computer.md) to sen
|
||||
|
||||
Computers *have to be shut down* before installing or removing this component. Installing it while the computer is running will have no effect, removing it may lead to system errors.
|
||||
|
||||
These cards can be configured to only connect to selected sides (use while holding). This allows using multiple cards to build a custom router, for example.
|
||||
|
||||
When using the default Linux distribution, this device will provide a regular ethernet device. Network setup can either be performed manually, or using the convenience script `setup-network.lua`. This script provides the option to either use a fixed-address setup, or a DHCP setup. For a DHCP setup, exactly one computer in the network must act as a DHCP server.
|
||||
|
||||
After initial setup, use the command `ifconfig` to see the currently used IP address.
|
||||
After initial setup, use the command `ifconfig` to see the currently used IP address.
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"item.oc2.flash_memory": "Flash Memory",
|
||||
"item.oc2.redstone_interface_card": "Redstone Interface Card",
|
||||
"item.oc2.network_interface_card": "Network Interface Card",
|
||||
"item.oc2.network_interface_card.is_configured": "Has connectivity configuration.",
|
||||
"item.oc2.file_import_export_card": "File Import/Export Card",
|
||||
"item.oc2.file_import_export_card.desc": "Provides an API to import and export files into and out of a virtual computer from and into your real file system.",
|
||||
"item.oc2.robot": "Robot",
|
||||
@@ -72,6 +73,11 @@
|
||||
"gui.oc2.file_chooser.confirm_button.overwrite": "Overwrite",
|
||||
"gui.oc2.file_chooser.cancel_button": "Cancel",
|
||||
|
||||
"gui.oc2.network_interface_card.side_state": "Connectivity: %s",
|
||||
"gui.oc2.network_interface_card.connectivity.enabled": "Enabled",
|
||||
"gui.oc2.network_interface_card.connectivity.disabled": "Disabled",
|
||||
"gui.oc2.network_interface_card.info": "Drag to rotate. Click faces to toggle connectivity.",
|
||||
|
||||
"manual.oc2.home": "Home",
|
||||
"manual.oc2.blocks": "Blocks",
|
||||
"manual.oc2.items": "Items",
|
||||
@@ -96,4 +102,4 @@
|
||||
"subtitles.oc2.floppy_eject": "Floppy ejected",
|
||||
"subtitles.oc2.floppy_insert": "Floppy inserted",
|
||||
"subtitles.oc2.hdd": "Hard drive access"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Reference in New Issue
Block a user