package appeng.fluids.parts; import appeng.api.AEApi; import appeng.api.config.RedstoneMode; import appeng.api.config.Settings; import appeng.api.networking.events.MENetworkChannelsChanged; import appeng.api.networking.events.MENetworkEventSubscribe; import appeng.api.networking.events.MENetworkPowerStatusChange; import appeng.api.networking.security.IActionSource; import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.storage.IStackWatcher; import appeng.api.networking.storage.IStackWatcherHost; import appeng.api.parts.IPartCollisionHelper; import appeng.api.parts.IPartModel; import appeng.api.storage.IMEMonitor; import appeng.api.storage.IMEMonitorHandlerReceiver; import appeng.api.storage.IStorageChannel; import appeng.api.storage.channels.IFluidStorageChannel; import appeng.api.storage.data.IAEFluidStack; import appeng.api.storage.data.IAEStack; import appeng.api.storage.data.IItemList; import appeng.api.util.AECableType; import appeng.api.util.AEPartLocation; import appeng.api.util.IConfigManager; import appeng.core.AppEng; import appeng.core.sync.GuiBridge; import appeng.fluids.helper.IConfigurableFluidInventory; import appeng.fluids.util.AEFluidInventory; import appeng.fluids.util.IAEFluidInventory; import appeng.fluids.util.IAEFluidTank; import appeng.items.parts.PartModels; import appeng.me.GridAccessException; import appeng.me.cache.NetworkMonitor; import appeng.parts.PartModel; import appeng.parts.automation.PartUpgradeable; import appeng.util.IConfigManagerHost; import appeng.util.Platform; import appeng.util.inv.InvOperation; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.IFluidHandler; import java.util.Random; public class PartFluidLevelEmitter extends PartUpgradeable implements IStackWatcherHost, IConfigManagerHost, IAEFluidInventory, IMEMonitorHandlerReceiver, IConfigurableFluidInventory { @PartModels public static final ResourceLocation MODEL_BASE_OFF = new ResourceLocation(AppEng.MOD_ID, "part/level_emitter_base_off"); @PartModels public static final ResourceLocation MODEL_BASE_ON = new ResourceLocation(AppEng.MOD_ID, "part/level_emitter_base_on"); @PartModels public static final ResourceLocation MODEL_STATUS_OFF = new ResourceLocation(AppEng.MOD_ID, "part/level_emitter_status_off"); @PartModels public static final ResourceLocation MODEL_STATUS_ON = new ResourceLocation(AppEng.MOD_ID, "part/level_emitter_status_on"); @PartModels public static final ResourceLocation MODEL_STATUS_HAS_CHANNEL = new ResourceLocation(AppEng.MOD_ID, "part/level_emitter_status_has_channel"); public static final PartModel MODEL_OFF_OFF = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_OFF); public static final PartModel MODEL_OFF_ON = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_ON); public static final PartModel MODEL_OFF_HAS_CHANNEL = new PartModel(MODEL_BASE_OFF, MODEL_STATUS_HAS_CHANNEL); public static final PartModel MODEL_ON_OFF = new PartModel(MODEL_BASE_ON, MODEL_STATUS_OFF); public static final PartModel MODEL_ON_ON = new PartModel(MODEL_BASE_ON, MODEL_STATUS_ON); public static final PartModel MODEL_ON_HAS_CHANNEL = new PartModel(MODEL_BASE_ON, MODEL_STATUS_HAS_CHANNEL); private static final int FLAG_ON = 4; private boolean prevState = false; private long lastReportedValue = 0; private long reportingValue = 0; private IStackWatcher stackWatcher = null; private final AEFluidInventory config = new AEFluidInventory(this, 1); public PartFluidLevelEmitter(ItemStack is) { super(is); this.getConfigManager().registerSetting(Settings.REDSTONE_EMITTER, RedstoneMode.HIGH_SIGNAL); } public long getReportingValue() { return this.reportingValue; } public void setReportingValue(final long v) { this.reportingValue = v; this.updateState(); } @Override public void updateSetting(IConfigManager manager, Enum settingName, Enum newValue) { this.configureWatchers(); } @Override public void updateWatcher(IStackWatcher newWatcher) { this.stackWatcher = newWatcher; this.configureWatchers(); } @Override public void onStackChange(IItemList o, IAEStack fullStack, IAEStack diffStack, IActionSource src, IStorageChannel chan) { if (chan == AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class) && fullStack.equals(this.config.getFluidInSlot(0))) { this.lastReportedValue = fullStack.getStackSize(); this.updateState(); } } @Override public void onFluidInventoryChanged(IAEFluidTank inv, int slot) { this.configureWatchers(); } @Override @MENetworkEventSubscribe public void powerRender(final MENetworkPowerStatusChange powerEvent) { if (this.getProxy().isActive()) { onListUpdate(); } this.updateState(); } @Override @MENetworkEventSubscribe public void chanRender(final MENetworkChannelsChanged c) { if (this.getProxy().isActive()) { onListUpdate(); } this.updateState(); } @Override public int isProvidingStrongPower() { return this.prevState ? 15 : 0; } @Override public int isProvidingWeakPower() { return this.prevState ? 15 : 0; } @Override protected int populateFlags(final int cf) { return cf | (this.prevState ? FLAG_ON : 0); } @Override public boolean isValid(final Object effectiveGrid) { try { return this.getProxy().getGrid() == effectiveGrid; } catch (final GridAccessException e) { return false; } } @Override public void postChange(final IBaseMonitor monitor, final Iterable change, final IActionSource actionSource) { this.updateReportingValue((IMEMonitor) monitor); } @Override public void onListUpdate() { try { final IStorageChannel channel = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class); final IMEMonitor inventory = this.getProxy().getStorage().getInventory(channel); this.updateReportingValue(inventory); } catch (final GridAccessException e) { // ;P } } private void updateState() { final boolean isOn = this.isLevelEmitterOn(); if (this.prevState != isOn) { this.getHost().markForUpdate(); final TileEntity te = this.getHost().getTile(); this.prevState = isOn; Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos()); Platform.notifyBlocksOfNeighbors(te.getWorld(), te.getPos().offset(this.getSide().getFacing())); } } private void configureWatchers() { final IFluidStorageChannel channel = AEApi.instance().storage().getStorageChannel(IFluidStorageChannel.class); if (this.stackWatcher != null) { this.stackWatcher.reset(); final IAEFluidStack myStack = this.config.getFluidInSlot(0); try { if (myStack != null) { this.getProxy().getStorage().getInventory(channel).removeListener(this); this.stackWatcher.add(myStack); } else { this.getProxy() .getStorage() .getInventory(channel) .addListener(this, this.getProxy().getGrid()); } final IMEMonitor inventory = this.getProxy().getStorage().getInventory(channel); this.updateReportingValue(inventory); } catch (GridAccessException e) { // NOP } } } private void updateReportingValue(final IMEMonitor monitor) { final IAEFluidStack myStack = this.config.getFluidInSlot(0); if (myStack == null) { if (monitor instanceof NetworkMonitor) { this.lastReportedValue = ((NetworkMonitor) monitor).getGridCurrentCount(); } } else { final IAEFluidStack r = monitor.getStorageList().findPrecise(myStack); if (r == null) { this.lastReportedValue = 0; } else { this.lastReportedValue = r.getStackSize(); } } this.updateState(); } private boolean isLevelEmitterOn() { if (Platform.isClient()) { return (this.getClientFlags() & FLAG_ON) == FLAG_ON; } if (!this.getProxy().isActive()) { return false; } final boolean flipState = this.getConfigManager().getSetting(Settings.REDSTONE_EMITTER) == RedstoneMode.LOW_SIGNAL; return flipState == (this.reportingValue > this.lastReportedValue); } @Override public AECableType getCableConnectionType(final AEPartLocation dir) { return AECableType.SMART; } @Override public float getCableConnectionLength(AECableType cable) { return 16; } @Override public boolean canConnectRedstone() { return true; } @Override public void getBoxes(final IPartCollisionHelper bch) { bch.addBox(7, 7, 11, 9, 9, 16); } @Override public void randomDisplayTick(final World world, final BlockPos pos, final Random r) { if (this.isLevelEmitterOn()) { final AEPartLocation d = this.getSide(); final double d0 = d.xOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D; final double d1 = d.yOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D; final double d2 = d.zOffset * 0.45F + (r.nextFloat() - 0.5F) * 0.2D; world.spawnParticle(EnumParticleTypes.REDSTONE, 0.5 + pos.getX() + d0, 0.5 + pos.getY() + d1, 0.5 + pos.getZ() + d2, 0.0D, 0.0D, 0.0D ); } } @Override public boolean onPartActivate(final EntityPlayer player, final EnumHand hand, final Vec3d pos) { if (Platform.isServer()) { Platform.openGUI(player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_FLUID_LEVEL_EMITTER); } return true; } @Override public IPartModel getStaticModels() { if (this.isActive() && this.isPowered()) { return this.isLevelEmitterOn() ? MODEL_ON_HAS_CHANNEL : MODEL_OFF_HAS_CHANNEL; } else if (this.isPowered()) { return this.isLevelEmitterOn() ? MODEL_ON_ON : MODEL_OFF_ON; } else { return this.isLevelEmitterOn() ? MODEL_ON_OFF : MODEL_OFF_OFF; } } public IAEFluidTank getConfig() { return this.config; } @Override public IFluidHandler getFluidInventoryByName(final String name) { if (name.equals("config")) { return this.config; } return null; } @Override public void readFromNBT(final NBTTagCompound data) { super.readFromNBT(data); this.lastReportedValue = data.getLong("lastReportedValue"); this.reportingValue = data.getLong("reportingValue"); this.prevState = data.getBoolean("prevState"); this.config.readFromNBT(data, "config"); } @Override public void writeToNBT(final NBTTagCompound data) { super.writeToNBT(data); data.setLong("lastReportedValue", this.lastReportedValue); data.setLong("reportingValue", this.reportingValue); data.setBoolean("prevState", this.prevState); this.config.writeToNBT(data, "config"); } }