mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-04 20:07:37 +01:00
Add create debuginfo command (#5531)
This commit is contained in:
parent
2e1bcdb619
commit
7eea02854e
12 changed files with 545 additions and 8 deletions
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -93,6 +93,8 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider;
|
|||
import com.simibubi.create.infrastructure.command.HighlightPacket;
|
||||
import com.simibubi.create.infrastructure.command.SConfigureConfigPacket;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.ServerDebugInfoPacket;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -203,7 +205,7 @@ public enum AllPackets {
|
|||
CONTRAPTION_ACTOR_TOGGLE(ContraptionDisableActorPacket.class, ContraptionDisableActorPacket::new, PLAY_TO_CLIENT),
|
||||
CONTRAPTION_COLLIDER_LOCK(ContraptionColliderLockPacket.class, ContraptionColliderLockPacket::new, PLAY_TO_CLIENT),
|
||||
ATTACHED_COMPUTER(AttachedComputerPacket.class, AttachedComputerPacket::new, PLAY_TO_CLIENT),
|
||||
|
||||
SERVER_DEBUG_INFO(ServerDebugInfoPacket.class, ServerDebugInfoPacket::new, PLAY_TO_CLIENT)
|
||||
;
|
||||
|
||||
public static final ResourceLocation CHANNEL_NAME = Create.asResource("main");
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package com.simibubi.create.foundation.mixin.accessor;
|
||||
|
||||
import net.minecraft.SystemReport;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(SystemReport.class)
|
||||
public interface SystemReportAccessor {
|
||||
@Accessor
|
||||
static String getOPERATING_SYSTEM() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Accessor
|
||||
static String getJAVA_VERSION() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Accessor
|
||||
Map<String, String> getEntries();
|
||||
}
|
|
@ -30,6 +30,7 @@ public class AllCommands {
|
|||
.then(OverlayConfigCommand.register())
|
||||
.then(DumpRailwaysCommand.register())
|
||||
.then(FixLightingCommand.register())
|
||||
.then(DebugInfoCommand.register())
|
||||
.then(HighlightCommand.register())
|
||||
.then(KillTrainCommand.register())
|
||||
.then(PassengerCommand.register())
|
||||
|
@ -39,6 +40,7 @@ public class AllCommands {
|
|||
.then(CloneCommand.register())
|
||||
.then(GlueCommand.register())
|
||||
|
||||
|
||||
// utility
|
||||
.then(util);
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.simibubi.create.infrastructure.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
|
||||
import com.simibubi.create.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.DebugInformation;
|
||||
import com.simibubi.create.infrastructure.debugInfo.ServerDebugInfoPacket;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class DebugInfoCommand {
|
||||
public static ArgumentBuilder<CommandSourceStack, ?> register() {
|
||||
return literal("debuginfo").executes(ctx -> {
|
||||
CommandSourceStack source = ctx.getSource();
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
source.sendSuccess(
|
||||
Components.literal("Sending server debug information to your client..."), true
|
||||
);
|
||||
AllPackets.getChannel().send(
|
||||
PacketDistributor.PLAYER.with(() -> player),
|
||||
new ServerDebugInfoPacket(player)
|
||||
);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.foundation.mixin.accessor.SystemReportAccessor;
|
||||
import com.simibubi.create.infrastructure.debugInfo.element.DebugInfoSection;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.SystemReport;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.element.InfoElement;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.element.InfoEntry;
|
||||
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.forgespi.language.IModInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlUtil;
|
||||
|
||||
/**
|
||||
* Allows for providing easily accessible debugging information.
|
||||
* This info can be retrieved with the "/create debuginfo" command.
|
||||
* This command copies all information to the clipboard, formatted for a GitHub issue.
|
||||
* Addons are welcome to add their own sections. Registration must occur synchronously.
|
||||
*/
|
||||
public class DebugInformation {
|
||||
private static final List<DebugInfoSection> client = new ArrayList<>();
|
||||
private static final List<DebugInfoSection> server = new ArrayList<>();
|
||||
|
||||
private static final ImmutableMap<String, String> mcSystemInfo = Util.make(() -> {
|
||||
SystemReport systemReport = new SystemReport();
|
||||
SystemReportAccessor access = (SystemReportAccessor) systemReport;
|
||||
return ImmutableMap.copyOf(access.getEntries());
|
||||
});
|
||||
|
||||
public static void registerClientInfo(DebugInfoSection section) {
|
||||
client.add(section);
|
||||
}
|
||||
|
||||
public static void registerServerInfo(DebugInfoSection section) {
|
||||
server.add(section);
|
||||
}
|
||||
|
||||
public static void registerBothInfo(DebugInfoSection section) {
|
||||
registerClientInfo(section);
|
||||
registerServerInfo(section);
|
||||
}
|
||||
|
||||
public static List<DebugInfoSection> getClientInfo() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public static List<DebugInfoSection> getServerInfo() {
|
||||
return server;
|
||||
}
|
||||
|
||||
static {
|
||||
DebugInfoSection.builder(Create.NAME)
|
||||
.put("Mod Version", Create.VERSION)
|
||||
.put("Forge Version", getVersionOfMod("forge"))
|
||||
.put("Minecraft Version", SharedConstants.getCurrentVersion().getName())
|
||||
.buildTo(DebugInformation::registerBothInfo);
|
||||
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
|
||||
DebugInfoSection.builder("Graphics")
|
||||
.put("Flywheel Version", Flywheel.getVersion().toString())
|
||||
.put("Flywheel Backend", () -> Backend.getBackendType().toString())
|
||||
.put("OpenGL Renderer", GlUtil::getRenderer)
|
||||
.put("OpenGL Version", GlUtil::getOpenGLVersion)
|
||||
.put("Graphics Mode", () -> Minecraft.getInstance().options.graphicsMode.toString())
|
||||
.buildTo(DebugInformation::registerClientInfo);
|
||||
});
|
||||
|
||||
DebugInfoSection.builder("System Information")
|
||||
.put("Operating System", SystemReportAccessor.getOPERATING_SYSTEM())
|
||||
.put("Java Version", SystemReportAccessor.getJAVA_VERSION())
|
||||
.put("JVM Flags", getMcSystemInfo("JVM Flags"))
|
||||
.put("Memory", () -> getMcSystemInfo("Memory"))
|
||||
.put("CPU", getCpuInfo())
|
||||
.putAll(listAllGraphicsCards())
|
||||
.buildTo(DebugInformation::registerBothInfo);
|
||||
|
||||
DebugInfoSection.builder("Other Mods")
|
||||
.putAll(listAllOtherMods())
|
||||
.buildTo(DebugInformation::registerBothInfo);
|
||||
}
|
||||
|
||||
public static String getVersionOfMod(String id) {
|
||||
return ModList.get().getModContainerById(id)
|
||||
.map(mod -> mod.getModInfo().getVersion().toString())
|
||||
.orElse("None");
|
||||
}
|
||||
|
||||
public static Collection<InfoElement> listAllOtherMods() {
|
||||
List<InfoElement> mods = new ArrayList<>();
|
||||
ModList.get().forEachModContainer((id, mod) -> {
|
||||
if (!id.equals(Create.ID) && !id.equals("forge") && !id.equals("minecraft") && !id.equals("flywheel")) {
|
||||
IModInfo info = mod.getModInfo();
|
||||
String name = info.getDisplayName();
|
||||
String version = info.getVersion().toString();
|
||||
mods.add(new InfoEntry(name, version));
|
||||
}
|
||||
});
|
||||
return mods;
|
||||
}
|
||||
|
||||
public static Collection<InfoElement> listAllGraphicsCards() {
|
||||
List<InfoElement> cards = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) { // there won't be more than 10, right? right??
|
||||
String name = getMcSystemInfo("Graphics card #" + i + " name");
|
||||
String vendor = getMcSystemInfo("Graphics card #" + i + " vendor");
|
||||
String vram = getMcSystemInfo("Graphics card #" + i + " VRAM (MB)");
|
||||
if (name == null || vendor == null || vram == null)
|
||||
break;
|
||||
String key = "Graphics card #" + i;
|
||||
String value = String.format("%s (%s); %s MB of VRAM", name, vendor, vram);
|
||||
cards.add(new InfoEntry(key, value));
|
||||
}
|
||||
return cards.isEmpty() ? List.of(new InfoEntry("Graphics cards", "none")) : cards;
|
||||
}
|
||||
|
||||
public static String getCpuInfo() {
|
||||
String name = tryTrim(getMcSystemInfo("Processor Name"));
|
||||
String freq = getMcSystemInfo("Frequency (GHz)");
|
||||
String sockets = getMcSystemInfo("Number of physical packages");
|
||||
String cores = getMcSystemInfo("Number of physical CPUs");
|
||||
String threads = getMcSystemInfo("Number of logical CPUs");
|
||||
return String.format("%s @ %s GHz; %s cores / %s threads on %s socket(s)", name, freq, cores, threads, sockets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a system attribute provided by Minecraft.
|
||||
* They can be found in the constructor of {@link SystemReport}.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getMcSystemInfo(String key) {
|
||||
return mcSystemInfo.get(key);
|
||||
}
|
||||
|
||||
public static String getIndent(int depth) {
|
||||
return Stream.generate(() -> "\t").limit(depth).collect(Collectors.joining());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String tryTrim(@Nullable String s) {
|
||||
return s == null ? null : s.trim();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A supplier of debug information. May be queried on the client or server.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface InfoProvider {
|
||||
/**
|
||||
* @param player the player requesting the data. May be null
|
||||
*/
|
||||
@Nullable
|
||||
String getInfo(@Nullable Player player);
|
||||
|
||||
default String getInfoSafe(Player player) {
|
||||
try {
|
||||
return Objects.toString(getInfo(player));
|
||||
} catch (Throwable t) {
|
||||
StringBuilder builder = new StringBuilder("Error getting information!");
|
||||
builder.append(' ').append(t.getMessage());
|
||||
for (StackTraceElement element : t.getStackTrace()) {
|
||||
builder.append('\n').append("\t").append(element.toString());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.infrastructure.debugInfo.element.DebugInfoSection;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
public class ServerDebugInfoPacket extends SimplePacketBase {
|
||||
public static final Component COPIED = Components.literal(
|
||||
"Debug information has been copied to your clipboard."
|
||||
).withStyle(ChatFormatting.GREEN);
|
||||
|
||||
private final List<DebugInfoSection> serverInfo;
|
||||
private final Player player;
|
||||
|
||||
public ServerDebugInfoPacket(Player player) {
|
||||
this.serverInfo = DebugInformation.getServerInfo();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public ServerDebugInfoPacket(FriendlyByteBuf buffer) {
|
||||
this.serverInfo = buffer.readList(DebugInfoSection::readDirect);
|
||||
this.player = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeCollection(this.serverInfo, (buf, section) -> section.write(player, buf));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(NetworkEvent.Context context) {
|
||||
context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::handleOnClient));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void printInfo(String side, Player player, List<DebugInfoSection> sections, StringBuilder output) {
|
||||
output.append("<details>");
|
||||
output.append('\n');
|
||||
output.append("<summary>").append(side).append(" Info").append("</summary>");
|
||||
output.append('\n').append('\n');
|
||||
output.append("```");
|
||||
output.append('\n');
|
||||
|
||||
for (int i = 0; i < sections.size(); i++) {
|
||||
if (i != 0) {
|
||||
output.append('\n');
|
||||
}
|
||||
sections.get(i).print(player, line -> output.append(line).append('\n'));
|
||||
}
|
||||
|
||||
output.append("```");
|
||||
output.append('\n').append('\n');
|
||||
output.append("</details>");
|
||||
output.append('\n');
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private void handleOnClient() {
|
||||
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
|
||||
StringBuilder output = new StringBuilder();
|
||||
List<DebugInfoSection> clientInfo = DebugInformation.getClientInfo();
|
||||
|
||||
printInfo("Client", player, clientInfo, output);
|
||||
output.append("\n\n");
|
||||
printInfo("Server", player, serverInfo, output);
|
||||
|
||||
String text = output.toString();
|
||||
Minecraft.getInstance().keyboardHandler.setClipboard(text);
|
||||
player.displayClientMessage(COPIED, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo.element;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.DebugInformation;
|
||||
import com.simibubi.create.infrastructure.debugInfo.InfoProvider;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A section for organizing debug information. Can contain both information and other sections.
|
||||
* To create one, use the {@link #builder(String) builder} method.
|
||||
*/
|
||||
public record DebugInfoSection(String name, ImmutableList<InfoElement> elements) implements InfoElement {
|
||||
@Override
|
||||
public void write(Player player, FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(true);
|
||||
buffer.writeUtf(name);
|
||||
buffer.writeCollection(elements, (buf, element) -> element.write(player, buf));
|
||||
}
|
||||
|
||||
public Builder builder() {
|
||||
return builder(name).putAll(elements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(int depth, @Nullable Player player, Consumer<String> lineConsumer) {
|
||||
String indent = DebugInformation.getIndent(depth);
|
||||
lineConsumer.accept(indent + name + ":");
|
||||
elements.forEach(element -> element.print(depth + 1, player, lineConsumer));
|
||||
}
|
||||
|
||||
public static DebugInfoSection read(FriendlyByteBuf buffer) {
|
||||
String name = buffer.readUtf();
|
||||
ArrayList<InfoElement> elements = buffer.readCollection(ArrayList::new, InfoElement::read);
|
||||
return new DebugInfoSection(name, ImmutableList.copyOf(elements));
|
||||
}
|
||||
|
||||
public static DebugInfoSection readDirect(FriendlyByteBuf buf) {
|
||||
buf.readBoolean(); // discard type marker
|
||||
return read(buf);
|
||||
}
|
||||
|
||||
public static Builder builder(String name) {
|
||||
return new Builder(null, name);
|
||||
}
|
||||
|
||||
public static DebugInfoSection of(String name, Collection<DebugInfoSection> children) {
|
||||
return builder(name).putAll(children).build();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Builder parent;
|
||||
private final String name;
|
||||
private final ImmutableList.Builder<InfoElement> elements;
|
||||
|
||||
public Builder(Builder parent, String name) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.elements = ImmutableList.builder();
|
||||
}
|
||||
|
||||
public Builder put(InfoElement element) {
|
||||
this.elements.add(element);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder put(String key, InfoProvider provider) {
|
||||
return put(new InfoEntry(key, provider));
|
||||
}
|
||||
|
||||
public Builder put(String key, Supplier<String> value) {
|
||||
return put(key, player -> value.get());
|
||||
}
|
||||
|
||||
public Builder put(String key, String value) {
|
||||
return put(key, player -> value);
|
||||
}
|
||||
|
||||
public Builder putAll(Collection<? extends InfoElement> elements) {
|
||||
elements.forEach(this::put);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder section(String name) {
|
||||
return new Builder(this, name);
|
||||
}
|
||||
|
||||
public Builder finishSection() {
|
||||
if (parent == null) {
|
||||
throw new IllegalStateException("Cannot finish the root section");
|
||||
}
|
||||
parent.elements.add(this.build());
|
||||
return parent;
|
||||
}
|
||||
|
||||
public DebugInfoSection build() {
|
||||
return new DebugInfoSection(name, elements.build());
|
||||
}
|
||||
|
||||
public void buildTo(Consumer<DebugInfoSection> consumer) {
|
||||
consumer.accept(this.build());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo.element;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public sealed interface InfoElement permits DebugInfoSection, InfoEntry {
|
||||
void write(Player player, FriendlyByteBuf buffer);
|
||||
|
||||
void print(int depth, @Nullable Player player, Consumer<String> lineConsumer);
|
||||
|
||||
default void print(@Nullable Player player, Consumer<String> lineConsumer) {
|
||||
print(0, player, lineConsumer);
|
||||
}
|
||||
|
||||
static InfoElement read(FriendlyByteBuf buffer) {
|
||||
boolean section = buffer.readBoolean();
|
||||
if (section) {
|
||||
return DebugInfoSection.read(buffer);
|
||||
} else {
|
||||
return InfoEntry.read(buffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.simibubi.create.infrastructure.debugInfo.element;
|
||||
|
||||
import com.simibubi.create.infrastructure.debugInfo.DebugInformation;
|
||||
import com.simibubi.create.infrastructure.debugInfo.InfoProvider;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public record InfoEntry(String name, InfoProvider provider) implements InfoElement {
|
||||
public InfoEntry(String name, String info) {
|
||||
this(name, player -> info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Player player, FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(false);
|
||||
buffer.writeUtf(name);
|
||||
buffer.writeUtf(provider.getInfoSafe(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(int depth, @Nullable Player player, Consumer<String> lineConsumer) {
|
||||
String value = provider.getInfoSafe(player);
|
||||
String indent = DebugInformation.getIndent(depth);
|
||||
if (value.contains("\n")) {
|
||||
String[] lines = value.split("\n");
|
||||
String firstLine = lines[0];
|
||||
String lineStart = name + ": ";
|
||||
lineConsumer.accept(indent + lineStart + firstLine);
|
||||
String extraIndent = Stream.generate(() -> " ").limit(lineStart.length()).collect(Collectors.joining());
|
||||
|
||||
for (int i = 1; i < lines.length; i++) {
|
||||
lineConsumer.accept(indent + extraIndent + lines[i]);
|
||||
}
|
||||
} else {
|
||||
lineConsumer.accept(indent + name + ": " + value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static InfoEntry read(FriendlyByteBuf buffer) {
|
||||
String name = buffer.readUtf();
|
||||
String value = buffer.readUtf();
|
||||
return new InfoEntry(name, value);
|
||||
}
|
||||
}
|
|
@ -22,9 +22,14 @@
|
|||
"accessor.GameTestHelperAccessor",
|
||||
"accessor.LivingEntityAccessor",
|
||||
"accessor.NbtAccounterAccessor",
|
||||
"accessor.ServerLevelAccessor"
|
||||
"accessor.ServerLevelAccessor",
|
||||
"accessor.SystemReportAccessor"
|
||||
],
|
||||
"client": [
|
||||
"accessor.AgeableListModelAccessor",
|
||||
"accessor.GameRendererAccessor",
|
||||
"accessor.HumanoidArmorLayerAccessor",
|
||||
"accessor.ParticleEngineAccessor",
|
||||
"client.BlockDestructionProgressMixin",
|
||||
"client.CameraMixin",
|
||||
"client.EntityContraptionInteractionMixin",
|
||||
|
@ -35,11 +40,7 @@
|
|||
"client.MapRendererMapInstanceMixin",
|
||||
"client.ModelDataRefreshMixin",
|
||||
"client.PlayerRendererMixin",
|
||||
"client.WindowResizeMixin",
|
||||
"accessor.AgeableListModelAccessor",
|
||||
"accessor.GameRendererAccessor",
|
||||
"accessor.HumanoidArmorLayerAccessor",
|
||||
"accessor.ParticleEngineAccessor"
|
||||
"client.WindowResizeMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
Loading…
Reference in a new issue