package mods.eln.transparentnode.teleporter; import mods.eln.i18n.I18N; import mods.eln.misc.Coordonate; import mods.eln.misc.Direction; import mods.eln.misc.LRDU; import mods.eln.misc.Utils; import mods.eln.node.NodePeriodicPublishProcess; import mods.eln.node.transparent.TransparentNode; import mods.eln.node.transparent.TransparentNodeDescriptor; import mods.eln.node.transparent.TransparentNodeElement; import mods.eln.sim.ElectricalLoad; import mods.eln.sim.IProcess; import mods.eln.sim.ThermalLoad; import mods.eln.sim.mna.component.Resistor; import mods.eln.sim.nbt.NbtElectricalLoad; import mods.eln.sim.process.destruct.VoltageStateWatchDog; import mods.eln.sim.process.destruct.WorldExplosion; import mods.eln.sixnode.lampsocket.LightBlockEntity; import mods.eln.sound.SoundCommand; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.AxisAlignedBB; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TeleporterElement extends TransparentNodeElement implements ITeleporter { TeleporterDescriptor descriptor; NbtElectricalLoad powerLoad = new NbtElectricalLoad("powerLoad"); Resistor powerResistor = new Resistor(powerLoad, null); TeleporterSlowProcess slowProcess = new TeleporterSlowProcess(); NodePeriodicPublishProcess publisher; static public final ArrayList<ITeleporter> teleporterList = new ArrayList<ITeleporter>(); public TeleporterElement(TransparentNode transparentNode, TransparentNodeDescriptor descriptor) { super(transparentNode, descriptor); this.descriptor = (TeleporterDescriptor) descriptor; publisher = new NodePeriodicPublishProcess(node, 2, 1); powerLoad.isPrivateSubSystem(); electricalLoadList.add(powerLoad); electricalComponentList.add(powerResistor); slowProcessList.add(slowProcess); slowProcessList.add(publisher); teleporterList.add(this); WorldExplosion exp = new WorldExplosion(this).machineExplosion(); slowProcessList.add(voltageWatchdog.set(powerLoad).setUNominal(this.descriptor.cable.electricalNominalVoltage).set(exp)); } VoltageStateWatchDog voltageWatchdog = new VoltageStateWatchDog(); Coordonate lightCoordonate; @Override public ElectricalLoad getElectricalLoad(Direction side, LRDU lrdu) { return powerLoad; } @Override public ThermalLoad getThermalLoad(Direction side, LRDU lrdu) { return null; } @Override public int getConnectionMask(Direction side, LRDU lrdu) { if (side == Direction.YP || side == Direction.YN) return 0; if (lrdu != LRDU.Down) return 0; return node.maskElectricalPower; } @Override public String multiMeterString(Direction side) { return null; } @Override public String thermoMeterString(Direction side) { return null; } @Override public boolean hasGui() { return true; } @Override public void initialize() { descriptor.cable.applyTo(powerLoad); powerResistor.highImpedance(); for (Coordonate c : descriptor.getPowerCoordonate(node.coordonate.world())) { TeleporterPowerNode n = new TeleporterPowerNode(); n.setElement(this); c.applyTransformation(front, node.coordonate); n.onBlockPlacedBy(c, Direction.XN, null, null); powerNodeList.add(n); } lightCoordonate = new Coordonate(this.descriptor.lightCoordonate); lightCoordonate.applyTransformation(front, node.coordonate); descriptor.ghostDoorClose.newRotate(front).eraseGeo(node.coordonate); descriptor.ghostDoorOpen.newRotate(front).plot(node.coordonate, node.coordonate, descriptor.getGhostGroupUuid()); connect(); } @Override public void onBreakElement() { super.onBreakElement(); for (TeleporterPowerNode n : powerNodeList) { n.onBreakBlock(); } powerNodeList.clear(); unregister(); } ArrayList<TeleporterPowerNode> powerNodeList = new ArrayList<TeleporterPowerNode>(); @Override public void unload() { super.unload(); unregister(); } void unregister() { teleporterList.remove(this); } @Override public boolean onBlockActivated(EntityPlayer entityPlayer, Direction side, float vx, float vy, float vz) { return false; } String name = "Unnamed", targetName = "Unnamed"; double energyHit = 0; double energyTarget = 0; double powerCharge = 2000; @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); nbt.setString("name", name); nbt.setString("targetName", targetName); nbt.setDouble("powerCharge", powerCharge); nbt.setBoolean("reset", state != StateIdle); } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); name = nbt.getString("name"); targetName = nbt.getString("targetName"); powerCharge = nbt.getDouble("powerCharge"); if (nbt.getBoolean("reset")) state = StateReset; } public static final byte StateIdle = 0; public static final byte StateStart = 1; public static final byte StateClose = 2; public static final byte StateCharge = 3; public static final byte StateTeleport = 4; public static final byte StateOpen = 5; public static final byte StateReserved = 6; public static final byte StateReset = 7; byte state = StateIdle; float timeCounter; boolean doorState = true; void setState(byte state) { if (state != this.state) { timeCounter = 0; switch (this.state) { case StateCharge: powerResistor.highImpedance(); publisher.reconfigure(2, 1); energyHit = 0; processRatio = 0; break; case StateReserved: publisher.reconfigure(2, 1); doorState = true; processRatio = 0; break; case StateClose: descriptor.ghostDoorOpen.newRotate(front).eraseGeo(node.coordonate); break; case StateOpen: descriptor.ghostDoorClose.newRotate(front).eraseGeo(node.coordonate); break; default: break; } this.state = state; switch (this.state) { case StateClose: doorState = false; descriptor.ghostDoorClose.newRotate(front).plot(node.coordonate, node.coordonate, descriptor.getGhostGroupUuid()); break; case StateOpen: doorState = true; descriptor.ghostDoorOpen.newRotate(front).plot(node.coordonate, node.coordonate, descriptor.getGhostGroupUuid()); break; case StateCharge: powerResistor.setR(Math.pow(descriptor.cable.electricalNominalVoltage, 2) / powerCharge); publisher.reconfigure(0.4, 0); break; case StateReserved: publisher.reconfigure(0.4, 0); break; default: break; } Utils.println("Teleporter state=" + state); needPublish(); } } @Override public boolean reservate() { if (state != StateIdle) return false; if (powerLoad.getU() < descriptor.cable.electricalNominalVoltage * 0.8) return false; setState(StateReserved); imMaster = false; return true; } @Override public void reservateRefresh(boolean doorState, float processRatio) { reservateRefreshed = true; if (this.doorState == false && doorState == true) { setState(StateOpen); // setState(StateReserved); } if (this.doorState == true && doorState == false) { setState(StateClose); // setState(StateReserved); } this.processRatio = processRatio; } boolean reservateRefreshed = false; float processRatio = 0; public static final byte eventNoTargetFind = 1; public static final byte eventMultipleoTargetFind = 2; public static final byte eventTargetFind = 3; public static final byte eventSameTarget = 4; public static final byte eventNotSameDimensionTarget = 5; public static final byte eventTargetBusy = 6; public static final byte eventInstablePowerSupply = 7; boolean imMaster = false; class TeleporterSlowProcess implements IProcess { int dx, dy, dz; int blinkCounter = 0; int soundCounter = 0; String targetNameCopy = ""; @Override public void process(double time) { { ITeleporter target = getTarget(state == StateIdle ? targetName : targetNameCopy); if (target == null) { energyTarget = 0; } else { Coordonate c = getTeleportCoordonate(); double distance = getTeleportCoordonate().trueDistanceTo(target.getTeleportCoordonate()); AxisAlignedBB bb = descriptor.getBB(node.coordonate, front); int playerCount = c.world().getEntitiesWithinAABB(EntityPlayer.class, bb).size(); int itemCount = c.world().getEntitiesWithinAABB(EntityItem.class, bb).size(); int petCount = c.world().getEntitiesWithinAABB(EntityLivingBase.class, bb).size() - playerCount; // Object o = c.world().getEntitiesWithinAABB(EntityItem.class,bb); energyTarget = 10000 + 40000 * playerCount + 5000 * petCount + 5000 * itemCount; energyTarget *= 1.0 + Math.pow(distance / 250.0, 0.5); } } if (++blinkCounter >= 9) { blinkCounter = 0; if ((powerLoad.getU() / descriptor.cable.electricalNominalVoltage - 0.5) * 3 > Math.random()) LightBlockEntity.addLight(lightCoordonate, 12, 11); } switch (state) { case StateReserved: if (reservateRefreshed == false) { if (doorState == false) setState(StateOpen); else setState(StateIdle); } break; case StateIdle: imMaster = false; if (startFlag) { targetNameCopy = targetName; energyHit = 0; if (targetNameCopy.equals(name)) { sendIdToAllClient(eventSameTarget); break; } int count = getTargetCount(targetNameCopy); if (count == 0) { sendIdToAllClient(eventNoTargetFind); break; } if (count > 1) { sendIdToAllClient(eventMultipleoTargetFind); break; } if (powerLoad.getU() < descriptor.cable.electricalNominalVoltage * 0.8) { break; } ITeleporter target = getTarget(targetNameCopy); if (target.reservate() == false) { sendIdToAllClient(eventTargetBusy); break; } sendIdToAllClient(eventTargetFind); /* * AxisAlignedBB bb = descriptor.getBB(node.coordonate,front); List list = node.coordonate.world().getEntitiesWithinAABB(EntityItem.class, bb); for(Object o : list){ Entity e = (Entity)o; if(e instanceof EntityPlayerMP) ((EntityPlayerMP)e).setPositionAndUpdate(e.posX + dx, e.posY + dy, e.posZ + dz); else e.setPosition(e.posX + dx, e.posY + dy, e.posZ + dz); } */ imMaster = true; setState(StateStart); } break; case StateStart: { int count = node.coordonate.world().getEntitiesWithinAABB(Entity.class, descriptor.getBB(node.coordonate, front)).size(); if (count == 0) { timeCounter = 0; } else { timeCounter += time; if (timeCounter > 2) { setState(StateClose); } } } break; case StateClose: timeCounter += time; if (timeCounter > 3) { if (reservateRefreshed) setState(StateReserved); else { setState(StateCharge); soundCounter = 0; } } break; case StateCharge: { if (soundCounter++ % 18 == 0) play(new SoundCommand(descriptor.chargeSound).mulVolume(descriptor.chargeVolume, 1f)); if (targetNameCopy.equals(name)) { sendIdToAllClient(eventSameTarget); setState(StateOpen); break; } int count = getTargetCount(targetNameCopy); if (count == 0) { sendIdToAllClient(eventNoTargetFind); setState(StateOpen); break; } if (count > 1) { sendIdToAllClient(eventMultipleoTargetFind); setState(StateOpen); break; } if (powerLoad.getU() < descriptor.cable.electricalNominalVoltage * 0.8) { sendIdToAllClient(eventInstablePowerSupply); AxisAlignedBB bb = descriptor.getBB(node.coordonate, front); List list = node.coordonate.world().getEntitiesWithinAABB(Entity.class, bb); for (Object o : list) { Entity e = (Entity) o; double failDistance = 1000; while (true) { int x, y, z; x = (int) (e.posX + (Math.random() * 2 - 1) * failDistance); z = (int) (e.posZ + (Math.random() * 2 - 1) * failDistance); y = 20; while (e.worldObj.getBlock(x, y, z) != Blocks.air && e.worldObj.getBlock(x, y + 1, z) != Blocks.air) { y++; } Utils.serverTeleport(e, x + 0.5, y, z + 0.5); break; } } setState(StateOpen); } else { ITeleporter target = getTarget(targetNameCopy); Coordonate c = getTeleportCoordonate(); // double distance = getTeleportCoordonate().trueDistanceTo(c); // AxisAlignedBB bb = descriptor.getBB(node.coordonate, front); // int playerCount = c.world().getEntitiesWithinAABB(EntityPlayer.class, bb).size(); // int itemCount = c.world().getEntitiesWithinAABB(EntityItem.class, bb).size(); // int petCount = c.world().getEntitiesWithinAABB(EntityLivingBase.class, bb).size() - playerCount; // // Object o = c.world().getEntitiesWithinAABB(EntityItem.class,bb); // energyTarget = 10000 + // 40000 * playerCount + // 5000 * petCount + // 5000 * itemCount; // // energyTarget *= 1.0 + Math.pow(distance / 250.0, 0.5); energyHit += powerResistor.getP() * time; processRatio = (float) (energyHit / energyTarget); if (energyHit >= energyTarget) { dx = target.getTeleportCoordonate().x - c.x; dy = target.getTeleportCoordonate().y - c.y; dz = target.getTeleportCoordonate().z - c.z; setState(StateTeleport); } } } break; case StateTeleport: { timeCounter += time; if (timeCounter > 0) { AxisAlignedBB bb = descriptor.getBB(node.coordonate, front); List list = node.coordonate.world().getEntitiesWithinAABB(Entity.class, bb); for (Object o : list) { Entity e = (Entity) o; Utils.serverTeleport(e, e.posX + dx, e.posY + dy, e.posZ + dz); } setState(StateOpen); } } break; case StateOpen: timeCounter += time; if (timeCounter > 3) { if (reservateRefreshed) setState(StateReserved); else setState(StateIdle); } break; case StateReset: setState(StateIdle); break; } if (state != StateIdle && imMaster) { ITeleporter target = getTarget(targetNameCopy); if (target != null) target.reservateRefresh(doorState, processRatio); } reservateRefreshed = false; startFlag = false; } } int getTargetCount(String str) { int count = 0; for (ITeleporter t : teleporterList) { if (t.getName().equals(str) && node.coordonate.dimention == t.getTeleportCoordonate().dimention) { count++; } } return count; } ITeleporter getTarget(String str) { ITeleporter target = null; for (ITeleporter t : teleporterList) { if (t.getName().equals(str) && node.coordonate.dimention == t.getTeleportCoordonate().dimention) { if (target != null) return null; target = t; } } return target; } boolean startFlag = false; public static final byte setNameId = 1; public static final byte startId = 2; public static final byte setTargetNameId = 3; public static final byte setChargePowerId = 4; @Override public byte networkUnserialize(DataInputStream stream) { switch (super.networkUnserialize(stream)) { case setNameId: if (state != StateIdle) break; try { name = stream.readUTF(); } catch (IOException e) { e.printStackTrace(); } needPublish(); break; case setTargetNameId: if (state != StateIdle) break; try { targetName = stream.readUTF(); } catch (IOException e) { e.printStackTrace(); } needPublish(); break; case startId: startFlag = true; break; case setChargePowerId: if (state != StateIdle) break; try { powerCharge = stream.readFloat(); } catch (IOException e) { e.printStackTrace(); } needPublish(); break; } return unserializeNulldId; } @Override public void networkSerialize(DataOutputStream stream) { super.networkSerialize(stream); try { stream.writeUTF(name); stream.writeUTF(targetName); stream.writeFloat((float) powerCharge); stream.writeByte(state); stream.writeByte( (doorState ? 0x1 : 0x0) ); stream.writeFloat(processRatio); stream.writeFloat((float) powerLoad.getU()); stream.writeFloat((float) energyHit); stream.writeFloat((float) energyTarget); // stream.writeFloat((float) energyHit); // stream.writeFloat((float) energyTarget); } catch (IOException e) { e.printStackTrace(); } } @Override public Coordonate getTeleportCoordonate() { return descriptor.getTeleportCoordonate(front, node.coordonate); } @Override public String getName() { return name; } @Override public Map<String, String> getWaila() { Map<String, String> info = new HashMap<String, String>(); info.put(I18N.tr("Destination"), targetName); info.put(I18N.tr("Distance"), Utils.plotValue(getTeleportCoordonate().trueDistanceTo(getTarget(targetName).getTeleportCoordonate()), "m")); info.put(I18N.tr("Required energy"), Utils.plotEnergy("", energyTarget)); info.put(I18N.tr("Charge power"), Utils.plotPower("", powerCharge)); return info; } }