getCoverUUIDsFromItemStack(final ItemStack stack) {
+ if (stack.hasTagCompound() && stack.getTagCompound()
+ .hasKey(GT_Values.NBT.COVERS, TAG_COMPOUND)) {
+ final NBTTagList tagList = stack.getTagCompound()
+ .getTagList(GT_Values.NBT.COVERS, TAG_COMPOUND);
+ return IntStream.range(0, tagList.tagCount())
+ .mapToObj(tagList::getCompoundTagAt)
+ .map(nbt -> new CoverInfo(null, nbt).getCoverData())
+ .filter(
+ serializableObject -> serializableObject instanceof GT_Cover_Metrics_Transmitter.MetricsTransmitterData)
+ .map(data -> ((GT_Cover_Metrics_Transmitter.MetricsTransmitterData) data).getFrequency());
+ }
+ return Stream.empty();
+ }
+
+ /**
+ * Data transmitted by a Metrics Transmitter cover.
+ *
+ * Since only negative states ({@link State#HOST_DECONSTRUCTED HOST_DECONSTRUCTED} and
+ * {@link State#SELF_DESTRUCTED SELF DESTRUCTED}) are persisted, additional fields can be added to this data with
+ * little consequence. Ensure that any new fields are nullable, and make any getter for these fields return an
+ * {@link Optional}.
+ */
+ public static class Data {
+
+ @NotNull
+ private final State state;
+ @Nullable
+ private final List payload;
+ @Nullable
+ private final Coordinates coordinates;
+
+ public Data(@NotNull State state) {
+ this.state = state;
+ this.payload = null;
+ this.coordinates = null;
+ }
+
+ public Data(@NotNull State state, @Nullable List payload) {
+ this.state = state;
+ this.payload = payload;
+ this.coordinates = null;
+ }
+
+ public Data(@NotNull State state, @Nullable List payload, @Nullable Coordinates coordinates) {
+ this.state = state;
+ this.payload = payload;
+ this.coordinates = coordinates;
+
+ }
+
+ /**
+ * Retrieves the payload for this data. Only present if the frequency is in an
+ * {@link State#OPERATIONAL operational} state. Will be cleared if the frequency goes into a
+ * {@link State#HOST_DECONSTRUCTED host-deconstructed} or {@link State#SELF_DESTRUCTED self-destructed} state.
+ *
+ * @return The data if present, or an empty Optional otherwise.
+ */
+ @NotNull
+ public Optional> getPayload() {
+ return Optional.ofNullable(payload);
+ }
+
+ /**
+ * Gets the state of the frequency.
+ *
+ * @return The state
+ */
+ @NotNull
+ public State getState() {
+ return state;
+ }
+
+ /**
+ * Gets the last known coordinates for the machine broadcasting metrics. Will only be present in an
+ * {@link State#OPERATIONAL operational} state.
+ *
+ * @return The coordinates
+ */
+ @NotNull
+ public Optional getCoordinates() {
+ return Optional.ofNullable(coordinates);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final Data data = (Data) o;
+ return state == data.state && Objects.equals(payload, data.payload)
+ && Objects.equals(coordinates, data.coordinates);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(state, payload, coordinates);
+ }
+ }
+
+ @SuppressWarnings("ClassCanBeRecord")
+ public static class Coordinates {
+
+ private final String dimension;
+ private final int x;
+ private final int y;
+ private final int z;
+
+ public Coordinates(final String dimension, final int x, final int y, final int z) {
+ this.dimension = dimension;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public int getZ() {
+ return z;
+ }
+
+ public String getDimension() {
+ return dimension;
+ }
+
+ public String getLocalizedCoordinates() {
+ return StatCollector.translateToLocalFormatted(
+ "gt.db.metrics_cover.coords",
+ GT_Utility.formatNumbers(x),
+ GT_Utility.formatNumbers(y),
+ GT_Utility.formatNumbers(z));
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final Coordinates that = (Coordinates) o;
+ return x == that.x && y == that.y && z == that.z && Objects.equals(dimension, that.dimension);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(dimension, x, y, z);
+ }
+ }
+
+ public enum State {
+ // NOTE: type cannot be 0, as NuclearControl returns a 0 when querying for an integer from an item stack's NBT
+ // data when it really means null.
+
+ /** The machine is online and broadcasting metrics. */
+ OPERATIONAL(1),
+ /**
+ * The machine was picked up, but the cover is still attached. Will transition to operational state if the
+ * machine is placed back down and started up again.
+ */
+ HOST_DECONSTRUCTED(2),
+ /**
+ * Cover was removed from its host machine, or machine was destroyed (in the limited number of ways we can
+ * detect.) Any frequency in this state will no longer get updates nor leave this state.
+ */
+ SELF_DESTRUCTED(3);
+
+ private static final Map VALID_TYPE_INTEGERS = Arrays.stream(State.values())
+ .collect(Collectors.toMap(State::getType, Function.identity()));
+ private final int type;
+
+ State(final int type) {
+ if (type <= 0) {
+ throw new IllegalArgumentException("A state must have a positive, nonzero type parameter.");
+ }
+ this.type = type;
+ }
+
+ @NotNull
+ public static Optional find(int candidate) {
+ return Optional.ofNullable(VALID_TYPE_INTEGERS.get(candidate));
+ }
+
+ public int getType() {
+ return type;
+ }
+ }
+}
--
cgit