Skip to content

Commit

Permalink
feat(debug): custom debug renderers and debug mode
Browse files Browse the repository at this point in the history
debug renderers are in core so that they do not need to be removed from
a mod before publishing. if they were in debug, the game would crash
trying to load them.
  • Loading branch information
CallMeEchoCodes committed Oct 21, 2024
1 parent d71e506 commit 0158b2c
Show file tree
Hide file tree
Showing 14 changed files with 609 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.spiritstudios.specter.api.core.debug;

import dev.spiritstudios.specter.impl.core.debug.DebugRendererRegistryImpl;
import dev.spiritstudios.specter.impl.core.debug.ToggleableDebugRenderer;
import net.minecraft.client.render.debug.DebugRenderer;
import net.minecraft.util.Identifier;

public final class DebugRendererRegistry {
public static void register(Identifier id, DebugRenderer.Renderer entry) {
DebugRendererRegistryImpl.register(id, new ToggleableDebugRenderer(entry));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dev.spiritstudios.specter.impl.core.debug;

import com.google.common.collect.ImmutableMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.util.Identifier;

import java.util.Map;

public final class DebugRendererRegistryImpl {
private static final Map<Identifier, ToggleableDebugRenderer> RENDERERS = new Object2ObjectOpenHashMap<>();

public static void register(Identifier id, ToggleableDebugRenderer entry) {
RENDERERS.put(id, entry);
}

public static Map<Identifier, ToggleableDebugRenderer> getRenderers() {
return ImmutableMap.copyOf(RENDERERS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.spiritstudios.specter.impl.core.debug;

import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.debug.DebugRenderer;
import net.minecraft.client.util.math.MatrixStack;

public final class ToggleableDebugRenderer implements DebugRenderer.Renderer {

private final DebugRenderer.Renderer renderer;
private boolean enabled;

public ToggleableDebugRenderer(DebugRenderer.Renderer renderer) {
this.renderer = renderer;
}

public void toggle() {
this.enabled = !enabled;
}

@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, double cameraX, double cameraY, double cameraZ) {
if (this.enabled) renderer.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package dev.spiritstudios.specter.impl.debug;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import dev.spiritstudios.specter.impl.core.debug.DebugRendererRegistryImpl;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.command.CommandSource;
import net.minecraft.command.argument.IdentifierArgumentType;
import net.minecraft.util.Identifier;

public final class DebugRenderCommand {
public static final SuggestionProvider<FabricClientCommandSource> DEBUG_RENDERER_SUGGESTIONS = (context, builder) ->
CommandSource.suggestIdentifiers(DebugRendererRegistryImpl.getRenderers().keySet(), builder);

public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher) {
dispatcher.register(ClientCommandManager.literal("debugrender")
.then(ClientCommandManager.argument("renderer", IdentifierArgumentType.identifier())
.suggests(DEBUG_RENDERER_SUGGESTIONS)
.executes(context -> {
Identifier id = context.getArgument("renderer", Identifier.class);
DebugRendererRegistryImpl.getRenderers().get(id).toggle();

return Command.SINGLE_SUCCESS;
})
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import dev.spiritstudios.specter.api.item.ItemMetatags;
import dev.spiritstudios.specter.api.render.RenderMetatags;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.minecraft.block.Block;
import net.minecraft.item.tooltip.TooltipType;
Expand Down Expand Up @@ -35,5 +36,9 @@ public void onInitializeClient() {

RenderMetatags.RENDER_LAYER.get(block).ifPresent(entry -> addMetatagLine(lines, "render_layer", entry.asString()));
});

ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> {
DebugRenderCommand.register(dispatcher);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package dev.spiritstudios.specter.mixin.debug.client;

import dev.spiritstudios.specter.impl.core.debug.DebugRendererRegistryImpl;
import dev.spiritstudios.specter.impl.core.debug.ToggleableDebugRenderer;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.debug.*;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(DebugRenderer.class)
public class DebugRendererMixin {
@Shadow
@Final
public DebugRenderer.Renderer waterDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer heightmapDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer collisionDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer supportingBlockDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer neighborUpdateDebugRenderer;

@Shadow
@Final
public StructureDebugRenderer structureDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer skyLightDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer blockOutlineDebugRenderer;

@Shadow
@Final
public DebugRenderer.Renderer chunkLoadingDebugRenderer;

@Shadow
@Final
public VillageDebugRenderer villageDebugRenderer;

@Shadow
@Final
public VillageSectionsDebugRenderer villageSectionsDebugRenderer;

@Shadow
@Final
public BeeDebugRenderer beeDebugRenderer;

@Shadow
@Final
public RaidCenterDebugRenderer raidCenterDebugRenderer;

@Shadow
@Final
public GoalSelectorDebugRenderer goalSelectorDebugRenderer;

@Shadow
@Final
public GameEventDebugRenderer gameEventDebugRenderer;

@Shadow
@Final
public LightDebugRenderer lightDebugRenderer;

@Shadow
@Final
public BreezeDebugRenderer breezeDebugRenderer;

@Shadow
@Final
public PathfindingDebugRenderer pathfindingDebugRenderer;

@Inject(method = "render", at = @At("RETURN"))
private void render(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) {
DebugRendererRegistryImpl.getRenderers().values()
.forEach(entry -> entry.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ));
}

@Inject(method = "<init>", at = @At("RETURN"))
private void init(MinecraftClient client, CallbackInfo ci) {
DebugRendererRegistryImpl.register(Identifier.ofVanilla("pathfinding"), new ToggleableDebugRenderer(pathfindingDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("water"), new ToggleableDebugRenderer(waterDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("heightmap"), new ToggleableDebugRenderer(heightmapDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("collision"), new ToggleableDebugRenderer(collisionDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("supporting_block"), new ToggleableDebugRenderer(supportingBlockDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("neighbor_update"), new ToggleableDebugRenderer(neighborUpdateDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("structure"), new ToggleableDebugRenderer(structureDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("sky_light"), new ToggleableDebugRenderer(skyLightDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("block_outline"), new ToggleableDebugRenderer(blockOutlineDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("chunk_loading"), new ToggleableDebugRenderer(chunkLoadingDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("village"), new ToggleableDebugRenderer(villageDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("village_sections"), new ToggleableDebugRenderer(villageSectionsDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("bee"), new ToggleableDebugRenderer(beeDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("raid_center"), new ToggleableDebugRenderer(raidCenterDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("goal_selector"), new ToggleableDebugRenderer(goalSelectorDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("game_event"), new ToggleableDebugRenderer(gameEventDebugRenderer));

DebugRendererRegistryImpl.register(Identifier.ofVanilla("light"), new ToggleableDebugRenderer(lightDebugRenderer));

DebugRendererRegistryImpl.register(
Identifier.ofVanilla("breeze"),
new ToggleableDebugRenderer((matrices, vertexConsumers, cameraX, cameraY, cameraZ) -> breezeDebugRenderer.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"required": true,
"minVersion": "0.8",
"package": "dev.spiritstudios.specter.mixin.debug.client",
"compatibilityLevel": "JAVA_21",
"injectors": {
"defaultRequire": 1
},
"client": [
"DebugRendererMixin"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package dev.spiritstudios.specter.mixin.debug;

import io.netty.channel.ChannelHandlerContext;
import net.minecraft.network.ClientConnection;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ClientConnection.class)
public abstract class ClientConnectionMixin {
@Shadow
@Final
private static Logger LOGGER;

@Inject(method = "exceptionCaught", at = @At("RETURN"))
private void exceptionCaught(ChannelHandlerContext context, Throwable ex, CallbackInfo ci) {
LOGGER.error("Failed to handle packet", ex);
}
}
Loading

0 comments on commit 0158b2c

Please sign in to comment.