Interfaces can now be given a custom label.
This will act as an additional device name, which allows referencing them by this label.
This commit is contained in:
@@ -9,6 +9,7 @@ import li.cil.oc2.client.gui.RobotTerminalScreen;
|
||||
import li.cil.oc2.client.item.CustomItemColors;
|
||||
import li.cil.oc2.client.item.CustomItemModelProperties;
|
||||
import li.cil.oc2.client.model.BusCableModelLoader;
|
||||
import li.cil.oc2.client.renderer.BusInterfaceNameRenderer;
|
||||
import li.cil.oc2.client.renderer.NetworkCableRenderer;
|
||||
import li.cil.oc2.client.renderer.entity.RobotEntityRenderer;
|
||||
import li.cil.oc2.client.renderer.tileentity.ChargerTileEntityRenderer;
|
||||
@@ -35,6 +36,7 @@ public final class ClientSetup {
|
||||
@SubscribeEvent
|
||||
public static void handleSetupEvent(final FMLClientSetupEvent event) {
|
||||
NetworkCableRenderer.initialize();
|
||||
BusInterfaceNameRenderer.initialize();
|
||||
CustomItemModelProperties.initialize();
|
||||
CustomItemColors.initialize();
|
||||
|
||||
|
||||
156
src/main/java/li/cil/oc2/client/gui/BusInterfaceScreen.java
Normal file
156
src/main/java/li/cil/oc2/client/gui/BusInterfaceScreen.java
Normal file
@@ -0,0 +1,156 @@
|
||||
package li.cil.oc2.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import li.cil.oc2.api.API;
|
||||
import li.cil.oc2.client.gui.widget.ImageButton;
|
||||
import li.cil.oc2.client.gui.widget.Sprite;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.item.Items;
|
||||
import li.cil.oc2.common.network.Network;
|
||||
import li.cil.oc2.common.network.message.BusInterfaceNameMessage;
|
||||
import li.cil.oc2.common.tileentity.BusCableTileEntity;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.TextFieldWidget;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public final class BusInterfaceScreen extends Screen {
|
||||
private static final ResourceLocation BACKGROUND_LOCATION = new ResourceLocation(API.MOD_ID, "textures/gui/screen/bus_interface.png");
|
||||
|
||||
private static final Sprite BACKGROUND = new Sprite(BACKGROUND_LOCATION, 256, 240, 30, 0, 0);
|
||||
private static final Sprite CONFIRM_BASE = new Sprite(BACKGROUND_LOCATION, 256, 12, 12, 5, 35);
|
||||
private static final Sprite CONFIRM_PRESSED = new Sprite(BACKGROUND_LOCATION, 256, 12, 12, 20, 35);
|
||||
private static final Sprite CANCEL_BASE = new Sprite(BACKGROUND_LOCATION, 256, 12, 12, 5, 50);
|
||||
private static final Sprite CANCEL_PRESSED = new Sprite(BACKGROUND_LOCATION, 256, 12, 12, 20, 50);
|
||||
|
||||
private static final int TEXT_LEFT = 9;
|
||||
private static final int TEXT_TOP = 11;
|
||||
private static final int CONFIRM_LEFT = 206;
|
||||
private static final int CONFIRM_TOP = 9;
|
||||
private static final int CANCEL_LEFT = 219;
|
||||
private static final int CANCEL_TOP = 9;
|
||||
|
||||
private final BusCableTileEntity tileEntity;
|
||||
private final Direction side;
|
||||
|
||||
private TextFieldWidget nameField;
|
||||
|
||||
private int left, top;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public BusInterfaceScreen(final BusCableTileEntity tileEntity, final Direction side) {
|
||||
super(Items.BUS_INTERFACE.get().getName());
|
||||
this.tileEntity = tileEntity;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
getMinecraft().keyboardListener.enableRepeatEvents(true);
|
||||
|
||||
left = (width - BACKGROUND.width) / 2;
|
||||
top = (height - BACKGROUND.height) / 2;
|
||||
|
||||
nameField = new TextFieldWidget(font, left + TEXT_LEFT, top + TEXT_TOP, 192, 12, new TranslationTextComponent("oc2.gui.bus_interface_name"));
|
||||
nameField.setCanLoseFocus(false);
|
||||
nameField.setTextColor(0xFFFFFFFF);
|
||||
nameField.setEnableBackgroundDrawing(false);
|
||||
nameField.setMaxStringLength(32);
|
||||
nameField.setText(tileEntity.getInterfaceName(side));
|
||||
addListener(nameField);
|
||||
setFocusedDefault(nameField);
|
||||
|
||||
addButton(new ImageButton(
|
||||
this,
|
||||
left + CONFIRM_LEFT, top + CONFIRM_TOP,
|
||||
CONFIRM_BASE.width, CONFIRM_BASE.height,
|
||||
new TranslationTextComponent(Constants.TOOLTIP_CONFIRM),
|
||||
null,
|
||||
CONFIRM_BASE,
|
||||
CONFIRM_PRESSED
|
||||
) {
|
||||
@Override
|
||||
public void onPress() {
|
||||
super.onPress();
|
||||
setInterfaceName(nameField.getText());
|
||||
closeScreen();
|
||||
}
|
||||
});
|
||||
addButton(new ImageButton(
|
||||
this,
|
||||
left + CANCEL_LEFT, top + CANCEL_TOP,
|
||||
CANCEL_BASE.width, CANCEL_BASE.height,
|
||||
new TranslationTextComponent(Constants.TOOLTIP_CANCEL),
|
||||
null,
|
||||
CANCEL_BASE,
|
||||
CANCEL_PRESSED
|
||||
) {
|
||||
@Override
|
||||
public void onPress() {
|
||||
super.onPress();
|
||||
closeScreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
super.onClose();
|
||||
|
||||
getMinecraft().keyboardListener.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
nameField.tick();
|
||||
|
||||
final Vector3d busCableCenter = Vector3d.copyCentered(tileEntity.getPos());
|
||||
if (getMinecraft().player.getDistanceSq(busCableCenter) > 8 * 8) {
|
||||
closeScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(final int keyCode, final int scanCode, final int modifiers) {
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER ||
|
||||
keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||
setInterfaceName(nameField.getText());
|
||||
closeScreen();
|
||||
return true;
|
||||
}
|
||||
|
||||
return nameField.keyPressed(keyCode, scanCode, modifiers) || super.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(final MatrixStack matrixStack, final int mouseX, final int mouseY, final float partialTicks) {
|
||||
renderBackground(matrixStack);
|
||||
BACKGROUND.draw(matrixStack, left, top);
|
||||
|
||||
super.render(matrixStack, mouseX, mouseY, partialTicks);
|
||||
|
||||
RenderSystem.disableBlend();
|
||||
nameField.render(matrixStack, mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPauseScreen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private void setInterfaceName(final String name) {
|
||||
Network.INSTANCE.sendToServer(new BusInterfaceNameMessage.ToServer(tileEntity, side, name));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package li.cil.oc2.client.renderer;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import li.cil.oc2.common.block.BusCableBlock;
|
||||
import li.cil.oc2.common.integration.Wrenches;
|
||||
import li.cil.oc2.common.tileentity.BusCableTileEntity;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererManager;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.vector.Matrix4f;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
public enum BusInterfaceNameRenderer {
|
||||
INSTANCE;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void initialize() {
|
||||
MinecraftForge.EVENT_BUS.register(INSTANCE);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void handleRenderLastEvent(final RenderWorldLastEvent event) {
|
||||
final Minecraft mc = Minecraft.getInstance();
|
||||
final PlayerEntity player = mc.player;
|
||||
final World world = player.getEntityWorld();
|
||||
|
||||
if (!Wrenches.isHoldingWrench(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc.objectMouseOver instanceof BlockRayTraceResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockRayTraceResult hit = (BlockRayTraceResult) mc.objectMouseOver;
|
||||
final BlockPos blockPos = hit.getPos();
|
||||
final TileEntity tileEntity = world.getTileEntity(blockPos);
|
||||
if (!(tileEntity instanceof BusCableTileEntity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BusCableTileEntity busCable = (BusCableTileEntity) tileEntity;
|
||||
final Direction side = BusCableBlock.getHitSide(blockPos, hit);
|
||||
if (BusCableBlock.getConnectionType(world.getBlockState(blockPos), side) != BusCableBlock.ConnectionType.INTERFACE) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String name = busCable.getInterfaceName(side);
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final MatrixStack stack = event.getMatrixStack();
|
||||
stack.push();
|
||||
|
||||
stack.translate(0.5, 1, 0.5);
|
||||
stack.translate(side.getXOffset() * 0.5f, 0, side.getZOffset() * 0.5f);
|
||||
|
||||
final ActiveRenderInfo info = mc.gameRenderer.getActiveRenderInfo();
|
||||
stack.translate(
|
||||
blockPos.getX() - info.getProjectedView().getX(),
|
||||
blockPos.getY() - info.getProjectedView().getY(),
|
||||
blockPos.getZ() - info.getProjectedView().getZ());
|
||||
|
||||
final EntityRendererManager renderManager = mc.getRenderManager();
|
||||
stack.rotate(renderManager.getCameraOrientation());
|
||||
|
||||
stack.scale(-0.025f, -0.025f, 0.025f);
|
||||
|
||||
final Matrix4f matrix = stack.getLast().getMatrix();
|
||||
|
||||
final FontRenderer fontrenderer = renderManager.getFontRenderer();
|
||||
final IRenderTypeBuffer.Impl buffer = IRenderTypeBuffer.getImpl(Tessellator.getInstance().getBuffer());
|
||||
|
||||
final float horizontalTextOffset = -fontrenderer.getStringWidth(name) * 0.5f;
|
||||
final float backgroundOpacity = Minecraft.getInstance().gameSettings.getTextBackgroundOpacity(0.25F);
|
||||
final int backgroundColor = (int) (backgroundOpacity * 255.0F) << 24;
|
||||
final int packedLight = LightTexture.packLight(15, 15);
|
||||
|
||||
fontrenderer.renderString(name, horizontalTextOffset, 0, 0xffffffff,
|
||||
false, matrix, buffer, true, backgroundColor, packedLight);
|
||||
fontrenderer.renderString(name, horizontalTextOffset, 0, 0xffffffff,
|
||||
false, matrix, buffer, false, 0, packedLight);
|
||||
|
||||
buffer.finish();
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,8 @@ public final class Constants {
|
||||
public static final String TOOLTIP_HARD_DRIVE_MISSING = "tooltip.oc2.hard_drive_missing";
|
||||
public static final String TOOLTIP_ENERGY = "tooltip.oc2.energy";
|
||||
public static final String TOOLTIP_ENERGY_CONSUMPTION = "tooltip.oc2.energyConsumption";
|
||||
public static final String TOOLTIP_CONFIRM = "tooltip.oc2.confirm";
|
||||
public static final String TOOLTIP_CANCEL = "tooltip.oc2.cancel";
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package li.cil.oc2.common.block;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import li.cil.oc2.client.gui.BusInterfaceScreen;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.integration.Wrenches;
|
||||
import li.cil.oc2.common.item.Items;
|
||||
@@ -12,6 +13,7 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.SoundType;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BlockItemUseContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -33,6 +35,8 @@ import net.minecraft.world.GameRules;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.util.Constants.BlockFlags;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -99,6 +103,11 @@ public final class BusCableBlock extends Block {
|
||||
return partCount;
|
||||
}
|
||||
|
||||
public static Direction getHitSide(final BlockPos pos, final BlockRayTraceResult hit) {
|
||||
final Vector3d localHitPos = hit.getHitVec().subtract(Vector3d.copyCentered(pos));
|
||||
return Direction.getFacingFromVector(localHitPos.x, localHitPos.y, localHitPos.z);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private final VoxelShape[] shapes;
|
||||
@@ -171,14 +180,27 @@ public final class BusCableBlock extends Block {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public ActionResultType onBlockActivated(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player, final Hand hand, final BlockRayTraceResult hit) {
|
||||
if (player.isSneaking() && Wrenches.isWrench(player.getHeldItem(hand))) {
|
||||
// NB: leave wrenching logic up to wrench when the to-be-removed interface is the last
|
||||
// part of this bus. This ensures we properly remove the block itself without having
|
||||
// to duplicate the logic needed for that.
|
||||
if (getPartCount(state) > 1)
|
||||
if (tryRemovePlug(state, world, pos, player, hit) || tryRemoveCable(state, world, pos, player)) {
|
||||
return ActionResultType.func_233537_a_(world.isRemote());
|
||||
if (Wrenches.isWrench(player.getHeldItem(hand))) {
|
||||
if (player.isSneaking()) {
|
||||
// NB: leave wrenching logic up to wrench when the to-be-removed interface is the last
|
||||
// part of this bus. This ensures we properly remove the block itself without having
|
||||
// to duplicate the logic needed for that.
|
||||
if (getPartCount(state) > 1)
|
||||
if (tryRemovePlug(state, world, pos, player, hit) || tryRemoveCable(state, world, pos, player)) {
|
||||
return ActionResultType.func_233537_a_(world.isRemote());
|
||||
}
|
||||
} else {
|
||||
final TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if (tileEntity instanceof BusCableTileEntity) {
|
||||
final BusCableTileEntity busCableTileEntity = (BusCableTileEntity) tileEntity;
|
||||
|
||||
final Direction side = getHitSide(pos, hit);
|
||||
if (getConnectionType(state, side) == ConnectionType.INTERFACE) {
|
||||
openBusInterfaceScreen(busCableTileEntity, side);
|
||||
return ActionResultType.func_233537_a_(world.isRemote());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.onBlockActivated(state, world, pos, player, hand, hit);
|
||||
@@ -261,8 +283,10 @@ public final class BusCableBlock extends Block {
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private boolean canHaveCableTo(final BlockState state, final Direction side) {
|
||||
return state.getBlock() == this && state.get(HAS_CABLE) && state.get(FACING_TO_CONNECTION_MAP.get(side)) != ConnectionType.INTERFACE;
|
||||
private static boolean canHaveCableTo(final BlockState state, final Direction side) {
|
||||
return state.getBlock() == Blocks.BUS_CABLE.get() &&
|
||||
state.get(HAS_CABLE) &&
|
||||
state.get(FACING_TO_CONNECTION_MAP.get(side)) != ConnectionType.INTERFACE;
|
||||
}
|
||||
|
||||
private static int getPartCount(final BlockState state) {
|
||||
@@ -273,9 +297,8 @@ public final class BusCableBlock extends Block {
|
||||
return partCount;
|
||||
}
|
||||
|
||||
private boolean tryRemovePlug(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player, final BlockRayTraceResult hit) {
|
||||
final Vector3d localHitPos = hit.getHitVec().subtract(Vector3d.copyCentered(pos));
|
||||
final Direction side = Direction.getFacingFromVector(localHitPos.x, localHitPos.y, localHitPos.z);
|
||||
private static boolean tryRemovePlug(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player, final BlockRayTraceResult hit) {
|
||||
final Direction side = getHitSide(pos, hit);
|
||||
final EnumProperty<ConnectionType> property = FACING_TO_CONNECTION_MAP.get(side);
|
||||
|
||||
if (state.get(property) != ConnectionType.INTERFACE) {
|
||||
@@ -294,7 +317,7 @@ public final class BusCableBlock extends Block {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean tryRemoveCable(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player) {
|
||||
private static boolean tryRemoveCable(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player) {
|
||||
if (!state.get(HAS_CABLE)) {
|
||||
return false;
|
||||
}
|
||||
@@ -306,7 +329,7 @@ public final class BusCableBlock extends Block {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handlePartRemoved(final BlockState state, final World world, final BlockPos pos, @Nullable final Direction side, final PlayerEntity player, final ItemStack drop) {
|
||||
private static void handlePartRemoved(final BlockState state, final World world, final BlockPos pos, @Nullable final Direction side, final PlayerEntity player, final ItemStack drop) {
|
||||
onConnectionTypeChanged(world, pos, side);
|
||||
|
||||
if (!player.isCreative() && world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)) {
|
||||
@@ -319,7 +342,7 @@ public final class BusCableBlock extends Block {
|
||||
WorldUtils.playSound(world, pos, state.getSoundType(), SoundType::getBreakSound);
|
||||
}
|
||||
|
||||
private void onConnectionTypeChanged(final IWorld world, final BlockPos pos, @Nullable final Direction face) {
|
||||
private static void onConnectionTypeChanged(final IWorld world, final BlockPos pos, @Nullable final Direction face) {
|
||||
final TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if (tileEntity instanceof BusCableTileEntity) {
|
||||
final BusCableTileEntity busCable = (BusCableTileEntity) tileEntity;
|
||||
@@ -327,6 +350,12 @@ public final class BusCableBlock extends Block {
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static void openBusInterfaceScreen(final BusCableTileEntity tileEntity, final Direction side) {
|
||||
final BusInterfaceScreen screen = new BusInterfaceScreen(tileEntity, side);
|
||||
Minecraft.getInstance().displayGuiScreen(screen);
|
||||
}
|
||||
|
||||
private static VoxelShape[] makeShapes() {
|
||||
final VoxelShape ownCableBounds = Block.makeCuboidShape(5, 5, 5, 11, 11, 11);
|
||||
final VoxelShape[] cableShapes = new VoxelShape[Constants.BLOCK_FACE_COUNT];
|
||||
|
||||
@@ -128,6 +128,14 @@ public final class RPCDeviceBusAdapter implements Steppable {
|
||||
final HashMap<RPCDeviceList, ArrayList<UUID>> identifiersByDevice = new HashMap<>();
|
||||
devicesByIdentifier.forEach((identifier, devices) -> {
|
||||
final RPCDeviceList device = new RPCDeviceList(devices);
|
||||
|
||||
// If there are no methods we have either no devices at all, or all synthetic
|
||||
// devices, i.e. devices that only contribute type names, but have no methods
|
||||
// to call. We do not expose these to avoid cluttering the device list.
|
||||
if (device.getMethods().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
identifiersByDevice
|
||||
.computeIfAbsent(device, unused -> new ArrayList<>())
|
||||
.add(identifier);
|
||||
|
||||
@@ -4,7 +4,6 @@ import li.cil.oc2.api.bus.BlockDeviceBusElement;
|
||||
import li.cil.oc2.api.bus.DeviceBus;
|
||||
import li.cil.oc2.api.bus.DeviceBusElement;
|
||||
import li.cil.oc2.api.bus.device.provider.BlockDeviceQuery;
|
||||
import li.cil.oc2.api.bus.device.rpc.RPCDevice;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.bus.device.rpc.TypeNameRPCDevice;
|
||||
import li.cil.oc2.common.bus.device.util.BlockDeviceInfo;
|
||||
@@ -101,7 +100,7 @@ public class TileEntityDeviceBusElement extends AbstractGroupingBlockDeviceBusEl
|
||||
}
|
||||
}
|
||||
|
||||
insertBlockNameDevice(world, pos, newDevices);
|
||||
collectSyntheticDevices(world, pos, direction, newDevices);
|
||||
|
||||
setDevicesForGroup(index, newDevices);
|
||||
}
|
||||
@@ -128,6 +127,13 @@ public class TileEntityDeviceBusElement extends AbstractGroupingBlockDeviceBusEl
|
||||
return canScanContinueTowards(direction);
|
||||
}
|
||||
|
||||
protected void collectSyntheticDevices(final World world, final BlockPos pos, final Direction direction, final HashSet<BlockDeviceInfo> devices) {
|
||||
final String blockName = WorldUtils.getBlockName(world, pos);
|
||||
if (blockName != null) {
|
||||
devices.add(new BlockDeviceInfo(null, new TypeNameRPCDevice(blockName)));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private void scanNeighborsForDevices() {
|
||||
@@ -151,13 +157,4 @@ public class TileEntityDeviceBusElement extends AbstractGroupingBlockDeviceBusEl
|
||||
capability.ifPresent(DeviceBus::scheduleScan);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertBlockNameDevice(final World world, final BlockPos pos, final HashSet<BlockDeviceInfo> devices) {
|
||||
if (devices.stream().anyMatch(info -> info.device instanceof RPCDevice)) {
|
||||
final String blockName = WorldUtils.getBlockName(world, pos);
|
||||
if (blockName != null) {
|
||||
devices.add(new BlockDeviceInfo(null, new TypeNameRPCDevice(blockName)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,18 @@ public final class Network {
|
||||
.decoder(DiskDriveFloppyMessage::new)
|
||||
.consumer(DiskDriveFloppyMessage::handleMessage)
|
||||
.add();
|
||||
|
||||
INSTANCE.messageBuilder(BusInterfaceNameMessage.ToClient.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.encoder(BusInterfaceNameMessage::toBytes)
|
||||
.decoder(BusInterfaceNameMessage.ToClient::new)
|
||||
.consumer(BusInterfaceNameMessage::handleMessageClient)
|
||||
.add();
|
||||
|
||||
INSTANCE.messageBuilder(BusInterfaceNameMessage.ToServer.class, getNextPacketId(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.encoder(BusInterfaceNameMessage::toBytes)
|
||||
.decoder(BusInterfaceNameMessage.ToServer::new)
|
||||
.consumer(BusInterfaceNameMessage::handleMessageServer)
|
||||
.add();
|
||||
}
|
||||
|
||||
public static <T> void sendToClientsTrackingChunk(final T message, final Chunk chunk) {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package li.cil.oc2.common.network.message;
|
||||
|
||||
import li.cil.oc2.common.network.MessageUtils;
|
||||
import li.cil.oc2.common.tileentity.BusCableTileEntity;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraftforge.fml.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class BusInterfaceNameMessage {
|
||||
private BlockPos pos;
|
||||
private Direction side;
|
||||
private String value;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
protected BusInterfaceNameMessage(final BusCableTileEntity tileEntity, final Direction side, final String value) {
|
||||
this.pos = tileEntity.getPos();
|
||||
this.side = side;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
protected BusInterfaceNameMessage(final PacketBuffer buffer) {
|
||||
fromBytes(buffer);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public static boolean handleMessageClient(final BusInterfaceNameMessage message, final Supplier<NetworkEvent.Context> context) {
|
||||
context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, BusCableTileEntity.class,
|
||||
(tileEntity) -> tileEntity.setInterfaceName(message.side, message.value)));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean handleMessageServer(final BusInterfaceNameMessage message, final Supplier<NetworkEvent.Context> context) {
|
||||
context.get().enqueueWork(() -> MessageUtils.withServerTileEntityAt(context, message.pos, BusCableTileEntity.class,
|
||||
(tileEntity) -> {
|
||||
final Vector3d busCableCenter = Vector3d.copyCentered(tileEntity.getPos());
|
||||
if (context.get().getSender().getDistanceSq(busCableCenter) <= 8 * 8) {
|
||||
tileEntity.setInterfaceName(message.side, message.value);
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void fromBytes(final PacketBuffer buffer) {
|
||||
pos = buffer.readBlockPos();
|
||||
side = buffer.readEnumValue(Direction.class);
|
||||
value = buffer.readString(32);
|
||||
}
|
||||
|
||||
public static void toBytes(final BusInterfaceNameMessage message, final PacketBuffer buffer) {
|
||||
buffer.writeBlockPos(message.pos);
|
||||
buffer.writeEnumValue(message.side);
|
||||
buffer.writeString(message.value, 32);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public static final class ToClient extends BusInterfaceNameMessage {
|
||||
public ToClient(final BusCableTileEntity tileEntity, final Direction side, final String value) {
|
||||
super(tileEntity, side, value);
|
||||
}
|
||||
|
||||
public ToClient(final PacketBuffer buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ToServer extends BusInterfaceNameMessage {
|
||||
public ToServer(final BusCableTileEntity tileEntity, final Direction side, final String value) {
|
||||
super(tileEntity, side, value);
|
||||
}
|
||||
|
||||
public ToServer(final PacketBuffer buffer) {
|
||||
super(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,37 @@ package li.cil.oc2.common.tileentity;
|
||||
|
||||
import li.cil.oc2.client.model.BusCableBakedModel;
|
||||
import li.cil.oc2.common.Config;
|
||||
import li.cil.oc2.common.Constants;
|
||||
import li.cil.oc2.common.block.BusCableBlock;
|
||||
import li.cil.oc2.common.bus.TileEntityDeviceBusElement;
|
||||
import li.cil.oc2.common.bus.device.rpc.TypeNameRPCDevice;
|
||||
import li.cil.oc2.common.bus.device.util.BlockDeviceInfo;
|
||||
import li.cil.oc2.common.capabilities.Capabilities;
|
||||
import li.cil.oc2.common.network.Network;
|
||||
import li.cil.oc2.common.network.message.BusInterfaceNameMessage;
|
||||
import li.cil.oc2.common.util.NBTTagIds;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.nbt.StringNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.model.data.IModelData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
private static final String BUS_ELEMENT_TAG_NAME = "busElement";
|
||||
private static final String INTERFACE_NAMES_TAG_NAME = "interfaceNames";
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private final TileEntityDeviceBusElement busElement = new BusCableBusElement();
|
||||
private final String[] interfaceNames = new String[Constants.BLOCK_FACE_COUNT];
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -30,6 +42,25 @@ public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getInterfaceName(final Direction side) {
|
||||
final String interfaceName = interfaceNames[side.getIndex()];
|
||||
return interfaceName == null ? "" : interfaceName;
|
||||
}
|
||||
|
||||
public void setInterfaceName(final Direction side, final String name) {
|
||||
final String validatedName = validateName(name);
|
||||
if (Objects.equals(validatedName, interfaceNames[side.getIndex()])) {
|
||||
return;
|
||||
}
|
||||
|
||||
interfaceNames[side.getIndex()] = validatedName;
|
||||
if (!getWorld().isRemote()) {
|
||||
final BusInterfaceNameMessage message = new BusInterfaceNameMessage.ToClient(this, side, interfaceNames[side.getIndex()]);
|
||||
Network.sendToClientsTrackingChunk(message, getWorld().getChunkAt(getPos()));
|
||||
handleNeighborChanged(getPos().offset(side));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleNeighborChanged(final BlockPos pos) {
|
||||
busElement.handleNeighborChanged(pos);
|
||||
|
||||
@@ -44,24 +75,54 @@ public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
// TODO Remove if https://github.com/MinecraftForge/MinecraftForge/pull/7595 gets merged.
|
||||
requestModelDataUpdate();
|
||||
} else {
|
||||
// Whenever they type changes we can clear it. Technically only needed
|
||||
// for the interface->none transition, but all others are no-ops, so
|
||||
// we can just do this.
|
||||
setInterfaceName(side, "");
|
||||
|
||||
invalidateCapability(Capabilities.DEVICE_BUS_ELEMENT, side);
|
||||
handleNeighborChanged(getPos().offset(side));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
|
||||
// Bus element will usually be discovered via bus scan, not via capability request, so
|
||||
// automatic invalidation via capability will *not* necessarily schedule a scan on the
|
||||
// controller of our current bus. So we need to trigger that manually.
|
||||
busElement.scheduleScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT getUpdateTag() {
|
||||
final CompoundNBT tag = super.getUpdateTag();
|
||||
|
||||
tag.put(INTERFACE_NAMES_TAG_NAME, serializeInterfaceNames());
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUpdateTag(final BlockState state, final CompoundNBT tag) {
|
||||
deserializeInterfaceNames(tag.getList(INTERFACE_NAMES_TAG_NAME, NBTTagIds.TAG_STRING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundNBT write(CompoundNBT tag) {
|
||||
tag = super.write(tag);
|
||||
tag.put(BUS_ELEMENT_TAG_NAME, busElement.serializeNBT());
|
||||
tag.put(INTERFACE_NAMES_TAG_NAME, serializeInterfaceNames());
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(final BlockState state, final CompoundNBT tag) {
|
||||
super.read(state, tag);
|
||||
if (tag.contains(BUS_ELEMENT_TAG_NAME, NBTTagIds.TAG_LIST)) {
|
||||
busElement.deserializeNBT(tag.getList(BUS_ELEMENT_TAG_NAME, NBTTagIds.TAG_COMPOUND));
|
||||
}
|
||||
busElement.deserializeNBT(tag.getList(BUS_ELEMENT_TAG_NAME, NBTTagIds.TAG_COMPOUND));
|
||||
deserializeInterfaceNames(tag.getList(INTERFACE_NAMES_TAG_NAME, NBTTagIds.TAG_STRING));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
@@ -80,16 +141,6 @@ public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
busElement.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
|
||||
// Bus element will usually be discovered via bus scan, not via capability request, so
|
||||
// automatic invalidation via capability will *not* necessarily schedule a scan on the
|
||||
// controller of our current bus. So we need to trigger that manually.
|
||||
busElement.scheduleScan();
|
||||
}
|
||||
|
||||
// TODO Remove if https://github.com/MinecraftForge/MinecraftForge/pull/7595 gets merged.
|
||||
@Override
|
||||
public IModelData getModelData() {
|
||||
@@ -102,6 +153,28 @@ public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private ListNBT serializeInterfaceNames() {
|
||||
final ListNBT tag = new ListNBT();
|
||||
for (int i = 0; i < Constants.BLOCK_FACE_COUNT; i++) {
|
||||
tag.add(StringNBT.valueOf(getInterfaceName(Direction.byIndex(i))));
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
private void deserializeInterfaceNames(final ListNBT tag) {
|
||||
for (int i = 0; i < Constants.BLOCK_FACE_COUNT; i++) {
|
||||
final String name = tag.getString(i).trim();
|
||||
interfaceNames[i] = name.substring(0, Math.min(32, name.length()));
|
||||
}
|
||||
}
|
||||
|
||||
private static String validateName(final String name) {
|
||||
final String trimmed = name.trim();
|
||||
return trimmed.length() > 32 ? trimmed.substring(0, 32) : trimmed;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
private final class BusCableBusElement extends TileEntityDeviceBusElement {
|
||||
public BusCableBusElement() {
|
||||
super(BusCableTileEntity.this);
|
||||
@@ -120,6 +193,15 @@ public final class BusCableTileEntity extends AbstractTileEntity {
|
||||
return connectionType == BusCableBlock.ConnectionType.INTERFACE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void collectSyntheticDevices(final World world, final BlockPos pos, final Direction direction, final HashSet<BlockDeviceInfo> devices) {
|
||||
super.collectSyntheticDevices(world, pos, direction, devices);
|
||||
final String interfaceName = interfaceNames[direction.getIndex()];
|
||||
if (!StringUtils.isNullOrEmpty(interfaceName)) {
|
||||
devices.add(new BlockDeviceInfo(null, new TypeNameRPCDevice(interfaceName)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getEnergyConsumption() {
|
||||
return super.getEnergyConsumption()
|
||||
|
||||
@@ -62,7 +62,9 @@
|
||||
"tooltip.oc2.memory_missing": "Some memory is required to load the flash memory for execution to boot.",
|
||||
"tooltip.oc2.hard_drive_missing": "Most systems will require a root file system to boot.",
|
||||
"tooltip.oc2.energy": "Energy: %s",
|
||||
"tooltip.oc2.energyConsumption": "Energy Consumption: %s",
|
||||
"tooltip.oc2.energyConsumption": "Energy Consumption: %s/t",
|
||||
"tooltip.oc2.confirm": "Confirm",
|
||||
"tooltip.oc2.cancel": "Cancel",
|
||||
|
||||
"subtitles.oc2.computer": "Computer fans running",
|
||||
"subtitles.oc2.floppy": "Floppy access",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Reference in New Issue
Block a user