diff --git a/library/misc/debug_renderers/build.gradle b/library/misc/debug_renderers/build.gradle new file mode 100644 index 0000000000..a206c6b818 --- /dev/null +++ b/library/misc/debug_renderers/build.gradle @@ -0,0 +1,36 @@ +plugins { + id("qsl.module") +} + +qslModule { + name = "Quilt Debug Renderers API" + moduleName = "debug_renderers" + id = "quilt_debug_renderers" + description = "Quilt APIs for creating and using debug renderers." + library = "misc" + moduleDependencies { + core { + api("qsl_base") + + compileOnly("networking") + testmodOnly("networking") + } + management { + compileOnly("client_command") + compileOnly("command") + testmodOnly("client_command") + testmodOnly("command") + } + } + entrypoints { + init { + values = ["org.quiltmc.qsl.debug_renderers.impl.Initializer"] + } + client_events { + values = ["org.quiltmc.qsl.debug_renderers.impl.client.VanillaDebugRenderers"] + } + client_init { + values = ["org.quiltmc.qsl.debug_renderers.impl.client.ClientInitializer"] + } + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/DebugFeature.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/DebugFeature.java new file mode 100644 index 0000000000..674bcb10a8 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/DebugFeature.java @@ -0,0 +1,85 @@ +package org.quiltmc.qsl.debug_renderers.api; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.impl.DebugFeaturesImpl; +import org.quiltmc.qsl.networking.api.PlayerLookup; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +public final class DebugFeature { + private final Identifier id; + private final boolean needsServer; + + private DebugFeature(Identifier id, boolean needsServer) { + this.id = id; + this.needsServer = needsServer; + } + + public boolean isEnabled() { + return DebugFeaturesImpl.isEnabled(this); + } + + public Collection getPlayersWithFeatureEnabled(MinecraftServer server) { + return DebugFeaturesImpl.isEnabled(this) ? + PlayerLookup.all(server).stream().filter(p -> DebugFeaturesImpl.isEnabledForPlayer(p, this)).toList() : + List.of(); + } + + public boolean isEnabledOnServerAndClient(ServerPlayerEntity player) { + return DebugFeaturesImpl.isEnabled(this) && DebugFeaturesImpl.isEnabledForPlayer(player, this); + } + + @ClientOnly + public boolean isEnabledOnServerAndClient() { + return DebugFeaturesImpl.isEnabledOnServer(this) && DebugFeaturesImpl.isEnabledOnServer(this); + } + + @ClientOnly + public boolean shouldRender() { + return this.isEnabled() && !this.needsServer() || this.isEnabledOnServerAndClient(); + } + + public static DebugFeature register(Identifier id, boolean needsServer) { + var existingFeature = DebugFeaturesImpl.get(id); + if (existingFeature != null) { + throw new IllegalArgumentException("A debug feature with the id %s already exists!".formatted(id)); + } + var newFeature = new DebugFeature(id, needsServer); + return DebugFeaturesImpl.register(newFeature); + } + + public Identifier id() { + return this.id; + } + + public boolean needsServer() { + return this.needsServer; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (DebugFeature) obj; + return Objects.equals(this.id, that.id) && + this.needsServer == that.needsServer; + } + + @Override + public int hashCode() { + return Objects.hash(this.id, this.needsServer); + } + + @Override + public String toString() { + return "DebugFeature[" + + "id=" + this.id + ", " + + "needsServer=" + this.needsServer + ']'; + } + +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/VanillaDebugFeatures.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/VanillaDebugFeatures.java new file mode 100644 index 0000000000..57d6f51c74 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/VanillaDebugFeatures.java @@ -0,0 +1,92 @@ +package org.quiltmc.qsl.debug_renderers.api; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.util.Identifier; + +/** + * In this class are {@link DebugFeature DebugFeatures} for the vanilla Debug Renderers which do not have other means + * of activation (i.e., not chunk borders, not collision, and not game test) + */ +public final class VanillaDebugFeatures { + /** + * @see net.minecraft.client.render.debug.DebugRenderer#pathfindingDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_PATH + */ + public static final DebugFeature PATHFINDING = DebugFeature.register(new Identifier("pathfinding"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#waterDebugRenderer + */ + public static final DebugFeature WATER = DebugFeature.register(new Identifier("water"), false); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#heightmapDebugRenderer + */ + public static final DebugFeature HEIGHTMAP = DebugFeature.register(new Identifier("heightmap"), false); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#neighborUpdateDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_NEIGHBORS_UPDATE + */ + public static final DebugFeature NEIGHBORS_UPDATE = DebugFeature.register(new Identifier("neighbors_update"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#structureDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_STRUCTURES + */ + public static final DebugFeature STRUCTURE = DebugFeature.register(new Identifier("structure"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#skyLightDebugRenderer + */ + public static final DebugFeature LIGHT = DebugFeature.register(new Identifier("light"), false); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#worldGenAttemptDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_WORLDGEN_ATTEMPT + */ + public static final DebugFeature WORLD_GEN_ATTEMPT = DebugFeature.register(new Identifier("world_gen_attempt"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#blockOutlineDebugRenderer + */ + public static final DebugFeature SOLID_FACE = DebugFeature.register(new Identifier("solid_face"), false); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#chunkLoadingDebugRenderer + */ + public static final DebugFeature CHUNK = DebugFeature.register(new Identifier("chunk"), false); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#villageDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_POI_ADDED + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_POI_REMOVED + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_POI_TICKET_COUNT + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_BRAIN + */ + public static final DebugFeature BRAIN = DebugFeature.register(new Identifier("brain"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#villageSectionsDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_VILLAGE_SECTIONS + */ + public static final DebugFeature VILLAGE_SECTIONS = DebugFeature.register(new Identifier("village_sections"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#beeDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_BEE + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_HIVE + */ + public static final DebugFeature BEE = DebugFeature.register(new Identifier("bee"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#raidCenterDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_RAIDS + */ + public static final DebugFeature RAID = DebugFeature.register(new Identifier("raid"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#goalSelectorDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_GOAL_SELECTOR + */ + public static final DebugFeature GOAL_SELECTOR = DebugFeature.register(new Identifier("goal_selector"), true); + /** + * @see net.minecraft.client.render.debug.DebugRenderer#gameEventDebugRenderer + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_GAME_EVENT + * @see net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket#DEBUG_GAME_EVENT_LISTENERS + */ + public static final DebugFeature GAME_EVENT = DebugFeature.register(new Identifier("game_event"), true); + + private VanillaDebugFeatures() {} + + @ApiStatus.Internal + public static void init() {} +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/client/DebugRendererRegistrationCallback.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/client/DebugRendererRegistrationCallback.java new file mode 100644 index 0000000000..93792a366e --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/api/client/DebugRendererRegistrationCallback.java @@ -0,0 +1,22 @@ +package org.quiltmc.qsl.debug_renderers.api.client; + +import net.minecraft.client.render.debug.DebugRenderer; +import org.quiltmc.qsl.base.api.event.Event; +import org.quiltmc.qsl.base.api.event.client.ClientEventAwareListener; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; + +@FunctionalInterface +public interface DebugRendererRegistrationCallback extends ClientEventAwareListener { + Event EVENT = Event.create(DebugRendererRegistrationCallback.class, callbacks -> registrar -> { + for (var callback : callbacks) { + callback.registerDebugRenderers(registrar); + } + }); + + void registerDebugRenderers(DebugRendererRegistrationCallback.DebugRendererRegistrar registrar); + + @FunctionalInterface + interface DebugRendererRegistrar { + void register(DebugFeature feature, DebugRenderer.Renderer renderer); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureCommands.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureCommands.java new file mode 100644 index 0000000000..87351e7224 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureCommands.java @@ -0,0 +1,68 @@ +package org.quiltmc.qsl.debug_renderers.impl; + +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.command.CommandSource; +import net.minecraft.command.argument.IdentifierArgumentType; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import org.quiltmc.qsl.command.api.CommandRegistrationCallback; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; + +@ApiStatus.Internal +final class DebugFeatureCommands { + static void init() { + CommandRegistrationCallback.EVENT.register((dispatcher, buildContext, environment) -> dispatcher.register( + literal("quilt_debug").then( + argument("feature", IdentifierArgumentType.identifier()) + .suggests((c, b) -> CommandSource.suggestIdentifiers(DebugFeaturesImpl.getFeatures().stream().filter(DebugFeature::needsServer).map(DebugFeature::id), b)).then( + literal("enable").executes(setEnabled(true)) + ).then( + literal("disable").executes(setEnabled(false)) + ) + ) + )); + } + + private static final DynamicCommandExceptionType INVALID_FEATURE = new DynamicCommandExceptionType(id -> Text.literal("No such Debug Feature "+id+"!")); + + private static final Dynamic2CommandExceptionType NOT_SERVER_FEATURE = new Dynamic2CommandExceptionType((id, enable) -> { + var suggestedCommand = "/quilt_debug_client " + id + " " + (enable == Boolean.TRUE ? "enable" : "disable"); + return Text.empty() + .append(Text.literal("Debug Feature " + id + " is not server-side! Did you mean to use [")) + .append(Text.literal(suggestedCommand).styled(s -> s.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, suggestedCommand)))) + .append("]"); + }); + + private static Command setEnabled(boolean value) { + return ctx -> { + var id = IdentifierArgumentType.getIdentifier(ctx, "feature"); + var feature = DebugFeaturesImpl.get(id); + if (feature == null) { + throw INVALID_FEATURE.create(id); + } + + if (!feature.needsServer()) { + throw NOT_SERVER_FEATURE.create(id, value); + } + + DebugFeaturesImpl.setEnabledNotifyClients(feature, value, ctx.getSource().getServer()); + ctx.getSource().sendFeedback( + Text.empty() + .append(Text.literal("[Debug|Server]: ").formatted(Formatting.LIGHT_PURPLE, Formatting.BOLD)) + .append(Text.literal(id+" "+(value ? "enabled" : "disabled"))), + true + ); + return Command.SINGLE_SUCCESS; + }; + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureSync.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureSync.java new file mode 100644 index 0000000000..07132cb236 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeatureSync.java @@ -0,0 +1,92 @@ +package org.quiltmc.qsl.debug_renderers.impl; + +import static org.quiltmc.qsl.debug_renderers.impl.Initializer.id; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; + +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; +import org.quiltmc.qsl.networking.api.PacketByteBufs; +import org.quiltmc.qsl.networking.api.ServerPlayNetworking; +import org.quiltmc.qsl.networking.api.client.ClientPlayNetworking; + +@ApiStatus.Internal +public final class DebugFeatureSync { + public static final Identifier SYNC_MESSAGE_ID = id("feature_sync"); + + @ClientOnly + public static void syncFeaturesToServer() { + var features = DebugFeaturesImpl.getFeatures(); + ClientPlayNetworking.send(SYNC_MESSAGE_ID, writeStatuses(features)); + } + + @ClientOnly + public static void syncFeaturesToServer(DebugFeature... features) { + ClientPlayNetworking.send(SYNC_MESSAGE_ID, writeStatuses(List.of(features))); + } + + public static void syncFeaturesToClient(ServerPlayerEntity... players) { + var features = DebugFeaturesImpl.getEnabledFeatures(); + ServerPlayNetworking.send(List.of(players), SYNC_MESSAGE_ID, writeStatuses(features)); + } + + public static void syncFeaturesToClient(Collection players, DebugFeature... features) { + ServerPlayNetworking.send(players, SYNC_MESSAGE_ID, writeStatuses(List.of(features))); + } + + public static PacketByteBuf writeStatuses(Collection features) { + var buf = PacketByteBufs.create(); + buf.writeVarInt(features.size()); + for (var feature : features) { + buf.writeIdentifier(feature.id()); + buf.writeBoolean(DebugFeaturesImpl.isEnabled(feature)); + } + return buf; + } + + public static Map readStatuses(PacketByteBuf buf) { + final int size = buf.readVarInt(); + var statuses = new HashMap(); + for (int i = 0; i < size; i++) { + var featureId = buf.readIdentifier(); + var feature = DebugFeaturesImpl.get(featureId); + if (feature == null) { + Initializer.LOGGER.warn("Received value for unknown debug feature {}", featureId); + continue; + } + boolean enabled = buf.readBoolean(); + statuses.put(feature, enabled); + } + + return statuses; + } + + public static void init() { + ServerPlayNetworking.registerGlobalReceiver(SYNC_MESSAGE_ID, (server, player, handler, buf, responseSender) -> { + var statuses = readStatuses(buf); + server.execute(() -> { + DebugFeaturesImpl.setEnabledForPlayer(player, statuses); + }); + }); + } + + @ClientOnly + public static void clientInit() { + ClientPlayNetworking.registerGlobalReceiver(SYNC_MESSAGE_ID, (client, handler, buf, responseSender) -> { + var statuses = readStatuses(buf); + client.execute(() -> { + DebugFeaturesImpl.setEnabledOnServer(statuses); + DebugFeatureSync.syncFeaturesToServer(); + }); + }); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeaturesImpl.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeaturesImpl.java new file mode 100644 index 0000000000..ae177072f4 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/DebugFeaturesImpl.java @@ -0,0 +1,112 @@ +package org.quiltmc.qsl.debug_renderers.impl; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; +import org.quiltmc.qsl.networking.api.PlayerLookup; + +import java.util.*; + +@ApiStatus.Internal +public class DebugFeaturesImpl { + private static final Map DEBUG_FEATURES = new HashMap<>(); + private static final Set ENABLED_FEATURES = new HashSet<>(); + private static final WeakHashMap> ENABLED_FEATURES_PER_PLAYER = new WeakHashMap<>(); + @ClientOnly + private static final Set ENABLED_FEATURES_ON_SERVER = new HashSet<>(); + + public static DebugFeature register(DebugFeature feature) { + DEBUG_FEATURES.put(feature.id(), feature); + return feature; + } + + public static @Nullable DebugFeature get(Identifier id) { + return DEBUG_FEATURES.get(id); + } + + public static Set getFeatures() { + return new HashSet<>(DEBUG_FEATURES.values()); + } + + public static boolean isEnabled(DebugFeature feature) { + return ENABLED_FEATURES.contains(feature); + } + + public static void setEnabled(DebugFeature feature, boolean value) { + if (value) { + ENABLED_FEATURES.add(feature); + } else { + ENABLED_FEATURES.remove(feature); + } + } + + public static void setEnabledNotifyClients(DebugFeature feature, boolean value, MinecraftServer server) { + setEnabled(feature, value); + DebugFeatureSync.syncFeaturesToClient(PlayerLookup.all(server), feature); + } + + @ClientOnly + public static void setEnabledNotifyServer(DebugFeature feature, boolean value) { + setEnabled(feature, value); + DebugFeatureSync.syncFeaturesToServer(feature); + } + + public static Set getEnabledFeatures() { + return new HashSet<>(ENABLED_FEATURES); + } + + public static boolean isEnabledForPlayer(ServerPlayerEntity player, DebugFeature feature) { + return ENABLED_FEATURES_PER_PLAYER.getOrDefault(player, Set.of()).contains(feature.id()); + } + + public static void setEnabledForPlayer(ServerPlayerEntity player, DebugFeature feature, boolean value) { + var set = ENABLED_FEATURES_PER_PLAYER.getOrDefault(player, new HashSet<>()); + if (value) { + set.add(feature.id()); + } else { + set.remove(feature.id()); + } + ENABLED_FEATURES_PER_PLAYER.put(player, set); + } + + public static void setEnabledForPlayer(ServerPlayerEntity player, Map statuses) { + var set = ENABLED_FEATURES_PER_PLAYER.getOrDefault(player, new HashSet<>()); + for (var entry : statuses.entrySet()) { + if (entry.getValue()) { + set.add(entry.getKey().id()); + } else { + set.remove(entry.getKey().id()); + } + } + ENABLED_FEATURES_PER_PLAYER.put(player, set); + } + + @ClientOnly + public static boolean isEnabledOnServer(DebugFeature feature) { + return ENABLED_FEATURES_ON_SERVER.contains(feature.id()); + } + + @ClientOnly + public static void setEnabledOnServer(DebugFeature feature, boolean value) { + if (value) { + ENABLED_FEATURES_ON_SERVER.add(feature.id()); + } else { + ENABLED_FEATURES_ON_SERVER.remove(feature.id()); + } + } + + @ClientOnly + public static void setEnabledOnServer(Map statuses) { + for (var entry : statuses.entrySet()) { + if (entry.getValue()) { + ENABLED_FEATURES_ON_SERVER.add(entry.getKey().id()); + } else { + ENABLED_FEATURES_ON_SERVER.remove(entry.getKey().id()); + } + } + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/Initializer.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/Initializer.java new file mode 100644 index 0000000000..b5c552b9f8 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/Initializer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.debug_renderers.impl; + +import com.mojang.logging.LogUtils; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.ApiStatus; +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.loader.api.QuiltLoader; +import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; +import org.quiltmc.qsl.debug_renderers.api.VanillaDebugFeatures; +import org.slf4j.Logger; + +@ApiStatus.Internal +public final class Initializer implements ModInitializer { + public static final String NAMESPACE = "quilt_debug_renderers"; + public static final Logger LOGGER = LogUtils.getLogger(); + public static boolean HAS_NETWORKING = QuiltLoader.isModLoaded("quilt_networking"); + + public static Identifier id(String path) { + return new Identifier(NAMESPACE, path); + } + + @Override + public void onInitialize(ModContainer mod) { + if (HAS_NETWORKING) { + DebugFeatureSync.init(); + LOGGER.info("[Quilt Debug Renderers] Networking support is enabled"); + } else { + LOGGER.info("[Quilt Debug Renderers] Networking support is disabled"); + } + + if (QuiltLoader.isModLoaded("quilt_command")) { + LOGGER.info("[Quilt Debug Renderers] Command support is enabled"); + DebugFeatureCommands.init(); + } else { + LOGGER.info("[Quilt Debug Renderers] Command support is disabled"); + } + + VanillaDebugFeatures.init(); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/ClientInitializer.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/ClientInitializer.java new file mode 100644 index 0000000000..d5f87f0066 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/ClientInitializer.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016, 2017, 2018, 2019, 2020 zml and Colonel contributors + * Copyright 2022 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.debug_renderers.impl.client; + +import com.mojang.logging.LogUtils; +import net.minecraft.client.MinecraftClient; +import org.jetbrains.annotations.ApiStatus; +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.api.client.DebugRendererRegistrationCallback; +import org.quiltmc.qsl.debug_renderers.impl.DebugFeatureSync; +import org.quiltmc.qsl.debug_renderers.impl.Initializer; +import org.slf4j.Logger; + +import org.quiltmc.loader.api.ModContainer; +import org.quiltmc.loader.api.QuiltLoader; +import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer; + +@ApiStatus.Internal +@ClientOnly +public final class ClientInitializer implements ClientModInitializer { + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public void onInitializeClient(ModContainer mod) { + if (QuiltLoader.isModLoaded("quilt_networking")) { + DebugFeatureSync.clientInit(); + LOGGER.info("[Quilt Debug Renderers|Client] Networking support is enabled"); + } else { + LOGGER.info("[Quilt Debug Renderers|Client] Networking support is disabled"); + } + + if (QuiltLoader.isModLoaded("quilt_client_command")) { + LOGGER.info("[Quilt Debug Renderers|Client] Client Command support is enabled"); + DebugFeatureClientCommands.init(); + } else { + LOGGER.info("[Quilt Debug Renderers|Client] Client Command support is disabled"); + } + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugFeatureClientCommands.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugFeatureClientCommands.java new file mode 100644 index 0000000000..21e8417483 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugFeatureClientCommands.java @@ -0,0 +1,70 @@ +package org.quiltmc.qsl.debug_renderers.impl.client; + +import static org.quiltmc.qsl.command.api.client.ClientCommandManager.argument; +import static org.quiltmc.qsl.command.api.client.ClientCommandManager.literal; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.command.CommandSource; +import net.minecraft.command.argument.IdentifierArgumentType; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; + +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.command.api.client.ClientCommandRegistrationCallback; +import org.quiltmc.qsl.command.api.client.QuiltClientCommandSource; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; +import org.quiltmc.qsl.debug_renderers.impl.DebugFeaturesImpl; + +@ApiStatus.Internal +@ClientOnly +final class DebugFeatureClientCommands { + static void init() { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, buildContext, environment) -> dispatcher.register( + literal("quilt_debug_client").then( + argument("feature", IdentifierArgumentType.identifier()) + .suggests((c, b) -> CommandSource.suggestIdentifiers(DebugFeaturesImpl.getFeatures().stream().map(DebugFeature::id), b)).then( + literal("enable").executes(setEnabled(true)) + ).then( + literal("disable").executes(setEnabled(false)) + ) + ) + )); + } + + private static final DynamicCommandExceptionType INVALID_FEATURE = new DynamicCommandExceptionType(id -> Text.literal("No such Debug Feature "+id+"!")); + + private static Command setEnabled(boolean value) { + return ctx -> { + var id = ctx.getArgument("feature", Identifier.class); + var feature = DebugFeaturesImpl.get(id); + if (feature == null) { + throw INVALID_FEATURE.create(id); + } + + if (feature.needsServer() && !DebugFeaturesImpl.isEnabledOnServer(feature)) { + var suggestedCommand = "/quilt_debug " + id + " enable"; + ctx.getSource().sendFeedback( + Text.empty() + .append(Text.literal("[Debug|Client]: ").formatted(Formatting.LIGHT_PURPLE, Formatting.BOLD)) + .append(Text.literal("Debug Feature " + id + " must be enabled on the server, but it is not - enable it with [")).formatted(Formatting.YELLOW) + .append(Text.literal(suggestedCommand).styled(s -> s.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, suggestedCommand)).withColor(Formatting.WHITE))) + .append(Text.literal("]")).formatted(Formatting.YELLOW) + ); + } + + DebugFeaturesImpl.setEnabledNotifyServer(feature, value); + + ctx.getSource().sendFeedback( + Text.empty() + .append(Text.literal("[Debug|Client]: ").formatted(Formatting.LIGHT_PURPLE, Formatting.BOLD)) + .append(Text.literal(id+" "+(value ? "enabled" : "disabled"))) + ); + return Command.SINGLE_SUCCESS; + }; + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugRendererRegistry.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugRendererRegistry.java new file mode 100644 index 0000000000..5a4a0bc86f --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/DebugRendererRegistry.java @@ -0,0 +1,33 @@ +package org.quiltmc.qsl.debug_renderers.impl.client; + +import net.minecraft.client.render.debug.DebugRenderer; +import org.jetbrains.annotations.ApiStatus; +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.api.DebugFeature; +import org.quiltmc.qsl.debug_renderers.impl.DebugFeaturesImpl; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@ApiStatus.Internal +@ClientOnly +public final class DebugRendererRegistry { + private static final Map RENDERERS = new HashMap<>(); + + DebugRendererRegistry() {} + + public static void register(DebugFeature feature, DebugRenderer.Renderer renderer) { + RENDERERS.put(feature, renderer); + } + + public static Collection getEnabledRenderers() { + return DebugFeaturesImpl.getEnabledFeatures().stream() + .filter(DebugFeature::shouldRender) + .map(RENDERERS::get) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/VanillaDebugRenderers.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/VanillaDebugRenderers.java new file mode 100644 index 0000000000..eba8517912 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/impl/client/VanillaDebugRenderers.java @@ -0,0 +1,33 @@ +package org.quiltmc.qsl.debug_renderers.impl.client; + +import org.jetbrains.annotations.ApiStatus; + +import net.minecraft.client.MinecraftClient; + +import org.quiltmc.loader.api.minecraft.ClientOnly; +import org.quiltmc.qsl.debug_renderers.api.client.DebugRendererRegistrationCallback; +import org.quiltmc.qsl.debug_renderers.api.VanillaDebugFeatures; + +@ApiStatus.Internal +@ClientOnly +public class VanillaDebugRenderers implements DebugRendererRegistrationCallback { + @Override + public void registerDebugRenderers(DebugRendererRegistrar registrar) { + var debugRenderer = MinecraftClient.getInstance().debugRenderer; + registrar.register(VanillaDebugFeatures.PATHFINDING, debugRenderer.pathfindingDebugRenderer); + registrar.register(VanillaDebugFeatures.WATER, debugRenderer.waterDebugRenderer); + registrar.register(VanillaDebugFeatures.HEIGHTMAP, debugRenderer.heightmapDebugRenderer); + registrar.register(VanillaDebugFeatures.NEIGHBORS_UPDATE, debugRenderer.neighborUpdateDebugRenderer); + registrar.register(VanillaDebugFeatures.STRUCTURE, debugRenderer.structureDebugRenderer); + registrar.register(VanillaDebugFeatures.LIGHT, debugRenderer.skyLightDebugRenderer); + registrar.register(VanillaDebugFeatures.WORLD_GEN_ATTEMPT, debugRenderer.worldGenAttemptDebugRenderer); + registrar.register(VanillaDebugFeatures.SOLID_FACE, debugRenderer.blockOutlineDebugRenderer); + registrar.register(VanillaDebugFeatures.CHUNK, debugRenderer.chunkLoadingDebugRenderer); + registrar.register(VanillaDebugFeatures.BRAIN, debugRenderer.villageDebugRenderer); + registrar.register(VanillaDebugFeatures.VILLAGE_SECTIONS, debugRenderer.villageSectionsDebugRenderer); + registrar.register(VanillaDebugFeatures.BEE, debugRenderer.beeDebugRenderer); + registrar.register(VanillaDebugFeatures.RAID, debugRenderer.raidCenterDebugRenderer); + registrar.register(VanillaDebugFeatures.GOAL_SELECTOR, debugRenderer.goalSelectorDebugRenderer); + registrar.register(VanillaDebugFeatures.GAME_EVENT, debugRenderer.gameEventDebugRenderer); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugInfoSenderMixin.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugInfoSenderMixin.java new file mode 100644 index 0000000000..92460b8904 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugInfoSenderMixin.java @@ -0,0 +1,151 @@ +package org.quiltmc.qsl.debug_renderers.mixin; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.pathing.Path; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.mob.PathAwareEntity; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.server.network.DebugInfoSender; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.structure.StructureStart; +import net.minecraft.structure.piece.StructurePiece; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.village.VillagerDataContainer; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import org.quiltmc.qsl.debug_renderers.api.VanillaDebugFeatures; +import org.quiltmc.qsl.debug_renderers.impl.Initializer; +import org.quiltmc.qsl.networking.api.PacketByteBufs; +import org.quiltmc.qsl.networking.api.ServerPlayNetworking; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Objects; + +@Mixin(DebugInfoSender.class) +public abstract class DebugInfoSenderMixin { + //TODO re-implement the empty methods in DebugInfoSender + + @Shadow + private static String format(ServerWorld world, @Nullable Object object) { + throw new UnsupportedOperationException("mixin"); + } + + @Shadow + private static void writeBrain(LivingEntity entity, PacketByteBuf buf) {} + + /** + * @author QuiltMC, Will BL + * @reason Re-implementation of method with missing body + */ + @Overwrite + public static void sendPathfindingData(World world, MobEntity mob, @Nullable Path path, float nodeReachProximity) { + if (path == null || world.isClient() || !Initializer.HAS_NETWORKING) { + return; + } + var buf = PacketByteBufs.create(); + buf.writeInt(mob.getId()); + path.toBuffer(buf); + buf.writeFloat(nodeReachProximity); + ServerPlayNetworking.send( + VanillaDebugFeatures.PATHFINDING.getPlayersWithFeatureEnabled(world.getServer()), + CustomPayloadS2CPacket.DEBUG_PATH, + buf + ); + } + + /** + * @author QuiltMC, Will BL + * @reason Re-implementation of method with missing body + */ + @Overwrite + public static void sendNeighborUpdate(World world, BlockPos pos) { + if (world.isClient() || !Initializer.HAS_NETWORKING) { + return; + } + + var buf = PacketByteBufs.create(); + buf.writeVarLong(world.getTime()); + buf.writeBlockPos(pos); + ServerPlayNetworking.send( + VanillaDebugFeatures.NEIGHBORS_UPDATE.getPlayersWithFeatureEnabled(world.getServer()), + CustomPayloadS2CPacket.DEBUG_NEIGHBORS_UPDATE, + buf + ); + } + + /** + * @author QuiltMC, Will BL + * @reason Re-implementation of method with missing body + */ + @Overwrite + public static void sendStructureStart(StructureWorldAccess world, StructureStart structureStart) { + if (world.isClient() || !Initializer.HAS_NETWORKING) { + return; + } + var server = Objects.requireNonNull(world.getServer()); + var registryManager = server.getRegistryManager(); + var buf = PacketByteBufs.create(); + buf.writeIdentifier(registryManager.get(Registry.DIMENSION_TYPE_KEY).getId(world.getDimension())); + var box = structureStart.setBoundingBoxFromChildren(); + buf.writeInt(box.getMinX()); + buf.writeInt(box.getMinY()); + buf.writeInt(box.getMinZ()); + buf.writeInt(box.getMaxX()); + buf.writeInt(box.getMaxY()); + buf.writeInt(box.getMaxZ()); + var children = structureStart.getChildren(); + buf.writeInt(children.size()); + for (int i = 0; i < children.size(); i++) { + StructurePiece child = children.get(i); + box = child.getBoundingBox(); + buf.writeInt(box.getMinX()); + buf.writeInt(box.getMinY()); + buf.writeInt(box.getMinZ()); + buf.writeInt(box.getMaxX()); + buf.writeInt(box.getMaxY()); + buf.writeInt(box.getMaxZ()); + buf.writeBoolean(i == 0); + } + ServerPlayNetworking.send( + VanillaDebugFeatures.STRUCTURE.getPlayersWithFeatureEnabled(world.getServer()), + CustomPayloadS2CPacket.DEBUG_STRUCTURES, + buf + ); + } + + /** + * @author QuiltMC, Will BL + * @reason Re-implementation of method with missing body + */ + @Overwrite + public static void sendBrainDebugData(LivingEntity living) { + if (living.world.isClient() || !Initializer.HAS_NETWORKING) { + return; + } + + var buf = PacketByteBufs.create(); + buf.writeDouble(living.getX()); + buf.writeDouble(living.getY()); + buf.writeDouble(living.getZ()); + buf.writeUuid(living.getUuid()); + buf.writeInt(living.getId()); + buf.writeString(format((ServerWorld) living.world, living)); + buf.writeString(living instanceof VillagerDataContainer villager ? villager.getVillagerData().getProfession().name() : "none"); + buf.writeInt(living instanceof VillagerEntity villager ? villager.getExperience() : 0); + buf.writeFloat(living.getHealth()); + buf.writeFloat(living.getMaxHealth()); + writeBrain(living, buf); + ServerPlayNetworking.send( + VanillaDebugFeatures.BRAIN.getPlayersWithFeatureEnabled(living.getServer()), + CustomPayloadS2CPacket.DEBUG_BRAIN, + buf + ); + } + +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugRendererMixin.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugRendererMixin.java new file mode 100644 index 0000000000..917f2c5cec --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/DebugRendererMixin.java @@ -0,0 +1,19 @@ +package org.quiltmc.qsl.debug_renderers.mixin; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.debug.DebugRenderer; +import net.minecraft.client.util.math.MatrixStack; +import org.quiltmc.qsl.debug_renderers.impl.client.DebugRendererRegistry; +import org.spongepowered.asm.mixin.Mixin; +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 { + @Inject(method = "render", at = @At("TAIL")) + private void quilt$renderCustomDebugRenderers(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo ci) { + DebugRendererRegistry.getEnabledRenderers() + .forEach(r -> r.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ)); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/MinecraftClientMixin.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/MinecraftClientMixin.java new file mode 100644 index 0000000000..fa74c0afb0 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/MinecraftClientMixin.java @@ -0,0 +1,18 @@ +package org.quiltmc.qsl.debug_renderers.mixin; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.RunArgs; +import org.quiltmc.qsl.debug_renderers.api.client.DebugRendererRegistrationCallback; +import org.quiltmc.qsl.debug_renderers.impl.client.DebugRendererRegistry; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin { + @Inject(method = "", at = @At(value = "INVOKE", shift = At.Shift.BY, by=2, target = "Lnet/minecraft/client/render/debug/DebugRenderer;(Lnet/minecraft/client/MinecraftClient;)V")) + private void quilt$initDebugRenderers(RunArgs args, CallbackInfo ci) { + DebugRendererRegistrationCallback.EVENT.invoker().registerDebugRenderers(DebugRendererRegistry::register); + } +} diff --git a/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/PlayerManagerMixin.java b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/PlayerManagerMixin.java new file mode 100644 index 0000000000..b61c051093 --- /dev/null +++ b/library/misc/debug_renderers/src/main/java/org/quiltmc/qsl/debug_renderers/mixin/PlayerManagerMixin.java @@ -0,0 +1,20 @@ +package org.quiltmc.qsl.debug_renderers.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.ClientConnection; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; + +import org.quiltmc.qsl.debug_renderers.impl.DebugFeatureSync; + +@Mixin(PlayerManager.class) +public class PlayerManagerMixin { + @Inject(method = "onPlayerConnect", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;sendCommandTree(Lnet/minecraft/server/network/ServerPlayerEntity;)V")) + private void quilt$tellPlayerAboutDebugFeatures(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) { + DebugFeatureSync.syncFeaturesToClient(player); + } +} diff --git a/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/icon.png b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/icon.png new file mode 100644 index 0000000000..8d54ad0021 Binary files /dev/null and b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/icon.png differ diff --git a/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/en_us.json b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/en_us.json new file mode 100644 index 0000000000..4f5c3a53da --- /dev/null +++ b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "quilt.argument.enum.unknown_value": "Unknown enum value \"%s\"" +} diff --git a/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/fi_fi.json b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/fi_fi.json new file mode 100644 index 0000000000..c558a29b0f --- /dev/null +++ b/library/misc/debug_renderers/src/main/resources/assets/quilt_debug_renderers/lang/fi_fi.json @@ -0,0 +1,3 @@ +{ + "quilt.argument.enum.unknown_value": "Tuntematon enum-arvo \"%s\"" +} diff --git a/library/misc/debug_renderers/src/main/resources/quilt_debug_renderers.mixins.json b/library/misc/debug_renderers/src/main/resources/quilt_debug_renderers.mixins.json new file mode 100644 index 0000000000..280d3bcc12 --- /dev/null +++ b/library/misc/debug_renderers/src/main/resources/quilt_debug_renderers.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "org.quiltmc.qsl.debug_renderers.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "DebugInfoSenderMixin", + "MinecraftClientMixin", + "PlayerManagerMixin" + ], + "client": [ + "DebugRendererMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/library/misc/debug_renderers/src/testmod/resources/quilt.mod.json b/library/misc/debug_renderers/src/testmod/resources/quilt.mod.json new file mode 100644 index 0000000000..adb3c897dc --- /dev/null +++ b/library/misc/debug_renderers/src/testmod/resources/quilt.mod.json @@ -0,0 +1,29 @@ +{ + "schema_version": 1, + "quilt_loader": { + "group": "org.quiltmc.qsl.debug_renderers", + "id": "quilt_debug_renderers_testmod", + "version": "1.0.0", + "metadata": { + "name": "Quilt Debug Renderers API Test Mod", + "description": "Testmod for Quilt Debug Renderers API.", + "license": "Apache-2.0", + "contact": { + "homepage": "https://quiltmc.org", + "issues": "https://github.com/QuiltMC/quilt-standard-libraries/issues", + "sources": "https://github.com/QuiltMC/quilt-standard-libraries" + }, + "contributors": { + "QuiltMC: QSL Team": "Author" + } + }, + "intermediate_mappings": "net.fabricmc:intermediary", + "load_type": "always", + "entrypoints": { + }, + "depends": [ + "quilt_loader", + "quilt_debug_renderers" + ] + } +}