Added DynamicStrings to minimize String.format invocations in GUI
This commit is contained in:
parent
755a6932cf
commit
890dd16ec6
@ -0,0 +1,84 @@
|
||||
package ru.windcorp.progressia.common.util.dynstr;
|
||||
|
||||
import gnu.trove.list.TCharList;
|
||||
|
||||
class DoubleFlusher {
|
||||
|
||||
public static void flushDouble(TCharList sink, double number, int width, int precision, boolean alwaysUseSign) {
|
||||
boolean isSignNeeded = !Double.isNaN(number) && !isZero(number, precision) && (number < 0 || alwaysUseSign);
|
||||
int size = getSize(number, precision, isSignNeeded);
|
||||
|
||||
int needChars = Math.max(width, size);
|
||||
reserve(sink, needChars);
|
||||
|
||||
int charPos = flushDigits(number, precision, sink);
|
||||
|
||||
if (isSignNeeded) {
|
||||
sink.set(--charPos, number > 0 ? '+' : '-');
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isZero(double number, int precision) {
|
||||
int digits = (int) Math.floor(number * pow10(precision));
|
||||
return digits == 0;
|
||||
}
|
||||
|
||||
private static final char[] NaN_CHARS = "NaN".toCharArray();
|
||||
private static final char[] INFINITY_CHARS = "Infinity".toCharArray();
|
||||
|
||||
private static int getSize(double number, int precision, boolean isSignNeeded) {
|
||||
if (Double.isNaN(number)) return NaN_CHARS.length;
|
||||
if (number == Double.POSITIVE_INFINITY) return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length;
|
||||
|
||||
int integer = (int) Math.floor(Math.abs(number));
|
||||
return (isSignNeeded ? 1 : 0) + IntFlusher.stringSize(integer) + 1 + precision;
|
||||
}
|
||||
|
||||
private static void reserve(TCharList sink, int needChars) {
|
||||
for (int i = 0; i < needChars; ++i) {
|
||||
sink.add(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private static int flushDigits(double number, int precision, TCharList sink) {
|
||||
if (Double.isFinite(number)) {
|
||||
return flushFiniteDigits(number, precision, sink);
|
||||
} else {
|
||||
return flushNonFiniteDigits(number, sink);
|
||||
}
|
||||
}
|
||||
|
||||
private static int flushFiniteDigits(double number, int precision, TCharList sink) {
|
||||
number = Math.abs(number);
|
||||
|
||||
int integer = (int) Math.floor(number);
|
||||
int fraction = (int) Math.floor((number - Math.floor(number)) * pow10(precision));
|
||||
|
||||
int charPos = IntFlusher.flushDigits(fraction, sink, sink.size());
|
||||
sink.set(--charPos, '.');
|
||||
charPos = IntFlusher.flushDigits(integer, sink, charPos);
|
||||
|
||||
return charPos;
|
||||
}
|
||||
|
||||
private static double pow10(int precision) {
|
||||
double result = 1;
|
||||
for (int i = 0; i < precision; ++i) result *= 10;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int flushNonFiniteDigits(double number, TCharList sink) {
|
||||
final char[] chars;
|
||||
|
||||
if (Double.isNaN(number)) {
|
||||
chars = NaN_CHARS;
|
||||
} else {
|
||||
chars = INFINITY_CHARS;
|
||||
}
|
||||
|
||||
int offset = sink.size() - chars.length;
|
||||
sink.set(offset, chars);
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package ru.windcorp.progressia.common.util.dynstr;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import gnu.trove.list.TCharList;
|
||||
import gnu.trove.list.array.TCharArrayList;
|
||||
import ru.windcorp.jputil.chars.CharConsumer;
|
||||
|
||||
public final class DynamicString implements CharSequence {
|
||||
|
||||
interface Part {
|
||||
void flush(TCharList sink);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CharFlusherPart {
|
||||
void flush(CharConsumer sink);
|
||||
}
|
||||
|
||||
final TCharList chars = new TCharArrayList();
|
||||
final Part[] parts;
|
||||
|
||||
private int hashCode = 0;
|
||||
|
||||
DynamicString(Part[] parts) {
|
||||
this.parts = parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the contents of this string to be reevaluated.
|
||||
* This is not currently thread-safe, take caution.
|
||||
*/
|
||||
public void update() {
|
||||
chars.clear();
|
||||
hashCode = 0;
|
||||
|
||||
for (Part part : parts) {
|
||||
part.flush(chars);
|
||||
}
|
||||
}
|
||||
|
||||
public Supplier<CharSequence> asSupplier() {
|
||||
return () -> {
|
||||
update();
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return chars.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return chars.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return new SubString(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
int length = length();
|
||||
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
sb.append(chars.get(i));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h = hashCode;
|
||||
int length = length();
|
||||
|
||||
if (h != 0 || length == 0) return h;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
h = 31 * h + this.chars.get(i);
|
||||
}
|
||||
|
||||
hashCode = h;
|
||||
return h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) return false;
|
||||
if (obj.getClass() != getClass()) return false;
|
||||
|
||||
DynamicString other = (DynamicString) obj;
|
||||
|
||||
if (hashCode() != this.hashCode()) return false;
|
||||
|
||||
return other.chars.equals(this.chars);
|
||||
}
|
||||
|
||||
private class SubString implements CharSequence {
|
||||
|
||||
private final int start;
|
||||
private final int end;
|
||||
|
||||
public SubString(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return Math.min(end, DynamicString.this.length()) - start;
|
||||
}
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
if (index < 0 || index > length()) {
|
||||
throw new IndexOutOfBoundsException(Integer.toString(index) + " is out of bounds");
|
||||
}
|
||||
|
||||
return DynamicString.this.charAt(index);
|
||||
}
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
if (start < 0) throw new IllegalArgumentException("start (" + start + ") is negative");
|
||||
if (end < start) throw new IllegalArgumentException("end (" + end + ") < start (" + start + ")");
|
||||
|
||||
int absoluteStart = this.start + start;
|
||||
int absoluteEnd = this.start + end;
|
||||
|
||||
return DynamicString.this.subSequence(absoluteStart, absoluteEnd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package ru.windcorp.progressia.common.util.dynstr;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import ru.windcorp.jputil.chars.CharConsumer;
|
||||
import ru.windcorp.jputil.functions.FloatSupplier;
|
||||
|
||||
public class DynamicStrings {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CharSource {
|
||||
void flush(CharConsumer sink);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StringSupplier {
|
||||
String get();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final List<DynamicString.Part> parts = new ArrayList<>();
|
||||
|
||||
public DynamicString build() {
|
||||
return new DynamicString(parts.toArray(new DynamicString.Part[parts.size()]));
|
||||
}
|
||||
|
||||
public Supplier<CharSequence> buildSupplier() {
|
||||
return build().asSupplier();
|
||||
}
|
||||
|
||||
public Builder addConst(Object constant) {
|
||||
return add(constant.toString());
|
||||
}
|
||||
|
||||
public Builder add(String string) {
|
||||
return add(string.toCharArray());
|
||||
}
|
||||
|
||||
public Builder add(final char[] chars) {
|
||||
parts.add(sink -> sink.add(chars));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder add(char c) {
|
||||
parts.add(sink -> sink.add(c));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(Object obj) {
|
||||
if (obj == null) return add("null");
|
||||
return addDyn(obj::toString);
|
||||
}
|
||||
|
||||
public Builder embed(DynamicString str) {
|
||||
if (str == null) return add("null");
|
||||
|
||||
for (DynamicString.Part p : str.parts) {
|
||||
parts.add(p);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(Supplier<?> supplier) {
|
||||
Objects.requireNonNull(supplier, "supplier");
|
||||
return addDyn(() -> Objects.toString(supplier.get()));
|
||||
}
|
||||
|
||||
public Builder addDyn(StringSupplier supplier) {
|
||||
Objects.requireNonNull(supplier, "supplier");
|
||||
|
||||
parts.add(sink -> {
|
||||
String str = supplier.get();
|
||||
int length = str.length();
|
||||
|
||||
for (int i = 0; i < length; ++i) {
|
||||
sink.add(str.charAt(i));
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(IntSupplier supplier, int width, boolean alwaysUseSign) {
|
||||
Objects.requireNonNull(supplier, "supplier");
|
||||
|
||||
parts.add(sink -> IntFlusher.flushInt(sink, supplier.getAsInt(), width, alwaysUseSign));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(IntSupplier supplier, int width) {
|
||||
return addDyn(supplier, width, false);
|
||||
}
|
||||
|
||||
public Builder addDyn(IntSupplier supplier, boolean alwaysUseSign) {
|
||||
return addDyn(supplier, 0, alwaysUseSign);
|
||||
}
|
||||
|
||||
public Builder addDyn(IntSupplier supplier) {
|
||||
return addDyn(supplier, 0, false);
|
||||
}
|
||||
|
||||
public Builder addDyn(DoubleSupplier supplier, int width, int precision, boolean alwaysUseSign) {
|
||||
Objects.requireNonNull(supplier, "supplier");
|
||||
|
||||
parts.add(sink -> DoubleFlusher.flushDouble(sink, supplier.getAsDouble(), width, precision, alwaysUseSign));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(DoubleSupplier supplier, int width, int precision) {
|
||||
return addDyn(supplier, width, precision, false);
|
||||
}
|
||||
|
||||
public Builder addDyn(DoubleSupplier supplier, boolean alwaysUseSign, int precision) {
|
||||
return addDyn(supplier, 0, precision, alwaysUseSign);
|
||||
}
|
||||
|
||||
public Builder addDyn(DoubleSupplier supplier, int precision) {
|
||||
return addDyn(supplier, 0, precision, false);
|
||||
}
|
||||
|
||||
public Builder addDyn(FloatSupplier supplier, int width, int precision, boolean alwaysUseSign) {
|
||||
Objects.requireNonNull(supplier, "supplier");
|
||||
|
||||
parts.add(sink -> FloatFlusher.flushFloat(sink, supplier.getAsFloat(), width, precision, alwaysUseSign));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addDyn(FloatSupplier supplier, int width, int precision) {
|
||||
return addDyn(supplier, width, precision, false);
|
||||
}
|
||||
|
||||
public Builder addDyn(FloatSupplier supplier, boolean alwaysUseSign, int precision) {
|
||||
return addDyn(supplier, 0, precision, alwaysUseSign);
|
||||
}
|
||||
|
||||
public Builder addDyn(FloatSupplier supplier, int precision) {
|
||||
return addDyn(supplier, 0, precision, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
private DynamicStrings() {}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package ru.windcorp.progressia.common.util.dynstr;
|
||||
|
||||
import gnu.trove.list.TCharList;
|
||||
|
||||
class FloatFlusher {
|
||||
|
||||
public static void flushFloat(TCharList sink, float number, int width, int precision, boolean alwaysUseSign) {
|
||||
boolean isSignNeeded = !Float.isNaN(number) && !isZero(number, precision) && (number < 0 || alwaysUseSign);
|
||||
int size = getSize(number, precision, isSignNeeded);
|
||||
|
||||
int needChars = Math.max(width, size);
|
||||
reserve(sink, needChars);
|
||||
|
||||
int charPos = flushDigits(number, precision, sink);
|
||||
|
||||
if (isSignNeeded) {
|
||||
sink.set(--charPos, number > 0 ? '+' : '-');
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isZero(float number, int precision) {
|
||||
int digits = (int) Math.floor(number * pow10(precision));
|
||||
return digits == 0;
|
||||
}
|
||||
|
||||
private static final char[] NaN_CHARS = "NaN".toCharArray();
|
||||
private static final char[] INFINITY_CHARS = "Infinity".toCharArray();
|
||||
|
||||
private static int getSize(float number, int precision, boolean isSignNeeded) {
|
||||
if (Float.isNaN(number)) return NaN_CHARS.length;
|
||||
if (number == Float.POSITIVE_INFINITY) return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length;
|
||||
|
||||
int integer = (int) Math.floor(Math.abs(number));
|
||||
return (isSignNeeded ? 1 : 0) + IntFlusher.stringSize(integer) + 1 + precision;
|
||||
}
|
||||
|
||||
private static void reserve(TCharList sink, int needChars) {
|
||||
for (int i = 0; i < needChars; ++i) {
|
||||
sink.add(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private static int flushDigits(float number, int precision, TCharList sink) {
|
||||
if (Float.isFinite(number)) {
|
||||
return flushFiniteDigits(number, precision, sink);
|
||||
} else {
|
||||
return flushNonFiniteDigits(number, sink);
|
||||
}
|
||||
}
|
||||
|
||||
private static int flushFiniteDigits(float number, int precision, TCharList sink) {
|
||||
number = Math.abs(number);
|
||||
|
||||
int integer = (int) Math.floor(number);
|
||||
int fraction = (int) Math.floor((number - Math.floor(number)) * pow10(precision));
|
||||
|
||||
int charPos = IntFlusher.flushDigits(fraction, sink, sink.size());
|
||||
sink.set(--charPos, '.');
|
||||
charPos = IntFlusher.flushDigits(integer, sink, charPos);
|
||||
|
||||
return charPos;
|
||||
}
|
||||
|
||||
private static float pow10(int precision) {
|
||||
float result = 1;
|
||||
for (int i = 0; i < precision; ++i) result *= 10;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int flushNonFiniteDigits(float number, TCharList sink) {
|
||||
final char[] chars;
|
||||
|
||||
if (Float.isNaN(number)) {
|
||||
chars = NaN_CHARS;
|
||||
} else {
|
||||
chars = INFINITY_CHARS;
|
||||
}
|
||||
|
||||
int offset = sink.size() - chars.length;
|
||||
sink.set(offset, chars);
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* The algorithm implemented in this class is adapted from OpenJDK's Integer.toString(int) implementation.
|
||||
* This class therefore falls under the GNU GPL v2 only license.
|
||||
*/
|
||||
package ru.windcorp.progressia.common.util.dynstr;
|
||||
|
||||
import gnu.trove.list.TCharList;
|
||||
|
||||
class IntFlusher {
|
||||
|
||||
public static void flushInt(TCharList sink, int number, int width, boolean alwaysUseSign) {
|
||||
int size = stringSize(number);
|
||||
|
||||
boolean isSignNeeded = number != 0 && (number < 0 || alwaysUseSign);
|
||||
if (isSignNeeded) {
|
||||
size++;
|
||||
}
|
||||
|
||||
int needChars = Math.max(size, width);
|
||||
reserve(sink, needChars);
|
||||
|
||||
int charPos = flushDigits(number, sink, sink.size());
|
||||
|
||||
if (isSignNeeded) {
|
||||
sink.set(--charPos, number > 0 ? '+' : '-');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from OpenJDK's Integer.stringSize(int)
|
||||
*/
|
||||
public static int stringSize(int x) {
|
||||
int d = 1;
|
||||
if (x >= 0) {
|
||||
d = 0;
|
||||
x = -x;
|
||||
}
|
||||
int p = -10;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
if (x > p)
|
||||
return i + d;
|
||||
p = 10 * p;
|
||||
}
|
||||
return 10 + d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from OpenJDK's Integer.DigitTens and Integer.DigitOnes
|
||||
*/
|
||||
private static final char[] DIGIT_TENS = {
|
||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
|
||||
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
|
||||
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
|
||||
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
|
||||
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
|
||||
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
|
||||
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
|
||||
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
|
||||
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
|
||||
};
|
||||
|
||||
private static final char[] DIGIT_ONES = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
};
|
||||
|
||||
/*
|
||||
* Adapted from OpenJDK's Integer.getChars(int, int, byte[])
|
||||
*/
|
||||
public static int flushDigits(int number, TCharList output, int endIndex) {
|
||||
int q, r;
|
||||
int charPos = endIndex;
|
||||
|
||||
if (number >= 0) {
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Generate two digits per iteration
|
||||
while (number <= -100) {
|
||||
q = number / 100;
|
||||
r = (q * 100) - number;
|
||||
number = q;
|
||||
output.set(--charPos, DIGIT_ONES[r]);
|
||||
output.set(--charPos, DIGIT_TENS[r]);
|
||||
}
|
||||
|
||||
// We know there are at most two digits left at this point.
|
||||
q = number / 10;
|
||||
r = (q * 10) - number;
|
||||
output.set(--charPos, (char) ('0' + r));
|
||||
|
||||
// Whatever left is the remaining digit.
|
||||
if (q < 0) {
|
||||
output.set(--charPos, (char) ('0' - q));
|
||||
}
|
||||
|
||||
return charPos;
|
||||
}
|
||||
|
||||
private static void reserve(TCharList sink, int needChars) {
|
||||
for (int i = 0; i < needChars; ++i) {
|
||||
sink.add(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,7 @@ package ru.windcorp.progressia.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.Client;
|
||||
@ -33,6 +33,7 @@ import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
import ru.windcorp.progressia.common.Units;
|
||||
import ru.windcorp.progressia.common.util.dynstr.DynamicStrings;
|
||||
import ru.windcorp.progressia.server.Server;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
|
||||
@ -67,7 +68,7 @@ public class LayerTestGUI extends GUILayer {
|
||||
|
||||
panel.addChild(new DynamicLabel(
|
||||
"FPSDisplay", new Font().withColor(0xFF37A3E6).deriveShadow(),
|
||||
LayerTestGUI::getFPS,
|
||||
DynamicStrings.builder().add("FPS: ").addDyn(() -> FPS_RECORD.update(GraphicsInterface.getFPS()), 5, 1).buildSupplier(),
|
||||
128
|
||||
));
|
||||
|
||||
@ -79,7 +80,7 @@ public class LayerTestGUI extends GUILayer {
|
||||
|
||||
panel.addChild(new DynamicLabel(
|
||||
"ChunkUpdatesDisplay", new Font().withColor(0xFF37A3E6).deriveShadow(),
|
||||
() -> "Pending updates: " + Integer.toString(ClientState.getInstance().getWorld().getPendingChunkUpdates()),
|
||||
DynamicStrings.builder().addConst("Pending updates: ").addDyn(ClientState.getInstance().getWorld()::getPendingChunkUpdates).buildSupplier(),
|
||||
128
|
||||
));
|
||||
|
||||
@ -148,26 +149,34 @@ public class LayerTestGUI extends GUILayer {
|
||||
private static final Averager FPS_RECORD = new Averager();
|
||||
private static final Averager TPS_RECORD = new Averager();
|
||||
|
||||
private static String getFPS() {
|
||||
return String.format(Locale.US, "FPS: %5.1f", FPS_RECORD.update(GraphicsInterface.getFPS()));
|
||||
}
|
||||
private static final Supplier<CharSequence> TPS_STRING = DynamicStrings.builder()
|
||||
.add("TPS: ")
|
||||
.addDyn(() -> TPS_RECORD.update(ServerState.getInstance().getTPS()), 5, 1)
|
||||
.buildSupplier();
|
||||
|
||||
private static String getTPS() {
|
||||
private static final Supplier<CharSequence> POS_STRING = DynamicStrings.builder()
|
||||
.add("Pos: ")
|
||||
.addDyn(() -> ClientState.getInstance().getCamera().getLastAnchorPosition().x, 7, 1)
|
||||
.addDyn(() -> ClientState.getInstance().getCamera().getLastAnchorPosition().y, 7, 1)
|
||||
.addDyn(() -> ClientState.getInstance().getCamera().getLastAnchorPosition().z, 7, 1)
|
||||
.buildSupplier();
|
||||
|
||||
private static CharSequence getTPS() {
|
||||
Server server = ServerState.getInstance();
|
||||
if (server == null) return "TPS: n/a";
|
||||
|
||||
return String.format(Locale.US, "TPS: %5.1f", TPS_RECORD.update(server.getTPS()));
|
||||
return TPS_STRING.get();
|
||||
}
|
||||
|
||||
private static String getPos() {
|
||||
private static CharSequence getPos() {
|
||||
Client client = ClientState.getInstance();
|
||||
if (client == null) return "Pos: n/a";
|
||||
if (client == null) return "Pos: client n/a";
|
||||
|
||||
Vec3 pos = client.getCamera().getLastAnchorPosition();
|
||||
if (Float.isNaN(pos.x)) {
|
||||
return "Pos: entity n/a";
|
||||
} else {
|
||||
return String.format(Locale.US, "Pos: %+7.1f %+7.1f %+7.1f", pos.x, pos.y, pos.z);
|
||||
return POS_STRING.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user