Fix Cell Microscope drive scan (#127)

Co-authored-by: lc-1337 <62835225+lc-1337@users.noreply.github.com>
This commit is contained in:
Kogepan229andlc-1337 authored and GitHub committed 2026-05-07 14:35:20 +02:00
1 parent cbd89ad9bf
commit bb327adb35
3 files changed
+287 -104

No files matched your search

@@ -1,50 +1,54 @@
package thaumicenergistics.common.items;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static appeng.util.item.AEItemStackType.ITEM_STACK_TYPE;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.world.World;
import appeng.api.AEApi;
import appeng.api.storage.ICellContainer;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.ISaveProvider;
import appeng.api.storage.StorageChannel;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IItemList;
import appeng.items.storage.ItemBasicStorageCell;
import appeng.util.IterationCounter;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import thaumcraft.api.research.ScanResult;
import thaumcraft.common.Thaumcraft;
import thaumcraft.common.items.relics.ItemThaumometer;
import thaumcraft.common.lib.network.PacketHandler;
import thaumcraft.common.lib.network.playerdata.PacketScannedToServer;
import thaumcraft.common.lib.research.ScanManager;
import thaumcraft.common.lib.utils.EntityUtils;
import thaumicenergistics.common.network.packet.client.Packet_C_CellMicroscopeScanFeedback;
import thaumicenergistics.common.registries.ThEStrings;
public class ItemCellMicroscope extends ItemThaumometer {
private static final String TAG_SCAN_TYPE = "scanType";
private static final String TAG_SCAN_ENTITY = "scanEntity";
private static final String TAG_SCAN_X = "scanX";
private static final String TAG_SCAN_Y = "scanY";
private static final String TAG_SCAN_Z = "scanZ";
private static final byte TARGET_NONE = 0;
private static final byte TARGET_ENTITY_ITEM = 1;
private static final byte TARGET_CELL_CONTAINER = 2;
public ItemCellMicroscope() {
super();
}
List<ItemStack> startCells = new ArrayList<ItemStack>();
TileEntity cellSaveManager = null;
@SideOnly(Side.CLIENT)
@Override
public void registerIcons(IIconRegister ir) {
@@ -68,11 +72,14 @@ public class ItemCellMicroscope extends ItemThaumometer {
@Override
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer p) {
ScanTarget target = this.findScanTarget(world, p);
if (world.isRemote) {
ArrayList<ItemStack> cells = this.doScan(stack, world, p, 0);
if (cells.size() != 0) {
this.startCells = cells;
}
this.playScanEffects(world, target, 0);
} else if (target.isValid()) {
this.writeScanTarget(stack, target);
} else {
this.clearScanTarget(stack);
}
p.setItemInUse(stack, this.getMaxItemUseDuration(stack));
@@ -81,46 +88,49 @@ public class ItemCellMicroscope extends ItemThaumometer {
@Override
public void onUsingTick(ItemStack stack, EntityPlayer p, int count) {
if (p.worldObj.isRemote && Objects
.equals(p.getCommandSenderName(), Minecraft.getMinecraft().thePlayer.getCommandSenderName())) {
ScanTarget target = this.findScanTarget(p.worldObj, p);
ArrayList<ItemStack> cells = this.doScan(stack, p.worldObj, p, count);
if (cells.size() != 0 && cells.equals(this.startCells)) {
if (count <= 5) {
p.stopUsingItem();
this.startCells.clear();
for (ItemStack cell : cells) {
doCellScan(p, cell);
}
}
if (count % 2 == 0) {
p.worldObj.playSound(
p.posX,
p.posY,
p.posZ,
"thaumcraft:cameraticks",
0.2F,
0.45F + ((float) count / 50) + p.worldObj.rand.nextFloat() * 0.1F,
false);
}
} else {
this.startCells.clear();
}
}
}
private void doCellScan(EntityPlayer p, ItemStack cell) {
IMEInventory<IAEItemStack> inv = AEApi.instance().registries().cell()
.getCellInventory(cell, (ISaveProvider) cellSaveManager, StorageChannel.ITEMS);
if (inv == null) {
if (p.worldObj.isRemote) {
this.playScanEffects(p.worldObj, target, count);
return;
}
if (!this.matchesStoredScanTarget(stack, target)) {
this.clearScanTarget(stack);
p.stopUsingItem();
return;
}
if (count <= 5) {
p.stopUsingItem();
this.clearScanTarget(stack);
this.doScan(p, target);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void doScan(EntityPlayer p, ScanTarget target) {
if (target.type == TARGET_ENTITY_ITEM && target.entityItem != null) {
this.doCellScan(p, target.entityItem.getEntityItem());
} else if (target.type == TARGET_CELL_CONTAINER && target.tile instanceof ICellContainer) {
List<IMEInventoryHandler> cellArray = ((ICellContainer) target.tile).getCellArray(ITEM_STACK_TYPE);
for (IMEInventoryHandler cell : cellArray) {
this.doInventoryScan(p, cell);
}
}
}
@SuppressWarnings("unchecked")
private void doCellScan(EntityPlayer p, ItemStack cell) {
IMEInventory<IAEItemStack> inv = AEApi.instance().registries().cell()
.getCellInventory(cell, null, ITEM_STACK_TYPE);
this.doInventoryScan(p, inv);
}
private void doInventoryScan(EntityPlayer p, IMEInventory<IAEItemStack> inv) {
if (inv == null) return;
IItemList<IAEItemStack> itemList = inv
.getAvailableItems(AEApi.instance().storage().createItemList(), IterationCounter.fetchNewId());
@@ -128,72 +138,193 @@ public class ItemCellMicroscope extends ItemThaumometer {
ScanResult sr = new ScanResult((byte) 1, Item.getIdFromItem(i.getItem()), i.getItemDamage(), null, "");
if (ScanManager.isValidScanTarget(p, sr, "@")) {
ScanManager.completeScan(p, sr, "@");
PacketHandler.INSTANCE.sendToServer(new PacketScannedToServer(sr, p, "@"));
if (!ScanManager.completeScan(p, sr, "@")) {
// Thaumcraft syncs successful scans to the client, but not failed ones.
// Run the client-side scan path manually so failure hints are shown.
Packet_C_CellMicroscopeScanFeedback.sendScanFeedback(p, sr);
}
}
}
}
private ArrayList<ItemStack> doScan(ItemStack stack, World world, EntityPlayer p, int count) {
ArrayList<ItemStack> cellsOutput = new ArrayList<>();
private ScanTarget findScanTarget(World world, EntityPlayer p) {
Entity pointedEntity = EntityUtils.getPointedEntity(p.worldObj, p, 0.5D, 10.0D, 0.0F, true);
if (pointedEntity != null) {
if (pointedEntity instanceof EntityItem) {
if (((EntityItem) pointedEntity).getEntityItem().getItem() instanceof ItemBasicStorageCell) {
MovingObjectPosition mop = this.getMovingObjectPositionFromPlayer(p.worldObj, p, true);
try {
Thaumcraft.proxy.blockRunes(
world,
mop.blockX,
(double) mop.blockY + 0.50D,
mop.blockZ,
0.3F,
0.3F,
0.7F + world.rand.nextFloat() * 0.7F,
15,
-0.03F);
} catch (Exception ignored) {}
cellSaveManager = null;
cellsOutput.add(((EntityItem) pointedEntity).getEntityItem());
return cellsOutput;
}
if (pointedEntity instanceof EntityItem entityItem) {
if (this.isItemStorageCell(entityItem.getEntityItem())) {
return ScanTarget.forEntityItem(entityItem);
}
}
MovingObjectPosition lookingAtBlock = Minecraft.getMinecraft().objectMouseOver;
TileEntity blockAtPos = world
.getTileEntity(lookingAtBlock.blockX, lookingAtBlock.blockY, lookingAtBlock.blockZ);
if (blockAtPos instanceof ICellContainer) {
((ICellContainer) blockAtPos).getCellArray(StorageChannel.ITEMS);
IInventory inv = (IInventory) blockAtPos;
cellSaveManager = blockAtPos;
try {
Thaumcraft.proxy.blockRunes(
world,
lookingAtBlock.blockX,
lookingAtBlock.blockY,
lookingAtBlock.blockZ,
0.3F,
0.3F,
0.7F + world.rand.nextFloat() * 0.7F,
15,
-0.03F);
} catch (Exception ignored) {}
for (int i = 0; i < inv.getSizeInventory(); i++) {
ItemStack itemStack = inv.getStackInSlot(i);
if (itemStack != null) {
cellsOutput.add(itemStack);
}
MovingObjectPosition lookingAtBlock = this.getMovingObjectPositionFromPlayer(world, p, true);
if ((lookingAtBlock != null) && (lookingAtBlock.typeOfHit == MovingObjectType.BLOCK)) {
TileEntity blockAtPos = world
.getTileEntity(lookingAtBlock.blockX, lookingAtBlock.blockY, lookingAtBlock.blockZ);
if (blockAtPos instanceof ICellContainer) {
return ScanTarget.forCellContainer(lookingAtBlock, blockAtPos);
}
}
return cellsOutput;
return ScanTarget.none();
}
private boolean isItemStorageCell(ItemStack stack) {
if (stack == null) return false;
return AEApi.instance().registries().cell().getCellInventory(stack, null, ITEM_STACK_TYPE) != null;
}
private void playScanEffects(World world, ScanTarget target, int count) {
if (!target.isValid()) return;
if (count % 2 == 0) {
world.playSound(
target.effectX,
target.effectY,
target.effectZ,
"thaumcraft:cameraticks",
0.2F,
0.45F + ((float) count / 50) + world.rand.nextFloat() * 0.1F,
false);
}
try {
Thaumcraft.proxy.blockRunes(
world,
target.effectX,
target.effectY,
target.effectZ,
0.3F,
0.3F,
0.7F + world.rand.nextFloat() * 0.7F,
15,
-0.03F);
} catch (Exception ignored) {}
}
/**
* Stores the scan target selected at right-click time so the server can verify that the player is still looking at
* the same cell when the use action completes. These tags are temporary and are cleared when scanning stops.
*/
private void writeScanTarget(ItemStack stack, ScanTarget target) {
NBTTagCompound tag = stack.getTagCompound();
if (tag == null) {
tag = new NBTTagCompound();
stack.setTagCompound(tag);
}
tag.setByte(TAG_SCAN_TYPE, target.type);
tag.setInteger(TAG_SCAN_ENTITY, target.entityId);
tag.setInteger(TAG_SCAN_X, target.x);
tag.setInteger(TAG_SCAN_Y, target.y);
tag.setInteger(TAG_SCAN_Z, target.z);
}
/**
* Rejects the scan if the player moved to a different entity or block during the charge-up period.
*/
private boolean matchesStoredScanTarget(ItemStack stack, ScanTarget target) {
if (!target.isValid() || !stack.hasTagCompound()) return false;
NBTTagCompound tag = stack.getTagCompound();
byte type = tag.getByte(TAG_SCAN_TYPE);
if (type != target.type) return false;
if (type == TARGET_ENTITY_ITEM) {
return tag.getInteger(TAG_SCAN_ENTITY) == target.entityId;
}
return (tag.getInteger(TAG_SCAN_X) == target.x) && (tag.getInteger(TAG_SCAN_Y) == target.y)
&& (tag.getInteger(TAG_SCAN_Z) == target.z);
}
/**
* Removes the temporary scan target after completion, cancellation, or target mismatch so the item does not keep
* stale target data.
*/
private void clearScanTarget(ItemStack stack) {
if (!stack.hasTagCompound()) return;
NBTTagCompound tag = stack.getTagCompound();
tag.removeTag(TAG_SCAN_TYPE);
tag.removeTag(TAG_SCAN_ENTITY);
tag.removeTag(TAG_SCAN_X);
tag.removeTag(TAG_SCAN_Y);
tag.removeTag(TAG_SCAN_Z);
if (tag.hasNoTags()) {
stack.setTagCompound(null);
}
}
public void onPlayerStoppedUsing(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer,
int par4) {
super.onPlayerStoppedUsing(par1ItemStack, par2World, par3EntityPlayer, par4);
this.startCells.clear();
this.clearScanTarget(par1ItemStack);
}
private static class ScanTarget {
private final byte type;
private final int entityId;
private final int x;
private final int y;
private final int z;
private final double effectX;
private final double effectY;
private final double effectZ;
private final EntityItem entityItem;
private final TileEntity tile;
private ScanTarget(byte type, int entityId, int x, int y, int z, double effectX, double effectY, double effectZ,
EntityItem entityItem, TileEntity tile) {
this.type = type;
this.entityId = entityId;
this.x = x;
this.y = y;
this.z = z;
this.effectX = effectX;
this.effectY = effectY;
this.effectZ = effectZ;
this.entityItem = entityItem;
this.tile = tile;
}
private static ScanTarget none() {
return new ScanTarget(TARGET_NONE, 0, 0, 0, 0, 0, 0, 0, null, null);
}
private static ScanTarget forEntityItem(EntityItem entityItem) {
return new ScanTarget(
TARGET_ENTITY_ITEM,
entityItem.getEntityId(),
0,
0,
0,
entityItem.posX,
entityItem.posY + 0.5D,
entityItem.posZ,
entityItem,
null);
}
private static ScanTarget forCellContainer(MovingObjectPosition position, TileEntity tile) {
return new ScanTarget(
TARGET_CELL_CONTAINER,
0,
position.blockX,
position.blockY,
position.blockZ,
position.blockX,
position.blockY,
position.blockZ,
null,
tile);
}
private boolean isValid() {
return this.type != TARGET_NONE;
}
}
}
@@ -10,6 +10,7 @@ import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import cpw.mods.fml.relauncher.Side;
import thaumicenergistics.common.ThaumicEnergistics;
import thaumicenergistics.common.network.packet.client.Packet_C_ArcaneCraftingTerminal;
import thaumicenergistics.common.network.packet.client.Packet_C_CellMicroscopeScanFeedback;
import thaumicenergistics.common.network.packet.client.Packet_C_DistillationEncoder;
import thaumicenergistics.common.network.packet.client.Packet_C_EssentiaVibrationChamber;
import thaumicenergistics.common.network.packet.client.Packet_C_ExportBusVoidButtonUpdate;
@@ -127,6 +128,9 @@ public class NetworkHandler {
// Sync packet
registerPacket(Packet_C_Sync.class);
// Cell microscope
registerPacket(Packet_C_CellMicroscopeScanFeedback.class);
registerPacket(Packet_S_NEIRecipe.class);
}
@@ -0,0 +1,48 @@
package thaumicenergistics.common.network.packet.client;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import thaumcraft.api.research.ScanResult;
import thaumcraft.common.lib.research.ScanManager;
import thaumicenergistics.common.network.NetworkHandler;
public class Packet_C_CellMicroscopeScanFeedback extends ThEClientPacket {
private int itemId;
private int itemDamage;
public static void sendScanFeedback(final EntityPlayer player, final ScanResult scanResult) {
Packet_C_CellMicroscopeScanFeedback packet = new Packet_C_CellMicroscopeScanFeedback();
packet.player = player;
packet.itemId = scanResult.id;
packet.itemDamage = scanResult.meta;
NetworkHandler.sendPacketToClient(packet);
}
@Override
protected void readData(final ByteBuf stream) {
this.itemId = stream.readInt();
this.itemDamage = stream.readInt();
}
@SideOnly(Side.CLIENT)
@Override
protected void wrappedExecute() {
ScanResult scanResult = new ScanResult((byte) 1, this.itemId, this.itemDamage, null, "");
if (Item.getItemById(this.itemId) != null) {
ScanManager.completeScan(this.player, scanResult, "@");
}
}
@Override
protected void writeData(final ByteBuf stream) {
stream.writeInt(this.itemId);
stream.writeInt(this.itemDamage);
}
}