mirror of
https://github.com/Astatin3/MC-server-icon.git
synced 2026-06-08 16:18:03 -06:00
Make the mod work
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ loom_version=1.11-SNAPSHOT
|
|||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=1.0.0
|
mod_version=1.0.0
|
||||||
maven_group=com.example
|
maven_group=dev.astatin3.favicon
|
||||||
archives_base_name=modid
|
archives_base_name=modid
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.example;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class ExampleMod implements ModInitializer {
|
|
||||||
public static final String MOD_ID = "modid";
|
|
||||||
|
|
||||||
// This logger is used to write text to the console and the log file.
|
|
||||||
// It is considered best practice to use your mod id as the logger's name.
|
|
||||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitialize() {
|
|
||||||
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
|
||||||
// However, some things (like resources) may still be uninitialized.
|
|
||||||
// Proceed with mild caution.
|
|
||||||
|
|
||||||
LOGGER.info("Hello Fabric world!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.example.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
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(MinecraftServer.class)
|
|
||||||
public class ExampleMixin {
|
|
||||||
@Inject(at = @At("HEAD"), method = "loadWorld")
|
|
||||||
private void init(CallbackInfo info) {
|
|
||||||
// This code is injected into the start of MinecraftServer.loadWorld()V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
package dev.astatin3.favicon;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
import net.minecraft.command.argument.TextArgumentType;
|
||||||
|
import net.minecraft.component.DataComponentTypes;
|
||||||
|
import net.minecraft.component.type.MapIdComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.item.map.MapState;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import net.minecraft.server.command.CommandManager;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static net.minecraft.server.command.CommandManager.literal;
|
||||||
|
|
||||||
|
public class ExampleMod implements ModInitializer {
|
||||||
|
public static final String MOD_ID = "favicon";
|
||||||
|
|
||||||
|
// This logger is used to write text to the console and the log file.
|
||||||
|
// It is considered best practice to use your mod id as the logger's name.
|
||||||
|
// That way, it's clear which mod wrote info, warnings, and errors.
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
// This code runs as soon as Minecraft is in a mod-load-ready state.
|
||||||
|
// However, some things (like resources) may still be uninitialized.
|
||||||
|
// Proceed with mild caution.
|
||||||
|
|
||||||
|
// LOGGER.info("Hello Fabric world!");
|
||||||
|
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("favicon")
|
||||||
|
.executes(context -> {
|
||||||
|
// For versions below 1.19, replace "Text.literal" with "new LiteralText".
|
||||||
|
// For versions below 1.20, remode "() ->" directly.
|
||||||
|
|
||||||
|
ServerPlayerEntity player = context.getSource().getPlayer();
|
||||||
|
ItemStack mainHandStack = player.getMainHandStack();
|
||||||
|
if(mainHandStack == null) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Error getting held item"), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Item item = mainHandStack.getItem();
|
||||||
|
if(!Objects.equals(item.toString(), "minecraft:filled_map")) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Invalid held item. You must be holding a Filled Map"), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MapIdComponent mapIdComponent = mainHandStack.get(DataComponentTypes.MAP_ID);
|
||||||
|
MapState mapState = player.getWorld().getMapState(mapIdComponent);
|
||||||
|
|
||||||
|
if(mapState == null) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Error getting map data"), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
MinecraftServer server = player.getServer();
|
||||||
|
|
||||||
|
ServerMetadata metadata = server.getServerMetadata();
|
||||||
|
|
||||||
|
if(metadata == null) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Error getting server metadata"), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Encoding icon data..."), false);
|
||||||
|
|
||||||
|
|
||||||
|
// for (int y = 0; y < 64; y++) {
|
||||||
|
// String text = "";
|
||||||
|
// for (int x = 0; x < 64; x++) {
|
||||||
|
// text += mapState.colors[y * 128 + x] + ", ";
|
||||||
|
// }
|
||||||
|
// String finalText = text;
|
||||||
|
// context.getSource().sendFeedback(() -> Text.literal(finalText), false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
BufferedImage bufImg = convertImage(mapState.colors);
|
||||||
|
byte[] favicon = toBytes(bufImg);
|
||||||
|
|
||||||
|
if(favicon == null) {
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Error encoding icon"), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Setting current server icon..."), false);
|
||||||
|
|
||||||
|
ServerMetadata newMetadata = new ServerMetadata(
|
||||||
|
metadata.description(),
|
||||||
|
metadata.players(),
|
||||||
|
metadata.version(),
|
||||||
|
Optional.of(new ServerMetadata.Favicon(favicon)),
|
||||||
|
metadata.secureChatEnforced()
|
||||||
|
);
|
||||||
|
|
||||||
|
((MetadataAccessor) server).setServerMetadata(newMetadata);
|
||||||
|
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Saving new icon file..."), false);
|
||||||
|
|
||||||
|
Path iconpath = server.getPath("server-icon.png");
|
||||||
|
try {
|
||||||
|
FileUtils.writeByteArrayToFile(iconpath.toFile(), favicon);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Done!"), false);
|
||||||
|
|
||||||
|
context.getSource().sendFeedback(() -> Text.literal("Current icon: " + server.getServerMetadata().favicon().get().iconBytes().length + " bytes"), false);
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
})));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(literal("motd")
|
||||||
|
// .then(CommandManager.argument("MOTD", StringArgumentType.greedyString())
|
||||||
|
// .executes(context -> {
|
||||||
|
//
|
||||||
|
// ServerPlayerEntity player = context.getSource().getPlayer();
|
||||||
|
// MinecraftServer server = player.getServer();
|
||||||
|
// ServerMetadata metadata = server.getServerMetadata();
|
||||||
|
//
|
||||||
|
// if(metadata == null) {
|
||||||
|
// context.getSource().sendFeedback(() -> Text.literal("Error getting server metadata"), false);
|
||||||
|
// return 1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// context.getSource().sendFeedback(() -> Text.literal("Setting server metadata..."), false);
|
||||||
|
// context.getSource().sendFeedback(() -> Text.literal("Preview:"), false);
|
||||||
|
//
|
||||||
|
// String motdText = StringArgumentType.getString(context, "MOTD");
|
||||||
|
// Text motd = Text.of(motdText);
|
||||||
|
//
|
||||||
|
// context.getSource().sendFeedback(() -> motd, false);
|
||||||
|
//
|
||||||
|
// ServerMetadata newMetadata = new ServerMetadata(
|
||||||
|
// motd,
|
||||||
|
// metadata.players(),
|
||||||
|
// metadata.version(),
|
||||||
|
// metadata.favicon(),
|
||||||
|
// metadata.secureChatEnforced()
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// ((MetadataAccessor) server).setServerMetadata(newMetadata);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// return 1;
|
||||||
|
// }))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage convertImage(byte[] mapBytes) {
|
||||||
|
|
||||||
|
if (mapBytes.length != 16384) {
|
||||||
|
throw new IllegalArgumentException("Image data must be exactly 16384 bytes (128x128)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create cropped image data (64x64 = 4096 bytes)
|
||||||
|
// byte[] croppedData = new byte[64 * 64];
|
||||||
|
|
||||||
|
BufferedImage bufferedImage = new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
|
// Copy top-left 64x64 quadrant
|
||||||
|
for (int y = 0; y < 64; y++) {
|
||||||
|
for (int x = 0; x < 64; x++) {
|
||||||
|
bufferedImage.setRGB(x, y, mapByteToColor(mapBytes[y * 128 + x]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufferedImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] toBytes(BufferedImage bufferedImage) {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
ImageIO.write(bufferedImage, "PNG", baos);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://minecraft.wiki/w/Map_item_format
|
||||||
|
private static final int[][] BASE_COLORS = {
|
||||||
|
{0, 0, 0}, // 0: None/Transparent
|
||||||
|
{127, 178, 56}, // 1: Grass
|
||||||
|
{247, 233, 163}, // 2: Sand
|
||||||
|
{199, 199, 199}, // 3: Wool
|
||||||
|
{255, 0, 0}, // 4: Fire
|
||||||
|
{160, 160, 255}, // 5: Ice
|
||||||
|
{167, 167, 167}, // 6: Metal
|
||||||
|
{0, 124, 0}, // 7: Plant
|
||||||
|
{255, 255, 255}, // 8: Snow
|
||||||
|
{164, 168, 184}, // 9: Clay
|
||||||
|
{151, 109, 77}, // 10: Dirt
|
||||||
|
{112, 112, 112}, // 11: Stone
|
||||||
|
{64, 64, 255}, // 12: Water
|
||||||
|
{143, 119, 72}, // 13: Wood
|
||||||
|
{255, 252, 245}, // 14: Quartz
|
||||||
|
{216, 127, 51}, // 15: Color Orange
|
||||||
|
{178, 76, 216}, // 16: Color Magenta
|
||||||
|
{102, 153, 216}, // 17: Color Light Blue
|
||||||
|
{229, 229, 51}, // 18: Color Yellow
|
||||||
|
{127, 204, 25}, // 19: Color Light Green
|
||||||
|
{242, 127, 165}, // 20: Color Pink
|
||||||
|
{76, 76, 76}, // 21: Color Gray
|
||||||
|
{153, 153, 153}, // 22: Color Light Gray
|
||||||
|
{76, 127, 153}, // 23: Color Cyan
|
||||||
|
{127, 63, 178}, // 24: Color Purple
|
||||||
|
{51, 76, 178}, // 25: Color Blue
|
||||||
|
{102, 76, 51}, // 26: Color Brown
|
||||||
|
{102, 127, 51}, // 27: Color Green
|
||||||
|
{153, 51, 51}, // 28: Color Red
|
||||||
|
{25, 25, 25}, // 29: Color Black
|
||||||
|
{250, 238, 77}, // 30: Gold
|
||||||
|
{92, 219, 213}, // 31: Diamond
|
||||||
|
{74, 128, 255}, // 32: Lapis
|
||||||
|
{0, 217, 58}, // 33: Emerald
|
||||||
|
{129, 86, 49}, // 34: Podzol
|
||||||
|
{112, 2, 0}, // 35: Nether
|
||||||
|
{209, 177, 161}, // 36: Terracotta White
|
||||||
|
{159, 82, 36}, // 37: Terracotta Orange
|
||||||
|
{149, 87, 108}, // 38: Terracotta Magenta
|
||||||
|
{112, 108, 138}, // 39: Terracotta Light Blue
|
||||||
|
{186, 133, 36}, // 40: Terracotta Yellow
|
||||||
|
{103, 117, 53}, // 41: Terracotta Light Green
|
||||||
|
{160, 77, 78}, // 42: Terracotta Pink
|
||||||
|
{57, 41, 35}, // 43: Terracotta Gray
|
||||||
|
{135, 107, 98}, // 44: Terracotta Light Gray
|
||||||
|
{87, 92, 92}, // 45: Terracotta Cyan
|
||||||
|
{122, 73, 88}, // 46: Terracotta Purple
|
||||||
|
{76, 62, 92}, // 47: Terracotta Blue
|
||||||
|
{76, 50, 35}, // 48: Terracotta Brown
|
||||||
|
{76, 82, 42}, // 49: Terracotta Green
|
||||||
|
{142, 60, 46}, // 50: Terracotta Red
|
||||||
|
{37, 22, 16}, // 51: Terracotta Black
|
||||||
|
{189, 48, 49}, // 52: Crimson Nylium
|
||||||
|
{148, 63, 97}, // 53: Crimson Stem
|
||||||
|
{92, 25, 29}, // 54: Crimson Hyphae
|
||||||
|
{22, 126, 134}, // 55: Warped Nylium
|
||||||
|
{58, 142, 140}, // 56: Warped Stem
|
||||||
|
{86, 44, 62}, // 57: Warped Hyphae
|
||||||
|
{20, 180, 133}, // 58: Warped Wart Block
|
||||||
|
{100, 100, 100}, // 59: Deepslate
|
||||||
|
{216, 175, 147}, // 60: Raw Iron
|
||||||
|
{127, 167, 150} // 61: Glow Lichen
|
||||||
|
};
|
||||||
|
|
||||||
|
// Brightness multipliers for each shade level
|
||||||
|
private static final double[] BRIGHTNESS_MULTIPLIERS = {
|
||||||
|
180.0 / 255.0, // 0: Darkest
|
||||||
|
220.0 / 255.0, // 1: Dark
|
||||||
|
255.0 / 255.0, // 2: Normal (brightest)
|
||||||
|
135.0 / 255.0 // 3: Very dark
|
||||||
|
};
|
||||||
|
|
||||||
|
public static int mapByteToColor(byte mapByte) {
|
||||||
|
int unsignedByte = mapByte & 0xFF;
|
||||||
|
|
||||||
|
// Color ID 0 is transparent
|
||||||
|
if (unsignedByte == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode base color and brightness level
|
||||||
|
int baseColorIndex = (unsignedByte - 1) / 4;
|
||||||
|
int brightnessLevel = (unsignedByte - 1) % 4;
|
||||||
|
|
||||||
|
// Validate base color index
|
||||||
|
if (baseColorIndex < 0 || baseColorIndex >= BASE_COLORS.length) {
|
||||||
|
return 0; // Return transparent for invalid colors
|
||||||
|
}
|
||||||
|
// Get base color RGB values
|
||||||
|
int[] baseRgb = BASE_COLORS[baseColorIndex];
|
||||||
|
double multiplier = BRIGHTNESS_MULTIPLIERS[brightnessLevel];
|
||||||
|
|
||||||
|
// Apply brightness multiplier
|
||||||
|
int r = (int) Math.round(baseRgb[0] * multiplier);
|
||||||
|
int g = (int) Math.round(baseRgb[1] * multiplier);
|
||||||
|
int b = (int) Math.round(baseRgb[2] * multiplier);
|
||||||
|
|
||||||
|
// Clamp values to 0-255 range
|
||||||
|
r = Math.max(0, Math.min(255, r));
|
||||||
|
g = Math.max(0, Math.min(255, g));
|
||||||
|
b = Math.max(0, Math.min(255, b));
|
||||||
|
|
||||||
|
// Combine into single RGB integer
|
||||||
|
return (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static int convertRgbByteToInt(byte rgbByte) {
|
||||||
|
// // Convert byte to unsigned int (0-255 range)
|
||||||
|
// int unsignedByte = rgbByte & 0xFF;
|
||||||
|
//
|
||||||
|
// // Extract the color components using bit masks and shifts
|
||||||
|
// int r = (unsignedByte >> 5) & 0x07; // Get top 3 bits (RRR)
|
||||||
|
// int g = (unsignedByte >> 2) & 0x07; // Get middle 3 bits (GGG)
|
||||||
|
// int b = unsignedByte & 0x03; // Get bottom 2 bits (BB)
|
||||||
|
//
|
||||||
|
// // Scale the values to full 8-bit range (0-255)
|
||||||
|
// // 3 bits (0-7) -> 8 bits (0-255): multiply by 255/7 ≈ 36.43
|
||||||
|
// // 2 bits (0-3) -> 8 bits (0-255): multiply by 255/3 = 85
|
||||||
|
// r = (r * 255) / 7; // Scale 3-bit to 8-bit
|
||||||
|
// g = (g * 255) / 7; // Scale 3-bit to 8-bit
|
||||||
|
// b = (b * 255) / 3; // Scale 2-bit to 8-bit
|
||||||
|
//
|
||||||
|
// // Combine into ARGB format: 0xAARRGGBB
|
||||||
|
// // Alpha = 255 (0xFF), fully opaque
|
||||||
|
// int argb = (255 << 24) | (r << 16) | (g << 8) | b;
|
||||||
|
//
|
||||||
|
// return argb;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package dev.astatin3.favicon;
|
||||||
|
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface MetadataAccessor {
|
||||||
|
default void setServerMetadata(ServerMetadata metadata) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package dev.astatin3.favicon.mixin;
|
||||||
|
|
||||||
|
import dev.astatin3.favicon.MetadataAccessor;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.ServerMetadata;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Mixin(MinecraftServer.class)
|
||||||
|
public class ExampleMixin implements MetadataAccessor {
|
||||||
|
@Shadow @Nullable private ServerMetadata metadata;
|
||||||
|
@Shadow @Nullable private ServerMetadata.Favicon favicon;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setServerMetadata(ServerMetadata metadata) {
|
||||||
|
this.metadata = metadata;
|
||||||
|
this.favicon = metadata.favicon().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
"name": "Example mod",
|
"name": "Example mod",
|
||||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
"description": "This is an example description! Tell everyone what your mod is about!",
|
||||||
"authors": [
|
"authors": [
|
||||||
"Me!"
|
"Astatin3"
|
||||||
],
|
],
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://fabricmc.net/",
|
"homepage": "https://fabricmc.net/",
|
||||||
@@ -16,18 +16,11 @@
|
|||||||
"environment": "*",
|
"environment": "*",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"main": [
|
"main": [
|
||||||
"com.example.ExampleMod"
|
"dev.astatin3.favicon.ExampleMod"
|
||||||
],
|
|
||||||
"client": [
|
|
||||||
"com.example.ExampleModClient"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"modid.mixins.json",
|
"modid.mixins.json"
|
||||||
{
|
|
||||||
"config": "modid.client.mixins.json",
|
|
||||||
"environment": "client"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.16.14",
|
"fabricloader": ">=0.16.14",
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"package": "com.example.mixin",
|
"package": "dev.astatin3.favicon.mixin",
|
||||||
"compatibilityLevel": "JAVA_21",
|
"compatibilityLevel": "JAVA_21",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"ExampleMixin"
|
"ExampleMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|||||||
Reference in New Issue
Block a user