353 lines
13 KiB
Java
353 lines
13 KiB
Java
package net.minecraft.client.renderer.debug;
|
|
|
|
import com.google.common.collect.Iterables;
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import com.mojang.logging.LogUtils;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.stream.Collectors;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.renderer.MultiBufferSource;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Position;
|
|
import net.minecraft.network.protocol.common.custom.BrainDebugPayload.BrainDump;
|
|
import net.minecraft.network.protocol.game.DebugEntityNameGenerator;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.slf4j.Logger;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class BrainDebugRenderer implements DebugRenderer.SimpleDebugRenderer {
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private static final boolean SHOW_NAME_FOR_ALL = true;
|
|
private static final boolean SHOW_PROFESSION_FOR_ALL = false;
|
|
private static final boolean SHOW_BEHAVIORS_FOR_ALL = false;
|
|
private static final boolean SHOW_ACTIVITIES_FOR_ALL = false;
|
|
private static final boolean SHOW_INVENTORY_FOR_ALL = false;
|
|
private static final boolean SHOW_GOSSIPS_FOR_ALL = false;
|
|
private static final boolean SHOW_PATH_FOR_ALL = false;
|
|
private static final boolean SHOW_HEALTH_FOR_ALL = false;
|
|
private static final boolean SHOW_WANTS_GOLEM_FOR_ALL = true;
|
|
private static final boolean SHOW_ANGER_LEVEL_FOR_ALL = false;
|
|
private static final boolean SHOW_NAME_FOR_SELECTED = true;
|
|
private static final boolean SHOW_PROFESSION_FOR_SELECTED = true;
|
|
private static final boolean SHOW_BEHAVIORS_FOR_SELECTED = true;
|
|
private static final boolean SHOW_ACTIVITIES_FOR_SELECTED = true;
|
|
private static final boolean SHOW_MEMORIES_FOR_SELECTED = true;
|
|
private static final boolean SHOW_INVENTORY_FOR_SELECTED = true;
|
|
private static final boolean SHOW_GOSSIPS_FOR_SELECTED = true;
|
|
private static final boolean SHOW_PATH_FOR_SELECTED = true;
|
|
private static final boolean SHOW_HEALTH_FOR_SELECTED = true;
|
|
private static final boolean SHOW_WANTS_GOLEM_FOR_SELECTED = true;
|
|
private static final boolean SHOW_ANGER_LEVEL_FOR_SELECTED = true;
|
|
private static final boolean SHOW_POI_INFO = true;
|
|
private static final int MAX_RENDER_DIST_FOR_BRAIN_INFO = 30;
|
|
private static final int MAX_RENDER_DIST_FOR_POI_INFO = 30;
|
|
private static final int MAX_TARGETING_DIST = 8;
|
|
private static final float TEXT_SCALE = 0.02F;
|
|
private static final int CYAN = -16711681;
|
|
private static final int GRAY = -3355444;
|
|
private static final int PINK = -98404;
|
|
private static final int ORANGE = -23296;
|
|
private final Minecraft minecraft;
|
|
private final Map<BlockPos, BrainDebugRenderer.PoiInfo> pois = Maps.<BlockPos, BrainDebugRenderer.PoiInfo>newHashMap();
|
|
private final Map<UUID, BrainDump> brainDumpsPerEntity = Maps.<UUID, BrainDump>newHashMap();
|
|
@Nullable
|
|
private UUID lastLookedAtUuid;
|
|
|
|
public BrainDebugRenderer(Minecraft minecraft) {
|
|
this.minecraft = minecraft;
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
this.pois.clear();
|
|
this.brainDumpsPerEntity.clear();
|
|
this.lastLookedAtUuid = null;
|
|
}
|
|
|
|
public void addPoi(BrainDebugRenderer.PoiInfo poiInfo) {
|
|
this.pois.put(poiInfo.pos, poiInfo);
|
|
}
|
|
|
|
public void removePoi(BlockPos pos) {
|
|
this.pois.remove(pos);
|
|
}
|
|
|
|
public void setFreeTicketCount(BlockPos pos, int freeTicketCount) {
|
|
BrainDebugRenderer.PoiInfo poiInfo = (BrainDebugRenderer.PoiInfo)this.pois.get(pos);
|
|
if (poiInfo == null) {
|
|
LOGGER.warn("Strange, setFreeTicketCount was called for an unknown POI: {}", pos);
|
|
} else {
|
|
poiInfo.freeTicketCount = freeTicketCount;
|
|
}
|
|
}
|
|
|
|
public void addOrUpdateBrainDump(BrainDump brainDump) {
|
|
this.brainDumpsPerEntity.put(brainDump.uuid(), brainDump);
|
|
}
|
|
|
|
public void removeBrainDump(int id) {
|
|
this.brainDumpsPerEntity.values().removeIf(brainDump -> brainDump.id() == id);
|
|
}
|
|
|
|
@Override
|
|
public void render(PoseStack poseStack, MultiBufferSource bufferSource, double camX, double camY, double camZ) {
|
|
this.clearRemovedEntities();
|
|
this.doRender(poseStack, bufferSource, camX, camY, camZ);
|
|
if (!this.minecraft.player.isSpectator()) {
|
|
this.updateLastLookedAtUuid();
|
|
}
|
|
}
|
|
|
|
private void clearRemovedEntities() {
|
|
this.brainDumpsPerEntity.entrySet().removeIf(entry -> {
|
|
Entity entity = this.minecraft.level.getEntity(((BrainDump)entry.getValue()).id());
|
|
return entity == null || entity.isRemoved();
|
|
});
|
|
}
|
|
|
|
private void doRender(PoseStack poseStack, MultiBufferSource buffer, double x, double y, double z) {
|
|
BlockPos blockPos = BlockPos.containing(x, y, z);
|
|
this.brainDumpsPerEntity.values().forEach(brainDump -> {
|
|
if (this.isPlayerCloseEnoughToMob(brainDump)) {
|
|
this.renderBrainInfo(poseStack, buffer, brainDump, x, y, z);
|
|
}
|
|
});
|
|
|
|
for (BlockPos blockPos2 : this.pois.keySet()) {
|
|
if (blockPos.closerThan(blockPos2, 30.0)) {
|
|
highlightPoi(poseStack, buffer, blockPos2);
|
|
}
|
|
}
|
|
|
|
this.pois.values().forEach(poiInfo -> {
|
|
if (blockPos.closerThan(poiInfo.pos, 30.0)) {
|
|
this.renderPoiInfo(poseStack, buffer, poiInfo);
|
|
}
|
|
});
|
|
this.getGhostPois().forEach((blockPos2x, list) -> {
|
|
if (blockPos.closerThan(blockPos2x, 30.0)) {
|
|
this.renderGhostPoi(poseStack, buffer, blockPos2x, list);
|
|
}
|
|
});
|
|
}
|
|
|
|
private static void highlightPoi(PoseStack poseStack, MultiBufferSource buffer, BlockPos pos) {
|
|
float f = 0.05F;
|
|
DebugRenderer.renderFilledBox(poseStack, buffer, pos, 0.05F, 0.2F, 0.2F, 1.0F, 0.3F);
|
|
}
|
|
|
|
private void renderGhostPoi(PoseStack poseStack, MultiBufferSource buffer, BlockPos pos, List<String> poiName) {
|
|
float f = 0.05F;
|
|
DebugRenderer.renderFilledBox(poseStack, buffer, pos, 0.05F, 0.2F, 0.2F, 1.0F, 0.3F);
|
|
renderTextOverPos(poseStack, buffer, poiName + "", pos, 0, -256);
|
|
renderTextOverPos(poseStack, buffer, "Ghost POI", pos, 1, -65536);
|
|
}
|
|
|
|
private void renderPoiInfo(PoseStack poseStack, MultiBufferSource buffer, BrainDebugRenderer.PoiInfo poiInfo) {
|
|
int i = 0;
|
|
Set<String> set = this.getTicketHolderNames(poiInfo);
|
|
if (set.size() < 4) {
|
|
renderTextOverPoi(poseStack, buffer, "Owners: " + set, poiInfo, i, -256);
|
|
} else {
|
|
renderTextOverPoi(poseStack, buffer, set.size() + " ticket holders", poiInfo, i, -256);
|
|
}
|
|
|
|
i++;
|
|
Set<String> set2 = this.getPotentialTicketHolderNames(poiInfo);
|
|
if (set2.size() < 4) {
|
|
renderTextOverPoi(poseStack, buffer, "Candidates: " + set2, poiInfo, i, -23296);
|
|
} else {
|
|
renderTextOverPoi(poseStack, buffer, set2.size() + " potential owners", poiInfo, i, -23296);
|
|
}
|
|
|
|
renderTextOverPoi(poseStack, buffer, "Free tickets: " + poiInfo.freeTicketCount, poiInfo, ++i, -256);
|
|
renderTextOverPoi(poseStack, buffer, poiInfo.type, poiInfo, ++i, -1);
|
|
}
|
|
|
|
private void renderPath(PoseStack poseStack, MultiBufferSource buffer, BrainDump brainDump, double x, double y, double z) {
|
|
if (brainDump.path() != null) {
|
|
PathfindingRenderer.renderPath(poseStack, buffer, brainDump.path(), 0.5F, false, false, x, y, z);
|
|
}
|
|
}
|
|
|
|
private void renderBrainInfo(PoseStack poseStack, MultiBufferSource buffer, BrainDump brainDump, double x, double y, double z) {
|
|
boolean bl = this.isMobSelected(brainDump);
|
|
int i = 0;
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, brainDump.name(), -1, 0.03F);
|
|
i++;
|
|
if (bl) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, brainDump.profession() + " " + brainDump.xp() + " xp", -1, 0.02F);
|
|
i++;
|
|
}
|
|
|
|
if (bl) {
|
|
int j = brainDump.health() < brainDump.maxHealth() ? -23296 : -1;
|
|
renderTextOverMob(
|
|
poseStack,
|
|
buffer,
|
|
brainDump.pos(),
|
|
i,
|
|
"health: " + String.format(Locale.ROOT, "%.1f", brainDump.health()) + " / " + String.format(Locale.ROOT, "%.1f", brainDump.maxHealth()),
|
|
j,
|
|
0.02F
|
|
);
|
|
i++;
|
|
}
|
|
|
|
if (bl && !brainDump.inventory().equals("")) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, brainDump.inventory(), -98404, 0.02F);
|
|
i++;
|
|
}
|
|
|
|
if (bl) {
|
|
for (String string : brainDump.behaviors()) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, string, -16711681, 0.02F);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
for (String string : brainDump.activities()) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, string, -16711936, 0.02F);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (brainDump.wantsGolem()) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, "Wants Golem", -23296, 0.02F);
|
|
i++;
|
|
}
|
|
|
|
if (bl && brainDump.angerLevel() != -1) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, "Anger Level: " + brainDump.angerLevel(), -98404, 0.02F);
|
|
i++;
|
|
}
|
|
|
|
if (bl) {
|
|
for (String string : brainDump.gossips()) {
|
|
if (string.startsWith(brainDump.name())) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, string, -1, 0.02F);
|
|
} else {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, string, -23296, 0.02F);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
for (String string : Lists.reverse(brainDump.memories())) {
|
|
renderTextOverMob(poseStack, buffer, brainDump.pos(), i, string, -3355444, 0.02F);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (bl) {
|
|
this.renderPath(poseStack, buffer, brainDump, x, y, z);
|
|
}
|
|
}
|
|
|
|
private static void renderTextOverPoi(PoseStack poseStack, MultiBufferSource buffer, String text, BrainDebugRenderer.PoiInfo poiInfo, int layer, int color) {
|
|
renderTextOverPos(poseStack, buffer, text, poiInfo.pos, layer, color);
|
|
}
|
|
|
|
private static void renderTextOverPos(PoseStack poseStack, MultiBufferSource buffer, String text, BlockPos pos, int layer, int color) {
|
|
double d = 1.3;
|
|
double e = 0.2;
|
|
double f = pos.getX() + 0.5;
|
|
double g = pos.getY() + 1.3 + layer * 0.2;
|
|
double h = pos.getZ() + 0.5;
|
|
DebugRenderer.renderFloatingText(poseStack, buffer, text, f, g, h, color, 0.02F, true, 0.0F, true);
|
|
}
|
|
|
|
private static void renderTextOverMob(PoseStack poseStack, MultiBufferSource buffer, Position pos, int layer, String text, int color, float scale) {
|
|
double d = 2.4;
|
|
double e = 0.25;
|
|
BlockPos blockPos = BlockPos.containing(pos);
|
|
double f = blockPos.getX() + 0.5;
|
|
double g = pos.y() + 2.4 + layer * 0.25;
|
|
double h = blockPos.getZ() + 0.5;
|
|
float i = 0.5F;
|
|
DebugRenderer.renderFloatingText(poseStack, buffer, text, f, g, h, color, scale, false, 0.5F, true);
|
|
}
|
|
|
|
private Set<String> getTicketHolderNames(BrainDebugRenderer.PoiInfo poiInfo) {
|
|
return (Set<String>)this.getTicketHolders(poiInfo.pos).stream().map(DebugEntityNameGenerator::getEntityName).collect(Collectors.toSet());
|
|
}
|
|
|
|
private Set<String> getPotentialTicketHolderNames(BrainDebugRenderer.PoiInfo poiInfo) {
|
|
return (Set<String>)this.getPotentialTicketHolders(poiInfo.pos).stream().map(DebugEntityNameGenerator::getEntityName).collect(Collectors.toSet());
|
|
}
|
|
|
|
private boolean isMobSelected(BrainDump brainDump) {
|
|
return Objects.equals(this.lastLookedAtUuid, brainDump.uuid());
|
|
}
|
|
|
|
private boolean isPlayerCloseEnoughToMob(BrainDump brainDump) {
|
|
Player player = this.minecraft.player;
|
|
BlockPos blockPos = BlockPos.containing(player.getX(), brainDump.pos().y(), player.getZ());
|
|
BlockPos blockPos2 = BlockPos.containing(brainDump.pos());
|
|
return blockPos.closerThan(blockPos2, 30.0);
|
|
}
|
|
|
|
private Collection<UUID> getTicketHolders(BlockPos pos) {
|
|
return (Collection<UUID>)this.brainDumpsPerEntity
|
|
.values()
|
|
.stream()
|
|
.filter(brainDump -> brainDump.hasPoi(pos))
|
|
.map(BrainDump::uuid)
|
|
.collect(Collectors.toSet());
|
|
}
|
|
|
|
private Collection<UUID> getPotentialTicketHolders(BlockPos pos) {
|
|
return (Collection<UUID>)this.brainDumpsPerEntity
|
|
.values()
|
|
.stream()
|
|
.filter(brainDump -> brainDump.hasPotentialPoi(pos))
|
|
.map(BrainDump::uuid)
|
|
.collect(Collectors.toSet());
|
|
}
|
|
|
|
private Map<BlockPos, List<String>> getGhostPois() {
|
|
Map<BlockPos, List<String>> map = Maps.<BlockPos, List<String>>newHashMap();
|
|
|
|
for (BrainDump brainDump : this.brainDumpsPerEntity.values()) {
|
|
for (BlockPos blockPos : Iterables.concat(brainDump.pois(), brainDump.potentialPois())) {
|
|
if (!this.pois.containsKey(blockPos)) {
|
|
((List)map.computeIfAbsent(blockPos, blockPosx -> Lists.newArrayList())).add(brainDump.name());
|
|
}
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
private void updateLastLookedAtUuid() {
|
|
DebugRenderer.getTargetedEntity(this.minecraft.getCameraEntity(), 8).ifPresent(entity -> this.lastLookedAtUuid = entity.getUUID());
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public static class PoiInfo {
|
|
public final BlockPos pos;
|
|
public final String type;
|
|
public int freeTicketCount;
|
|
|
|
public PoiInfo(BlockPos pos, String type, int freeTicketCount) {
|
|
this.pos = pos;
|
|
this.type = type;
|
|
this.freeTicketCount = freeTicketCount;
|
|
}
|
|
}
|
|
}
|