Hbm-s-Nuclear-Tech-GIT/src/main/java/com/hbm/tileentity/machine/TileEntityMachineRadarNT.java
Kirby7871 d01f54d1ba
Update TileEntityMachineRadarNT.java
Fixed a comma typo
2025-05-29 02:36:36 +02:00

749 lines
23 KiB
Java

package com.hbm.tileentity.machine;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonWriter;
import com.hbm.extprop.HbmLivingProps;
import com.hbm.handler.CompatHandler;
import com.hbm.interfaces.IControlReceiver;
import com.hbm.inventory.container.ContainerMachineRadarNT;
import com.hbm.inventory.gui.GUIMachineRadarNT;
import com.hbm.inventory.gui.GUIMachineRadarNTSlots;
import com.hbm.items.ISatChip;
import com.hbm.items.ModItems;
import com.hbm.items.tool.ItemCoordinateBase;
import com.hbm.lib.Library;
import com.hbm.main.MainRegistry;
import com.hbm.saveddata.SatelliteSavedData;
import com.hbm.saveddata.satellites.Satellite;
import com.hbm.saveddata.satellites.SatelliteHorizons;
import com.hbm.saveddata.satellites.SatelliteLaser;
import com.hbm.saveddata.satellites.SatelliteResonator;
import com.hbm.tileentity.IConfigurableMachine;
import com.hbm.tileentity.IGUIProvider;
import com.hbm.tileentity.IRadarCommandReceiver;
import com.hbm.tileentity.TileEntityMachineBase;
import com.hbm.util.Tuple.Triplet;
import com.hbm.util.fauxpointtwelve.BlockPos;
import com.hbm.util.fauxpointtwelve.DirPos;
import com.hbm.world.WorldUtil;
import api.hbm.energymk2.IEnergyReceiverMK2;
import api.hbm.entity.IRadarDetectable;
import api.hbm.entity.IRadarDetectableNT;
import api.hbm.entity.IRadarDetectableNT.RadarScanParams;
import api.hbm.entity.RadarEntry;
import cpw.mods.fml.common.Optional;
import cpw.mods.fml.common.network.internal.FMLNetworkHandler;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import li.cil.oc.api.machine.Arguments;
import li.cil.oc.api.machine.Callback;
import li.cil.oc.api.machine.Context;
import li.cil.oc.api.network.SimpleComponent;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
/**
* Now with SmЯt™ lag-free entity detection! (patent pending)
* @author hbm
*/
@Optional.InterfaceList({@Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers")})
public class TileEntityMachineRadarNT extends TileEntityMachineBase implements IEnergyReceiverMK2, IGUIProvider, IConfigurableMachine, IControlReceiver, SimpleComponent, CompatHandler.OCComponent {
public boolean scanMissiles = true;
public boolean scanShells = true;
public boolean scanPlayers = true;
public boolean smartMode = true;
public boolean redMode = true;
public boolean showMap = false;
public boolean jammed = false;
public float prevRotation;
public float rotation;
public long power = 0;
protected int pingTimer = 0;
protected int lastPower;
protected final static int maxTimer = 80;
public static int maxPower = 100_000;
public static int consumption = 500;
public static int radarRange = 1_000;
public static int radarBuffer = 30;
public static int radarAltitude = 55;
public static int chunkLoadCap = 10;
public static boolean generateChunks = false;
public byte[] map = new byte[40_000];
public boolean clearFlag = false;
public List<RadarEntry> entries = new ArrayList();
@Override
public String getConfigName() {
return "radar";
}
@Override
public void readIfPresent(JsonObject obj) {
maxPower = IConfigurableMachine.grab(obj, "L:powerCap", maxPower);
consumption = IConfigurableMachine.grab(obj, "L:consumption", consumption);
radarRange = IConfigurableMachine.grab(obj, "I:radarRange", radarRange);
radarBuffer = IConfigurableMachine.grab(obj, "I:radarBuffer", radarBuffer);
radarAltitude = IConfigurableMachine.grab(obj, "I:radarAltitude", radarAltitude);
chunkLoadCap = IConfigurableMachine.grab(obj, "I:chunkLoadCap", chunkLoadCap);
generateChunks = IConfigurableMachine.grab(obj, "B:generateChunks", generateChunks);
}
@Override
public void writeConfig(JsonWriter writer) throws IOException {
writer.name("L:powerCap").value(maxPower);
writer.name("L:consumption").value(consumption);
writer.name("I:radarRange").value(radarRange);
writer.name("I:radarBuffer").value(radarBuffer);
writer.name("I:radarAltitude").value(radarAltitude);
writer.name("B:generateChunks").value(generateChunks);
}
public TileEntityMachineRadarNT() {
super(10);
}
@Override
public String getName() {
return "container.radar";
}
public int getRange() {
return radarRange;
}
@Override
public void updateEntity() {
if(this.map == null || this.map.length != 40_000) this.map = new byte[40_000];
if(!worldObj.isRemote) {
this.power = Library.chargeTEFromItems(slots, 9, power, maxPower);
if(worldObj.getTotalWorldTime() % 20 == 0) {
for(DirPos pos : getConPos()) {
this.trySubscribe(worldObj, pos.getX(), pos.getY(), pos.getZ(), pos.getDir());
}
}
this.power = Library.chargeTEFromItems(slots, 0, power, maxPower);
this.jammed = false;
allocateTargets();
if(this.lastPower != getRedPower()) {
this.markChanged();
for(DirPos pos : getConPos()) this.updateRedstoneConnection(pos);
}
lastPower = getRedPower();
if(!this.muffled) {
pingTimer++;
if(power > 0 && pingTimer >= maxTimer) {
this.worldObj.playSoundEffect(this.xCoord, this.yCoord, this.zCoord, "hbm:block.sonarPing", 5.0F, 1.0F);
pingTimer = 0;
}
}
if(this.showMap) {
int chunkLoads = 0;
for(int i = 0; i < 100; i++) {
int index = (int) (worldObj.getTotalWorldTime() % 400) * 100 + i;
int iX = (index % 200) * getRange() * 2 / 200;
int iZ = index / 200 * getRange() * 2 / 200;
int x = xCoord - getRange() + iX;
int z = zCoord - getRange() + iZ;
if(worldObj.getChunkProvider().chunkExists(x >> 4, z >> 4)) {
this.map[index] = (byte) MathHelper.clamp_int(worldObj.getHeightValue(x, z), 50, 128);
} else {
if(this.map[index] == 0 && chunkLoads < chunkLoadCap) {
if(this.generateChunks) {
worldObj.getChunkFromChunkCoords(x >> 4, z >> 4);
this.map[index] = (byte) MathHelper.clamp_int(worldObj.getHeightValue(x, z), 50, 128);
chunkLoads++;
} else {
WorldUtil.provideChunk((WorldServer) worldObj, x >> 4, z >> 4);
this.map[index] = (byte) MathHelper.clamp_int(worldObj.getHeightValue(x, z), 50, 128);
if(worldObj.getChunkProvider().chunkExists(x >> 4, z >> 4)) chunkLoads++;
}
}
}
}
}
if(slots[8] != null && slots[8].getItem() == ModItems.radar_linker) {
BlockPos pos = ItemCoordinateBase.getPosition(slots[8]);
if(pos != null) {
TileEntity tile = worldObj.getTileEntity(pos.getX(), pos.getY(), pos.getZ());
if(tile instanceof TileEntityMachineRadarScreen) {
TileEntityMachineRadarScreen screen = (TileEntityMachineRadarScreen) tile;
screen.entries.clear();
screen.entries.addAll(this.entries);
screen.refX = xCoord;
screen.refY = yCoord;
screen.refZ = zCoord;
screen.range = this.getRange();
screen.linked = true;
screen.networkPackNT(25);
}
}
}
this.networkPackNT(50);
if(this.clearFlag) {
this.map = new byte[40_000];
this.clearFlag = false;
}
} else {
prevRotation = rotation;
if(power > 0) rotation += 5F;
if(rotation >= 360) {
rotation -= 360F;
prevRotation -= 360F;
}
}
}
public DirPos[] getConPos() {
return new DirPos[] {
new DirPos(xCoord + 1, yCoord, zCoord, Library.POS_X),
new DirPos(xCoord - 1, yCoord, zCoord, Library.NEG_X),
new DirPos(xCoord, yCoord, zCoord + 1, Library.POS_Z),
new DirPos(xCoord, yCoord, zCoord - 1, Library.NEG_Z),
};
}
@Override
public void serialize(ByteBuf buf) {
super.serialize(buf);
buf.writeLong(this.power);
buf.writeBoolean(this.scanMissiles);
buf.writeBoolean(this.scanShells);
buf.writeBoolean(this.scanPlayers);
buf.writeBoolean(this.smartMode);
buf.writeBoolean(this.redMode);
buf.writeBoolean(this.showMap);
buf.writeBoolean(this.jammed);
buf.writeInt(entries.size());
for(RadarEntry entry : entries) entry.toBytes(buf);
if(this.clearFlag) {
buf.writeBoolean(true);
} else {
buf.writeBoolean(false);
if(this.showMap) {
buf.writeBoolean(true);
short index = (short) (worldObj.getTotalWorldTime() % 400);
buf.writeShort(index);
for(int i = index * 100; i < (index + 1) * 100; i++) {
buf.writeByte(this.map[i]);
}
} else {
buf.writeBoolean(false);
}
}
}
@Override
public void deserialize(ByteBuf buf) {
super.deserialize(buf);
this.power = buf.readLong();
this.scanMissiles = buf.readBoolean();
this.scanShells = buf.readBoolean();
this.scanPlayers = buf.readBoolean();
this.smartMode = buf.readBoolean();
this.redMode = buf.readBoolean();
this.showMap = buf.readBoolean();
this.jammed = buf.readBoolean();
int count = buf.readInt();
this.entries.clear();
for(int i = 0; i < count; i++) {
RadarEntry entry = new RadarEntry();
entry.fromBytes(buf);
this.entries.add(entry);
}
if(buf.readBoolean()) { // clear flag
this.map = new byte[40_000];
} else {
if(buf.readBoolean()) { // map enabled
int index = buf.readShort();
for(int i = index * 100; i < (index + 1) * 100; i++) {
this.map[i] = buf.readByte();
}
}
}
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
this.power = nbt.getLong("power");
this.scanMissiles = nbt.getBoolean("scanMissiles");
this.scanShells = nbt.getBoolean("scanShells");
this.scanPlayers = nbt.getBoolean("scanPlayers");
this.smartMode = nbt.getBoolean("smartMode");
this.redMode = nbt.getBoolean("redMode");
this.showMap = nbt.getBoolean("showMap");
if(nbt.hasKey("map")) this.map = nbt.getByteArray("map");
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt);
nbt.setLong("power", power);
nbt.setBoolean("scanMissiles", scanMissiles);
nbt.setBoolean("scanShells", scanShells);
nbt.setBoolean("scanPlayers", scanPlayers);
nbt.setBoolean("smartMode", smartMode);
nbt.setBoolean("redMode", redMode);
nbt.setBoolean("showMap", showMap);
nbt.setByteArray("map", map);
}
protected void allocateTargets() {
this.entries.clear();
if(this.yCoord < radarAltitude) return;
if(this.power < consumption) {
this.power = 0;
return;
}
this.power -= consumption;
int scan = this.getRange();
RadarScanParams params = new RadarScanParams(this.scanMissiles, this.scanShells, this.scanPlayers, this.smartMode);
for(Entity e : matchingEntities) {
if(e.dimension == worldObj.provider.dimensionId && Math.abs(e.posX - (xCoord + 0.5)) <= scan && Math.abs(e.posZ - (zCoord + 0.5)) <= scan && e.posY - yCoord > radarBuffer) {
if(e instanceof EntityLivingBase && HbmLivingProps.getDigamma((EntityLivingBase) e) > 0.001) {
this.jammed = true;
entries.clear();
return;
}
for(Function<Triplet<Entity, Object, RadarScanParams>, RadarEntry> converter : converters) {
RadarEntry entry = converter.apply(new Triplet(e, this, params));
if(entry != null) {
this.entries.add(entry);
break;
}
}
}
}
}
public int getRedPower() {
if(!entries.isEmpty()) {
/// PROXIMITY ///
if(redMode) {
double maxRange = this.getRange() * Math.sqrt(2D);
int power = 0;
for(int i = 0; i < entries.size(); i++) {
RadarEntry e = entries.get(i);
if(!e.redstone) continue;
double dist = Math.sqrt(Math.pow(e.posX - xCoord, 2) + Math.pow(e.posZ - zCoord, 2));
int p = 15 - (int)Math.floor(dist / maxRange * 15);
if(p > power) power = p;
}
return power;
/// TIER ///
} else {
int power = 0;
for(int i = 0; i < entries.size(); i++) {
RadarEntry e = entries.get(i);
if(!e.redstone) continue;
if(e.blipLevel + 1 > power) {
power = e.blipLevel + 1;
}
}
return power;
}
}
return 0;
}
@Override
public void setPower(long i) {
power = i;
}
@Override
public long getPower() {
return power;
}
@Override
public long getMaxPower() {
return maxPower;
}
@Override
public boolean hasPermission(EntityPlayer player) {
return this.isUseableByPlayer(player);
}
@Override public void receiveControl(NBTTagCompound data) { }
@Override
public void receiveControl(EntityPlayer player, NBTTagCompound data) {
if(data.hasKey("missiles")) this.scanMissiles = !this.scanMissiles;
if(data.hasKey("shells")) this.scanShells = !this.scanShells;
if(data.hasKey("players")) this.scanPlayers = !this.scanPlayers;
if(data.hasKey("smart")) this.smartMode = !this.smartMode;
if(data.hasKey("red")) this.redMode = !this.redMode;
if(data.hasKey("map")) this.showMap = !this.showMap;
if(data.hasKey("clear")) this.clearFlag = true;
if(data.hasKey("gui1")) FMLNetworkHandler.openGui(player, MainRegistry.instance, 1, worldObj, xCoord, yCoord, zCoord);
if(data.hasKey("link")) {
int id = data.getInteger("link");
ItemStack link = slots[id];
if(link != null && link.getItem() == ModItems.sat_relay) {
World world = player.getEntityWorld();
Satellite sat = SatelliteSavedData.getData(world).getSatFromFreq(ISatChip.getFreqS(link));
if(sat instanceof SatelliteLaser) {
if(data.hasKey("launchPosX")) {
int x = data.getInteger("launchPosX");
int z = data.getInteger("launchPosZ");
worldObj.playSoundAtEntity(player, "hbm:item.techBleep", 1.0F, 1.0F);
sat.onClick(world, x, z);
}
}
if(sat instanceof SatelliteHorizons) {
if(data.hasKey("launchPosX")) {
int x = data.getInteger("launchPosX");
int z = data.getInteger("launchPosZ");
int y = 60; //one day I will make radars transmit Y coordinate as well and you will be butchered alhamdulila
worldObj.playSoundAtEntity(player, "hbm:item.techBleep", 1.0F, 1.0F);
sat.onCoordAction(world, player, x, y, z);
}
}
if(sat instanceof SatelliteResonator) {
if(data.hasKey("launchPosX")) {
int x = data.getInteger("launchPosX");
int z = data.getInteger("launchPosZ");
int y = world.getTopSolidOrLiquidBlock(x, z); //the top fucking block because I will never make radars transmit Y coordinates as well!
worldObj.playSoundAtEntity(player, "hbm:item.techBleep", 1.0F, 1.0F);
sat.onCoordAction(world, player, x, y, z);
}
}
}
if(link != null && link.getItem() == ModItems.radar_linker) {
BlockPos pos = ItemCoordinateBase.getPosition(link);
if(pos != null) {
TileEntity tile = worldObj.getTileEntity(pos.getX(), pos.getY(), pos.getZ());
if(tile instanceof IRadarCommandReceiver) {
IRadarCommandReceiver rec = (IRadarCommandReceiver) tile;
if(data.hasKey("launchEntity")) {
Entity entity = worldObj.getEntityByID(data.getInteger("launchEntity"));
if(entity != null) {
if(rec.sendCommandEntity(entity)) {
worldObj.playSoundAtEntity(player, "hbm:item.techBleep", 1.0F, 1.0F);
}
}
} else if(data.hasKey("launchPosX")) {
int x = data.getInteger("launchPosX");
int z = data.getInteger("launchPosZ");
if(rec.sendCommandPosition(x, yCoord, z)) {
worldObj.playSoundAtEntity(player, "hbm:item.techBleep", 1.0F, 1.0F);
}
}
}
}
}
}
}
AxisAlignedBB bb = null;
@Override
public AxisAlignedBB getRenderBoundingBox() {
if(bb == null) {
bb = AxisAlignedBB.getBoundingBox(
xCoord - 1,
yCoord,
zCoord - 1,
xCoord + 2,
yCoord + 3,
zCoord + 2
);
}
return bb;
}
@Override
@SideOnly(Side.CLIENT)
public double getMaxRenderDistanceSquared() {
return 65536.0D;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player) {
if(worldObj.getTileEntity(xCoord, yCoord, zCoord) != this) {
return false;
} else {
return true;
}
}
@Override
public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) {
if(ID == 1) return new ContainerMachineRadarNT(player.inventory, this);
return null;
}
@Override
@SideOnly(Side.CLIENT)
public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) {
if(ID == 0) return new GUIMachineRadarNT(this);
if(ID == 1) return new GUIMachineRadarNTSlots(player.inventory, this);
return null;
}
/** List of lambdas that are supplied a Pair with the entity and radar in question to generate a RadarEntry
The converters coming first have the highest priority */
public static List<Function<Triplet<Entity, Object, RadarScanParams>, RadarEntry>> converters = new ArrayList();
public static List<Class> classes = new ArrayList();
public static List<Entity> matchingEntities = new ArrayList();
/**
* Iterates over every entity in the world and add them to the matchingEntities list if the class is in the detectable list
* From this compiled list, radars can easily grab the required entities since we can assume that the total amount of detectable entities is comparatively low
*/
public static void updateSystem() {
matchingEntities.clear();
for(WorldServer world : MinecraftServer.getServer().worldServers) {
for(Object entity : world.loadedEntityList) {
for(Class clazz : classes) {
if(clazz.isAssignableFrom(entity.getClass())) {
matchingEntities.add((Entity) entity);
break;
}
}
}
}
}
/** Registers a class that if an entity inherits that class, it is picked up by the system */
public static void registerEntityClasses() {
classes.add(IRadarDetectableNT.class);
classes.add(IRadarDetectable.class);
classes.add(EntityPlayer.class);
}
/** Registers converters. Converters are used to go over the list of detected entities and turn them into a RadarEntry using the entity instance and the radar's instance. */
public static void registerConverters() {
//IRadarDetectableNT
converters.add(x -> {
Entity e = x.getX();
if(e instanceof IRadarDetectableNT) {
IRadarDetectableNT detectable = (IRadarDetectableNT) e;
if(detectable.canBeSeenBy(x.getY()) && detectable.paramsApplicable(x.getZ())) return new RadarEntry(detectable, e, detectable.suppliesRedstone(x.getZ()));
}
return null;
});
//IRadarDetectable, Legacy
converters.add(x -> {
Entity e = x.getX();
RadarScanParams params = x.getZ();
if(e instanceof IRadarDetectable && params.scanMissiles) {
return new RadarEntry((IRadarDetectable) e, e);
}
return null;
});
//Players
converters.add(x -> {
if(x.getX() instanceof EntityPlayer && x.getZ().scanPlayers) return new RadarEntry((EntityPlayer) x.getX());
return null;
});
}
//OC compat!
@Override
@Optional.Method(modid = "OpenComputers")
public String getComponentName() {
return "ntm_radar";
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getSettings(Context context, Arguments args) {
return new Object[] {scanMissiles, scanShells, scanPlayers, smartMode};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getRange(Context context, Arguments args) {
return new Object[] {this.getRange()};
}
@Callback(direct = true, limit = 4)
@Optional.Method(modid = "OpenComputers")
public Object[] setSettings(Context context, Arguments args) {
this.scanMissiles = args.checkBoolean(0);
this.scanShells = args.checkBoolean(1);
this.scanPlayers = args.checkBoolean(2);
this.smartMode = args.checkBoolean(3);
return new Object[] {};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getEnergyInfo(Context context, Arguments args) {
return new Object[] {getPower(), getMaxPower()};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] isJammed(Context context, Arguments args) {
return new Object[] {this.jammed};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getAmount(Context context, Arguments args) {
return new Object[] {entries.size()};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] isIndexPlayer(Context context, Arguments args) {
int index = args.checkInteger(0) - 1;
if(index > entries.size() || index < 0) {
return new Object[] {null, "No entity exists at that index."};
}
RadarEntry e = entries.get(index);
return new Object[] {e.blipLevel == IRadarDetectableNT.PLAYER};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getIndexType(Context context, Arguments args) {
int index = args.checkInteger(0) - 1;
if(index > entries.size() || index < 0) {
return new Object[] {null, "No entity exists at that index."};
}
RadarEntry e = entries.get(index);
return new Object[] {e.blipLevel};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getEntityAtIndex(Context context, Arguments args) {
int index = args.checkInteger(0) - 1;
if(index > entries.size() || index < 0) {
return new Object[] {null, "No entity exists at that index."};
}
RadarEntry e = entries.get(index);
int type = e.blipLevel;
if(e.blipLevel == IRadarDetectableNT.PLAYER) {
return new Object[]{true, e.posX, e.posY, e.posZ, type, e.unlocalizedName};
}
return new Object[]{false, e.posX, e.posY, e.posZ, type};
}
@Callback(direct = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getPos(Context context, Arguments args) {
return new Object[] {xCoord, yCoord, zCoord};
}
@Override
@Optional.Method(modid = "OpenComputers")
public String[] methods() {
return new String[] {
"getSettings",
"getRange",
"setSettings",
"getEnergyInfo",
"isJammed",
"getAmount",
"isIndexPlayer",
"getIndexType",
"getEntityAtIndex",
"getPos"
};
}
@Override
@Optional.Method(modid = "OpenComputers")
public Object[] invoke(String method, Context context, Arguments args) throws Exception {
switch(method) {
case ("getSettings"):
return getSettings(context, args);
case ("getRange"):
return getRange(context, args);
case ("setSettings"):
return setSettings(context, args);
case ("getEnergyInfo"):
return getEnergyInfo(context, args);
case ("isJammed"):
return isJammed(context, args);
case ("getAmount"):
return getAmount(context, args);
case ("isIndexPlayer"):
return isIndexPlayer(context, args);
case ("getIndexType"):
return getIndexType(context, args);
case ("getEntityAtIndex"):
return getEntityAtIndex(context, args);
case("getPos"):
return getPos(context, args);
}
throw new NoSuchMethodException();
}
}