mirror of
https://github.com/GTNewHorizons/StructureLib.git
synced 2026-10-25 20:32:24 +00:00
feat(middle-click): Add in GUI and in-world middle-click pick to set and reset channels (#74)
This commit is contained in:
10 files changed
+254
-8
No files matched your search
@@ -3,7 +3,6 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
api("com.github.GTNewHorizons:GTNHLib:0.11.21:dev")
|
api("com.github.GTNewHorizons:GTNHLib:0.11.21:dev")
|
||||||
implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.110-GTNH:dev")
|
implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.110-GTNH:dev")
|
||||||
|
|
||||||
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
||||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||||
testRuntimeOnly ('org.junit.platform:junit-platform-launcher')
|
testRuntimeOnly ('org.junit.platform:junit-platform-launcher')
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package com.gtnewhorizon.structurelib;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.ChatComponentTranslation;
|
||||||
|
import net.minecraft.util.MovingObjectPosition;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||||
|
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for middle-click channel picking. When the player holds a hologram projector on the cursor and middle-clicks
|
||||||
|
* a registered indicator item, the corresponding channel is set on the projector. The same applies in world when the
|
||||||
|
* projector is held in hand and a registered indicator block is middle-clicked. Shift+middle-click wipes all channels.
|
||||||
|
* Was made side neutral to support server-side validation at some point if necessary.
|
||||||
|
*/
|
||||||
|
public final class ChannelPickHandler {
|
||||||
|
|
||||||
|
private ChannelPickHandler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a middle-click event while holding a hologram projector on the cursor.
|
||||||
|
*/
|
||||||
|
public static boolean handleMiddleClick(EntityPlayer player, ItemStack holoStack, @Nullable ItemStack targetStack,
|
||||||
|
final boolean isSneaking) {
|
||||||
|
return handlePick(player, holoStack, targetStack, isSneaking, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean handleWorldPick(World world, EntityPlayer player, ItemStack holoStack,
|
||||||
|
@Nullable MovingObjectPosition hit, final boolean isSneaking) {
|
||||||
|
ItemStack targetStack = null;
|
||||||
|
|
||||||
|
if (hit != null) {
|
||||||
|
Block block = world.getBlock(hit.blockX, hit.blockY, hit.blockZ);
|
||||||
|
if (!block.isAir(world, hit.blockX, hit.blockY, hit.blockZ)) {
|
||||||
|
targetStack = block.getPickBlock(hit, world, hit.blockX, hit.blockY, hit.blockZ, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A null target still goes through so that shift+middle-click wipes even when aiming at nothing
|
||||||
|
return handlePick(player, holoStack, targetStack, isSneaking, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean handlePick(EntityPlayer player, ItemStack holoStack, @Nullable ItemStack targetStack,
|
||||||
|
final boolean isSneaking, final boolean onCursor) {
|
||||||
|
// Clear channels on shift+middle-click. The "press again to confirm" gesture is gated client-side
|
||||||
|
// (see ChannelWipeConfirmation) before this method is ever called.
|
||||||
|
if (isSneaking) {
|
||||||
|
ChannelDataAccessor.wipeChannelData(holoStack);
|
||||||
|
sendChannelData(player, holoStack, onCursor);
|
||||||
|
player.addChatMessage(new ChatComponentTranslation("structurelib.pickchannel.cleared"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetStack == null) return false; // nothing hovered, cancel silently
|
||||||
|
|
||||||
|
Collection<Map.Entry<String, Integer>> channels = ChannelDescription.iterate(targetStack);
|
||||||
|
if (channels.isEmpty()) {
|
||||||
|
player.addChatMessage(new ChatComponentTranslation("structurelib.pickchannel.nomapping"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming there's only 1 channel per item for now (same behavior as drag and drop)
|
||||||
|
Map.Entry<String, Integer> first = channels.iterator().next();
|
||||||
|
ChannelDataAccessor.setChannelData(holoStack, first.getKey(), first.getValue());
|
||||||
|
sendChannelData(player, holoStack, onCursor);
|
||||||
|
player.addChatMessage(
|
||||||
|
new ChatComponentTranslation("structurelib.pickchannel.success", first.getKey(), first.getValue()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player is the one triggering this update, so should already be in-sync.
|
||||||
|
*/
|
||||||
|
private static void sendChannelData(EntityPlayer player, ItemStack holoStack, boolean onCursor) {
|
||||||
|
if (!(player instanceof EntityPlayerMP)) {
|
||||||
|
StructureLib.net.sendToServer(new SetChannelDataMessage(holoStack, onCursor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.gtnewhorizon.structurelib;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.util.ChatComponentTranslation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client-side-only confirmation gate for "wipe all channels" shift+middle-click gesture.
|
||||||
|
*/
|
||||||
|
public final class ChannelWipeConfirmation {
|
||||||
|
|
||||||
|
private static final long CONFIRM_WINDOW_MS = 5000;
|
||||||
|
private static long armedAtMs = -1;
|
||||||
|
|
||||||
|
private ChannelWipeConfirmation() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this before invoking {@link ChannelPickHandler} whenever the wipe gesture (shift+middle-click) is detected.
|
||||||
|
*
|
||||||
|
* @return true if this is a confirming second press within the window and the wipe should proceed now; false if
|
||||||
|
* this press only armed the confirmation.
|
||||||
|
*/
|
||||||
|
public static boolean confirm(EntityPlayer player) {
|
||||||
|
long now = Minecraft.getSystemTime();
|
||||||
|
if (now - armedAtMs > CONFIRM_WINDOW_MS) {
|
||||||
|
armedAtMs = now;
|
||||||
|
player.addChatMessage(new ChatComponentTranslation("structurelib.pickchannel.confirmwipe"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
armedAtMs = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import net.minecraft.util.IChatComponent;
|
|||||||
import net.minecraft.util.IIcon;
|
import net.minecraft.util.IIcon;
|
||||||
import net.minecraft.util.Vec3;
|
import net.minecraft.util.Vec3;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.client.event.MouseEvent;
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.common.config.ConfigElement;
|
import net.minecraftforge.common.config.ConfigElement;
|
||||||
@@ -40,6 +41,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
|
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
|
||||||
|
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||||
import com.gtnewhorizon.structurelib.net.RegistryOrderSyncMessage;
|
import com.gtnewhorizon.structurelib.net.RegistryOrderSyncMessage;
|
||||||
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
|
||||||
|
|
||||||
@@ -53,6 +55,8 @@ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
|||||||
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
|
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
|
||||||
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
|
||||||
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
||||||
|
import cpw.mods.fml.relauncher.Side;
|
||||||
|
import cpw.mods.fml.relauncher.SideOnly;
|
||||||
|
|
||||||
public class ClientProxy extends CommonProxy {
|
public class ClientProxy extends CommonProxy {
|
||||||
|
|
||||||
@@ -560,6 +564,35 @@ public class ClientProxy extends CommonProxy {
|
|||||||
|
|
||||||
public static class ForgeEventHandler {
|
public static class ForgeEventHandler {
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public void onMouseEvent(MouseEvent event) {
|
||||||
|
final EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||||
|
|
||||||
|
if (player == null || player.isDead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ItemStack heldItem = player.getHeldItem();
|
||||||
|
|
||||||
|
if (heldItem == null || !(heldItem.getItem() instanceof ItemConstructableTrigger)) return;
|
||||||
|
|
||||||
|
if (event.button != 2 || !event.buttonstate) return;
|
||||||
|
|
||||||
|
// Sink the middle click as soon as a projector is held, so vanilla pick block does not run
|
||||||
|
event.setCanceled(true);
|
||||||
|
|
||||||
|
final boolean isSneaking = player.isSneaking();
|
||||||
|
if (isSneaking && !ChannelWipeConfirmation.confirm(player)) return;
|
||||||
|
|
||||||
|
ChannelPickHandler.handleWorldPick(
|
||||||
|
player.worldObj,
|
||||||
|
player,
|
||||||
|
heldItem,
|
||||||
|
Minecraft.getMinecraft().objectMouseOver,
|
||||||
|
isSneaking);
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onEntityJoinWorld(EntityJoinWorldEvent e) {
|
public void onEntityJoinWorld(EntityJoinWorldEvent e) {
|
||||||
if (e.world.isRemote && e.entity instanceof EntityClientPlayerMP) {
|
if (e.world.isRemote && e.entity instanceof EntityClientPlayerMP) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import net.minecraftforge.common.MinecraftForge;
|
|||||||
import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
||||||
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
||||||
|
|
||||||
|
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||||
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
||||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||||
@@ -64,6 +65,8 @@ public class CommonProxy {
|
|||||||
|
|
||||||
public void preInit(FMLPreInitializationEvent e) {}
|
public void preInit(FMLPreInitializationEvent e) {}
|
||||||
|
|
||||||
|
public void init(FMLInitializationEvent e) {}
|
||||||
|
|
||||||
public long getOverworldTime() {
|
public long getOverworldTime() {
|
||||||
return MinecraftServer.getServer().getEntityWorld().getTotalWorldTime();
|
return MinecraftServer.getServer().getEntityWorld().getTotalWorldTime();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import com.gtnewhorizon.structurelib.util.XSTR;
|
|||||||
|
|
||||||
import cpw.mods.fml.common.Mod;
|
import cpw.mods.fml.common.Mod;
|
||||||
import cpw.mods.fml.common.SidedProxy;
|
import cpw.mods.fml.common.SidedProxy;
|
||||||
|
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||||
import cpw.mods.fml.common.event.FMLInterModComms;
|
import cpw.mods.fml.common.event.FMLInterModComms;
|
||||||
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
|
||||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||||
@@ -128,6 +129,11 @@ public class StructureLib {
|
|||||||
DevelopHelper.onPreInit();
|
DevelopHelper.onPreInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void init(FMLInitializationEvent e) {
|
||||||
|
proxy.init(e);
|
||||||
|
}
|
||||||
|
|
||||||
@Mod.EventHandler
|
@Mod.EventHandler
|
||||||
public void loadComplete(FMLLoadCompleteEvent e) {
|
public void loadComplete(FMLLoadCompleteEvent e) {
|
||||||
proxy.loadComplete(e);
|
proxy.loadComplete(e);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.gtnewhorizon.structurelib.core;
|
package com.gtnewhorizon.structurelib.core;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -7,7 +8,9 @@ import java.util.Set;
|
|||||||
|
|
||||||
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
|
import com.gtnewhorizon.gtnhmixins.IEarlyMixinLoader;
|
||||||
|
|
||||||
|
import cpw.mods.fml.relauncher.FMLLaunchHandler;
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||||
|
import cpw.mods.fml.relauncher.Side;
|
||||||
|
|
||||||
@IFMLLoadingPlugin.MCVersion("1.7.10")
|
@IFMLLoadingPlugin.MCVersion("1.7.10")
|
||||||
public class StructureLibCore implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
public class StructureLibCore implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||||
@@ -44,6 +47,11 @@ public class StructureLibCore implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getMixins(Set<String> loadedCoreMods) {
|
public List<String> getMixins(Set<String> loadedCoreMods) {
|
||||||
return Arrays.asList("blockChangeNotifier.MixinForgeHooks", "blockChangeNotifier.MixinWorld");
|
List<String> mixins = new ArrayList<>(
|
||||||
|
Arrays.asList("blockChangeNotifier.MixinForgeHooks", "blockChangeNotifier.MixinWorld"));
|
||||||
|
if (FMLLaunchHandler.side() == Side.CLIENT) {
|
||||||
|
mixins.add("MixinGuiContainer_PickChannel");
|
||||||
|
}
|
||||||
|
return mixins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
package com.gtnewhorizon.structurelib.mixins.early;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
|
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.inventory.Slot;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import com.gtnewhorizon.structurelib.ChannelPickHandler;
|
||||||
|
import com.gtnewhorizon.structurelib.ChannelWipeConfirmation;
|
||||||
|
import com.gtnewhorizon.structurelib.StructureLib;
|
||||||
|
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||||
|
|
||||||
|
import codechicken.nei.NEIClientConfig;
|
||||||
|
import codechicken.nei.guihook.GuiContainerManager;
|
||||||
|
import cpw.mods.fml.common.Loader;
|
||||||
|
|
||||||
|
@Mixin(value = GuiContainer.class, priority = 100)
|
||||||
|
public abstract class MixinGuiContainer_PickChannel {
|
||||||
|
|
||||||
|
@Inject(method = "mouseClicked(III)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void slib$onMouseClicked(int mouseX, int mouseY, int mouseButton, CallbackInfo ci) {
|
||||||
|
if (mouseButton != 2) return;
|
||||||
|
|
||||||
|
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||||
|
if (player == null) return;
|
||||||
|
|
||||||
|
ItemStack cursorStack = player.inventory.getItemStack();
|
||||||
|
if (cursorStack == null || !(cursorStack.getItem() instanceof ItemConstructableTrigger)) return;
|
||||||
|
|
||||||
|
// Sink middle click as soon as projector is picked up
|
||||||
|
ci.cancel();
|
||||||
|
|
||||||
|
ItemStack hoveredStack = null;
|
||||||
|
try {
|
||||||
|
Slot slot = slib$invokeGetSlotAtPosition(mouseX, mouseY);
|
||||||
|
if (slot != null) {
|
||||||
|
hoveredStack = slot.getStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try NEI
|
||||||
|
if (hoveredStack == null && Loader.isModLoaded("NotEnoughItems") && !NEIClientConfig.isHidden()) {
|
||||||
|
hoveredStack = GuiContainerManager.getStackMouseOver((GuiContainer) (Object) this);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
StructureLib.LOGGER.error("Error while resolving hovered slot for channel pick", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSneaking = GuiScreen.isShiftKeyDown();
|
||||||
|
if (isSneaking && !ChannelWipeConfirmation.confirm(player)) return;
|
||||||
|
|
||||||
|
ChannelPickHandler.handleMiddleClick(player, cursorStack, hoveredStack, isSneaking);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Invoker("getSlotAtPosition")
|
||||||
|
protected abstract Slot slib$invokeGetSlotAtPosition(int x, int y);
|
||||||
|
}
|
||||||
@@ -23,15 +23,22 @@ import io.netty.buffer.ByteBuf;
|
|||||||
public class SetChannelDataMessage implements IMessage {
|
public class SetChannelDataMessage implements IMessage {
|
||||||
|
|
||||||
private final List<Map.Entry<String, Integer>> data = new ArrayList<>();
|
private final List<Map.Entry<String, Integer>> data = new ArrayList<>();
|
||||||
|
private boolean onCursor;
|
||||||
|
|
||||||
public SetChannelDataMessage() {}
|
public SetChannelDataMessage() {}
|
||||||
|
|
||||||
public SetChannelDataMessage(ItemStack trigger) {
|
public SetChannelDataMessage(ItemStack trigger) {
|
||||||
|
this(trigger, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetChannelDataMessage(ItemStack trigger, final boolean onCursor) {
|
||||||
|
this.onCursor = onCursor;
|
||||||
ChannelDataAccessor.iterateChannelData(trigger).forEach(data::add);
|
ChannelDataAccessor.iterateChannelData(trigger).forEach(data::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fromBytes(ByteBuf buf) {
|
public void fromBytes(ByteBuf buf) {
|
||||||
|
onCursor = buf.readBoolean();
|
||||||
data.clear();
|
data.clear();
|
||||||
int size = ByteBufUtils.readVarShort(buf);
|
int size = ByteBufUtils.readVarShort(buf);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
@@ -41,6 +48,7 @@ public class SetChannelDataMessage implements IMessage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toBytes(ByteBuf buf) {
|
public void toBytes(ByteBuf buf) {
|
||||||
|
buf.writeBoolean(onCursor);
|
||||||
ByteBufUtils.writeVarShort(buf, data.size());
|
ByteBufUtils.writeVarShort(buf, data.size());
|
||||||
for (Entry<String, Integer> e : data) {
|
for (Entry<String, Integer> e : data) {
|
||||||
ByteBufUtils.writeUTF8String(buf, e.getKey());
|
ByteBufUtils.writeUTF8String(buf, e.getKey());
|
||||||
@@ -53,11 +61,11 @@ public class SetChannelDataMessage implements IMessage {
|
|||||||
@Override
|
@Override
|
||||||
public IMessage onMessage(SetChannelDataMessage message, MessageContext ctx) {
|
public IMessage onMessage(SetChannelDataMessage message, MessageContext ctx) {
|
||||||
EntityPlayerMP player = ctx.getServerHandler().playerEntity;
|
EntityPlayerMP player = ctx.getServerHandler().playerEntity;
|
||||||
ItemStack heldItem = player.getHeldItem();
|
ItemStack target = message.onCursor ? player.inventory.getItemStack() : player.getHeldItem();
|
||||||
if (heldItem != null && heldItem.getItem() instanceof ItemConstructableTrigger) {
|
if (target != null && target.getItem() instanceof ItemConstructableTrigger) {
|
||||||
ChannelDataAccessor.wipeChannelData(heldItem);
|
ChannelDataAccessor.wipeChannelData(target);
|
||||||
for (Entry<String, Integer> e : message.data) {
|
for (Entry<String, Integer> e : message.data) {
|
||||||
ChannelDataAccessor.setChannelData(heldItem, e.getKey(), e.getValue());
|
ChannelDataAccessor.setChannelData(target, e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
// since this is a set all channel request from the client, we would assume client already know
|
// since this is a set all channel request from the client, we would assume client already know
|
||||||
// what this would look like on the client, so no sync
|
// what this would look like on the client, so no sync
|
||||||
@@ -65,7 +73,7 @@ public class SetChannelDataMessage implements IMessage {
|
|||||||
StructureLib.LOGGER.warn(
|
StructureLib.LOGGER.warn(
|
||||||
"{} trying to set channel data on {}, which is not a hologram projector!",
|
"{} trying to set channel data on {}, which is not a hologram projector!",
|
||||||
player.getUniqueID(),
|
player.getUniqueID(),
|
||||||
heldItem);
|
target);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ item.structurelib.constructableTrigger.gui.info=Many multiblocks support some de
|
|||||||
channels.structurelib.show_errors=When set, will highlight parts of the multiblock that is definitely wrong
|
channels.structurelib.show_errors=When set, will highlight parts of the multiblock that is definitely wrong
|
||||||
|
|
||||||
structurelib.tooltip.channelvalue=§7Value §b%d§r§7 for subchannel §b%s
|
structurelib.tooltip.channelvalue=§7Value §b%d§r§7 for subchannel §b%s
|
||||||
structurelib.tooltip.indicator_dnd=Drop into GUI to select this value for this channel
|
structurelib.tooltip.indicator_dnd=Drop into GUI or middle-click to select this value for this channel
|
||||||
|
structurelib.pickchannel.success=§aSet §b%s§r§a to §b%d§r
|
||||||
|
structurelib.pickchannel.cleared=§aAll channels cleared§r
|
||||||
|
structurelib.pickchannel.confirmwipe=§6Sneak+Middle-click again to clear all channels
|
||||||
|
structurelib.pickchannel.nomapping=§cNo channel mapping found for this item
|
||||||
|
|
||||||
structurelib.autoplace.built_stat=Built %s blocks
|
structurelib.autoplace.built_stat=Built %s blocks
|
||||||
structurelib.autoplace.complete=§aThis multiblock has completed!
|
structurelib.autoplace.complete=§aThis multiblock has completed!
|
||||||
|
|||||||
Reference in new issue
Block a user