diff --git a/common/build.gradle b/common/build.gradle index 2a88c5e..4b92f50 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -5,7 +5,7 @@ dependencies { // Remove the next line if you don't want to depend on the API modApi "dev.architectury:architectury:${rootProject.architectury_version}" - modApi "me.shedaniel.cloth:cloth-config-fabric:11.0.99" + modApi "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_config_version}" } architectury { diff --git a/common/src/main/java/me/zacharias/speedometer/Client.java b/common/src/main/java/me/zacharias/speedometer/Client.java index 96247b0..a2d8b5b 100644 --- a/common/src/main/java/me/zacharias/speedometer/Client.java +++ b/common/src/main/java/me/zacharias/speedometer/Client.java @@ -11,22 +11,21 @@ import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.ClickEvent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.animal.Pig; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.vehicle.Boat; -import net.minecraft.world.entity.vehicle.Minecart; import net.minecraft.world.phys.Vec3; import net.minecraft.network.chat.Component; +import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Objects; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; -import static me.zacharias.speedometer.Speedometer.LOGGER; -import static me.zacharias.speedometer.Speedometer.MOD_ID; +import static me.zacharias.speedometer.Speedometer.*; public class Client { public static final KeyMapping CONFIG_KEY = new KeyMapping( @@ -44,11 +43,10 @@ public class Client { private static final ArrayList speeds = new ArrayList<>(); private static boolean speedometerVisualDisplayFailed = false; - public static BufferedImage img = null; public static void init(){ - final boolean isClothLoaded = false;//Platform.isModLoaded("cloth_config") || Platform.isModLoaded("cloth-config"); + final boolean isClothLoaded = Platform.isModLoaded("cloth_config") || Platform.isModLoaded("cloth-config"); if(isClothLoaded) { Platform.getMod(MOD_ID).registerConfigurationScreen(parent -> ConfigMenu.getConfig(parent).build()); @@ -97,11 +95,6 @@ public class Client { ClientGuiEvent.RENDER_HUD.register(Client::render); - LOGGER.info("Loading speedometer "); - if(!MeterImages.LARGE.initiate()){ - speedometerVisualDisplayFailed = true; - } - LOGGER.info("Finished loading speedometer"); } @@ -109,28 +102,22 @@ public class Client { if(Minecraft.getInstance().player == null) return; Entity entity = Minecraft.getInstance().player.getRootVehicle(); - Vec3 vec = entity.getDeltaMovement(); + Vec3 vec = new Vec3( + entity.getX() - entity.xOld, + entity.getY() - entity.yOld, + entity.getZ() - entity.zOld + ); - double yOffset = 0.0784000015258789D; + double yOffset = 0D; double xOffset = 0D; double zOffset = 0D; double vOffset = 0D; - if (entity instanceof Player e) { - if (!e.onGround() && e.isCreative()) { - yOffset = 0; - } else if (e.isInWater()) { - yOffset = 0.005; - } - } else if (entity instanceof Boat || entity instanceof Minecart || entity instanceof Pig) { - yOffset = 0; - } - double speed = (Math.sqrt(Math.pow(vec.x + xOffset, 2) + Math.pow(vec.y + yOffset, 2) + Math.pow(vec.z + zOffset, 2)) * 20)+vOffset; double lSpeed = speed; if (speeds.size() >= 30) { - speeds.remove(0); + speeds.removeFirst(); } speeds.add(speed); speed = 0; @@ -153,54 +140,32 @@ public class Client { } String format = String.format("%.2f", speedTypeSpeed); - - //double v = (Math.pow(1.0233435, speedTypeSpeed)-1)/100; - double v = switch (speedType){ - case KMPH -> Math.pow(speedTypeSpeed,0.87)-1; - case BlockPS, MPS -> Math.pow(speedTypeSpeed,1.25); - case MPH -> speedTypeSpeed; - case KNOT -> Math.pow(speedTypeSpeed,1.05); - }/100; - - double i = (v *(316-45))+45; String speedString = format + " " + SpeedTypes.getName(speedType).getString(); - int width = switch ((Config.getVisualSpeedometer() && !speedometerVisualDisplayFailed) ? 1 : 0){ + int width = switch ((Config.getVisualSpeedometer() && !Config.isDisableVisualSpeedometer()) ? 1 : 0){ case 1 -> Config.getImageSize(); case 0 -> Minecraft.getInstance().font.width(speedString); default -> 0; }; - int yPos = getPos(graphics, width, Config.getYPosition(), 1); - int xPos = getPos(graphics, width, Config.getXPosition(), 0); + int yPos = getPos(graphics, width, Config.getYPosition(), false); + int xPos = getPos(graphics, width, Config.getXPosition(), true); int lineHeight = Minecraft.getInstance().font.lineHeight; - if(Config.getVisualSpeedometer() && !speedometerVisualDisplayFailed){ + if(Config.getVisualSpeedometer() && !Config.isDisableVisualSpeedometer()){ //double v = speedTypeSpeed / speedType.gatMaxVisual(); - img = ImageHandler.clone(MeterImages.LARGE.getImage()); + BufferedImage img = ImageHandler.scale(ICON.getSpeedometerIcon(speedTypeSpeed), Config.getImageSize(), Config.getImageSize()); - Graphics2D g2d = img.createGraphics(); - - g2d.setColor(new Color(138, 0, 0)); - g2d.setFont(new Font(g2d.getFont().getName(), Font.PLAIN, 15)); - - if(Config.getShowSpeedType()){ - speedString = SpeedTypes.getName(speedType).getString(); - drawString(graphics, xPos - width, yPos - Config.getImageSize() - lineHeight - 1, speedString, Config.getColor().getRGB()); - } - - BufferedImage img = ImageHandler.scale(Client.img, Config.getImageSize(), Config.getImageSize()); - - int radius = img.getWidth()/2-4; + /*int radius = img.getWidth()/2-4; int x3 = (int) Math.round(radius*Math.cos(Math.toRadians(i+90)))+(img.getWidth()/2); int y3 = (int) Math.round(radius*Math.sin(Math.toRadians(i+90)))+(img.getHeight()/2); - g2d = img.createGraphics(); + Graphics2D g2d = img.createGraphics(); g2d.setColor(new Color(138, 0, 0)); @@ -227,9 +192,21 @@ public class Client { Minecraft.getInstance().font, string, xPos-Minecraft.getInstance().font.width(string), - (int)(yPos-4.5-(Config.getImageSize()/2)), + (int)(yPos-4.5-((double) Config.getImageSize() /2)), new Color(138, 0, 0).getRGB() ); + }*/ + for(int x1 = 0; x1 < img.getWidth(); x1++){ + for(int y1 = 0; y1 < img.getHeight(); y1++){ + int x2 = x1 + xPos - img.getWidth(); + int y2 = y1 + yPos - img.getHeight(); + + int rgb = img.getRGB(x1, y1); + + if(new Color(rgb).equals(Color.black)) continue; + + graphics.fill(x2, y2, x2+1, y2+1, rgb); + } } }else { @@ -262,8 +239,8 @@ public class Client { " Total: " + lSpeed + "\n" + "Velocity total average: " + speed + "\n" + "Velocity total in " + speedType.name() + ": " + speedTypeSpeed + "\n" + - "Percentage point of visual speedometer: " + v + "\n" + - "Degree end point: " + i +"\n" + + "Percentage point of visual speedometer: " + /*v*/"error" + "\n" + + "Degree end point: " + /*i*/"error" +"\n" + (Config.getVisualSpeedometer()?"Visual Size: ":"Textual display") + Config.getImageSize(); Color color = new Color(255, 255, 255); @@ -286,20 +263,20 @@ public class Client { ); } - private static int getPos(GuiGraphics event, int width, String input, int type) { + private static int getPos(GuiGraphics event, int width, String input, boolean isXPosition) { ArrayList passerPose = new ArrayList<>(); final char[] s = input.toCharArray(); + try{ for(int i = 0; i 0) { + if(i-1 > 0 && passerPose.get(i - 1).matches("^[0-9]+$")) { Integer.parseInt(passerPose.get(i - 1)); passerPose.add(i - 1, passerPose.get(i - 1) + s[i]); } @@ -327,17 +304,17 @@ public class Client { } }catch (Exception e){ passerPose.clear(); - defaultValues(event, type, passerPose); + defaultValues(event, isXPosition, passerPose); } // - int xPos; + int position; try{ - xPos = Integer.parseInt(passerPose.get(0)); + position = Integer.parseInt(passerPose.getFirst()); }catch (NumberFormatException e){ - defaultValues(event, type, passerPose); - xPos = Integer.parseInt(passerPose.get(0)); + defaultValues(event, isXPosition, passerPose); + position = Integer.parseInt(passerPose.getFirst()); } for(int i = 1; i < passerPose.size(); i++){ @@ -351,31 +328,34 @@ public class Client { } if(Objects.equals(s1, "+") && !first){ - xPos += Integer.parseInt(s2); + position += Integer.parseInt(s2); }else if(Objects.equals(s1, "-") && !first){ - xPos -= Integer.parseInt(s2); + position -= Integer.parseInt(s2); }else if(Objects.equals(s1, "*") && !first){ - xPos *= Integer.parseInt(s2); + position *= Integer.parseInt(s2); }else if(Objects.equals(s1, "/") && !first){ - xPos /= Integer.parseInt(s2); + position /= Integer.parseInt(s2); } } if((Config.isDebug()) && Config.getCounter() < 2) { - LOGGER.info("Selected speed type: "+SpeedTypes.getName(Config.getSpeedType()).getString()+"\n"+ - Arrays.toString(passerPose.toArray())+"\n\n"+ - xPos+"\n\n"+ - (type==0?Config.getXPosition():Config.getYPosition())); + String speedDisplayType = SpeedTypes.getName(Config.getSpeedType()).getString(); + String splitRawSpeedPosition = Arrays.toString(passerPose.toArray()); + String rawSpeedPosition = isXPosition ? Config.getXPosition() : Config.getYPosition(); + LOGGER.info("Selected speed type: {}\n{}\n\n{}\n\n{}", speedDisplayType, splitRawSpeedPosition, position, rawSpeedPosition); Config.addCounter(); } - return xPos; + return position; } - private static void defaultValues(GuiGraphics event, int type, ArrayList passerPose) { - if(type == 0){ + private static void defaultValues(GuiGraphics event, boolean isXPosition, ArrayList passerPose) { + if(isXPosition) + { passerPose.add(String.valueOf(event.guiWidth())); passerPose.add("-"); passerPose.add("3"); - }else if(type == 1){ + } + else + { passerPose.add(String.valueOf(event.guiHeight())); passerPose.add("-"); passerPose.add("3"); diff --git a/common/src/main/java/me/zacharias/speedometer/Config.java b/common/src/main/java/me/zacharias/speedometer/Config.java index ff31802..898102c 100644 --- a/common/src/main/java/me/zacharias/speedometer/Config.java +++ b/common/src/main/java/me/zacharias/speedometer/Config.java @@ -4,6 +4,7 @@ import dev.architectury.platform.Platform; import org.json.JSONObject; import java.awt.*; +import java.awt.image.BufferedImage; import java.io.*; @@ -14,6 +15,8 @@ public class Config { public static final float configVersion = 3f; private static int counter = 0; private static String configPath; + private static BufferedImage speedometer; + private static boolean disableVisualSpeedometer = false; public static void initialize(){ if(config != null) throw new RuntimeException("Already Initialized"); @@ -128,7 +131,8 @@ public class Config { } counter=0; } - + + //region Config Getters public static SpeedTypes getSpeedType(){ if(config.has("speed")){ return config.getEnum(SpeedTypes.class, "speed"); @@ -169,7 +173,9 @@ public class Config { public static boolean getVisualSpeedometer(){ if(config.has("visualSpeedometer")){ return config.getBoolean("visualSpeedometer"); - }else { + } + else + { return false; } } @@ -212,7 +218,23 @@ public class Config { return true; } } - + + public static String getConfigPath() + { + return configPath; + } + + public static BufferedImage getSpeedometer() { + return speedometer; + } + + public static boolean isDisableVisualSpeedometer() { + return disableVisualSpeedometer; + } + + //endregion + + //region Config Setters public static void setColor(int r, int g, int b){ config.put("color", new JSONObject() .put("r", r) @@ -253,8 +275,12 @@ public class Config { config.put("showSpeedType", showSpeedType); } - public static String getConfigPath() - { - return configPath; + public static void setSpeedometer(BufferedImage speedometer) { + Config.speedometer = speedometer; } + + public static void setDisableVisualSpeedometer (boolean disableVisualSpeedometer){ + Config.disableVisualSpeedometer = disableVisualSpeedometer; + } + //endregion } diff --git a/common/src/main/java/me/zacharias/speedometer/ConfigMenu.java b/common/src/main/java/me/zacharias/speedometer/ConfigMenu.java index 4a202e6..e485a90 100644 --- a/common/src/main/java/me/zacharias/speedometer/ConfigMenu.java +++ b/common/src/main/java/me/zacharias/speedometer/ConfigMenu.java @@ -1,9 +1,6 @@ package me.zacharias.speedometer; -import me.shedaniel.clothconfig2.api.ConfigBuilder; -import me.shedaniel.clothconfig2.api.ConfigCategory; -import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; -import net.minecraft.ChatFormatting; +import me.shedaniel.clothconfig2.api.*; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; @@ -41,6 +38,7 @@ public class ConfigMenu { category.addEntry(entryBuilder.startBooleanToggle(Component.translatable("speedometer.config.visualSpeedometer"), me.zacharias.speedometer.Config.getVisualSpeedometer()) .setSaveConsumer(me.zacharias.speedometer.Config::setVisualSpeedometer) .setYesNoTextSupplier((visualSpeedometer -> Component.translatable("speedometer.visualSpeedometer."+visualSpeedometer))) + .setRequirement(Requirement.isFalse(Config::isDisableVisualSpeedometer)) .build() ); diff --git a/common/src/main/java/me/zacharias/speedometer/ImageHandler.java b/common/src/main/java/me/zacharias/speedometer/ImageHandler.java index 9158389..e06f9ef 100644 --- a/common/src/main/java/me/zacharias/speedometer/ImageHandler.java +++ b/common/src/main/java/me/zacharias/speedometer/ImageHandler.java @@ -1,6 +1,7 @@ package me.zacharias.speedometer; import java.awt.*; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; public class ImageHandler { @@ -23,4 +24,25 @@ public class ImageHandler { } return out; } + + public static BufferedImage rotate(BufferedImage img, double angle) { + double rads = Math.toRadians(angle); + int w = img.getWidth(); + int h = img.getHeight(); + + BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = rotated.createGraphics(); + AffineTransform at = new AffineTransform(); + at.translate(w / 2d, h / 2d); + + int x = w / 2; + int y = h / 2; + + at.rotate(rads, x, y); + g2d.setTransform(at); + g2d.drawImage(img, 0, h, null); + g2d.dispose(); + + return rotated; + } } \ No newline at end of file diff --git a/common/src/main/java/me/zacharias/speedometer/MeterImages.java b/common/src/main/java/me/zacharias/speedometer/MeterImages.java deleted file mode 100644 index 521e8d1..0000000 --- a/common/src/main/java/me/zacharias/speedometer/MeterImages.java +++ /dev/null @@ -1,60 +0,0 @@ -package me.zacharias.speedometer; - -import net.minecraft.network.chat.Component; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.Objects; - -import static me.zacharias.speedometer.Speedometer.LOGGER; - -public enum MeterImages { - LARGE(Component.translatable("speedometer.meter.large"), "/assets/speedometer/meter/meter-115.png", 115), - SMALL(Component.translatable("speedometer.meter.small"), "/assets/speedometer/meter/meter-19.png", 19), - MEDIUM(Component.translatable("speedometer.meter.small"), "/assets/speedometer/meter/meter-67.png", 67) - - ; - - private final Component name; - private final String meterIcon; - private BufferedImage image; - private final int size; - - MeterImages(Component name, String meterIcon, int size) { - this.name = name; - this.size = size; - this.meterIcon = meterIcon; - } - - public boolean initiate(){ - if(image != null){ - LOGGER.warn("Already loaded \""+meterIcon+"\""); - } - try{ - LOGGER.info("Loading speedometer \""+meterIcon+"\""); - image = ImageIO.read(Objects.requireNonNull(Speedometer.class.getResourceAsStream(meterIcon))); - LOGGER.info("Loaded speedometer \""+meterIcon+"\""); - return true; - } catch (IOException e) { - image = new BufferedImage(0,0, BufferedImage.TYPE_INT_ARGB); - LOGGER.warn("Failed to load speedometer \""+meterIcon+"\""); - return false; - } - } - - public BufferedImage getImage() { - if(image == null){ - LOGGER.warn("\""+meterIcon+"\" has not ben loaded yet!"); - } - return image; - } - - public int getSize() { - return size; - } - - public Component getName() { - return name; - } -} diff --git a/common/src/main/java/me/zacharias/speedometer/MissingPropertyException.java b/common/src/main/java/me/zacharias/speedometer/MissingPropertyException.java new file mode 100644 index 0000000..225ab79 --- /dev/null +++ b/common/src/main/java/me/zacharias/speedometer/MissingPropertyException.java @@ -0,0 +1,7 @@ +package me.zacharias.speedometer; + +public class MissingPropertyException extends Exception { + public MissingPropertyException(String field) { + super("Missing Speedometer config field: " + field); + } +} diff --git a/common/src/main/java/me/zacharias/speedometer/Speedometer.java b/common/src/main/java/me/zacharias/speedometer/Speedometer.java index 489d7c5..729b2b2 100644 --- a/common/src/main/java/me/zacharias/speedometer/Speedometer.java +++ b/common/src/main/java/me/zacharias/speedometer/Speedometer.java @@ -3,17 +3,25 @@ package me.zacharias.speedometer; import dev.architectury.platform.Platform; import dev.architectury.utils.Env; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.json.JSONObject; +import java.io.BufferedReader; import java.io.File; +import java.io.InputStream; import java.util.Objects; +import java.util.Optional; public class Speedometer { public static final String MOD_ID = "speedometer"; public static final Logger LOGGER = LogManager.getLogger(MOD_ID); public static final String VERSION = Platform.getMod(MOD_ID).getVersion(); + public static SpeedometerIcon ICON = null; public static void init() { LOGGER.info("Loading speedometer by Allen"); @@ -26,20 +34,50 @@ public class Speedometer if (f.getName().startsWith("speedometer")) { String fileName = "speedometer-" + VERSION + ".jar.disable"; if(f.renameTo(new File(f.getParent(), fileName))){ - LOGGER.warn("Successfully in renaming the mod jar file to "+fileName); - LOGGER.warn("You should remove the file from "+Platform.getModsFolder().toString()); + LOGGER.warn("Successfully in renaming the mod jar file to {}", fileName); + LOGGER.warn("You should remove the file from {}", Platform.getModsFolder().toString()); }else{ LOGGER.warn("Unsuccessful in renaming mod jar"); - LOGGER.warn("You should remove the mod from "+Platform.getModsFolder().toString()+" to no longer receive this message"); + LOGGER.warn("You should remove the mod from {} to no longer receive this message", Platform.getModsFolder().toString()); } } } }catch (NullPointerException e){ - LOGGER.warn("Can't disable the mod"); + LOGGER.warn("Can't disable the mod. Please delete the file!"); } return; } Client.init(); } + + public static void loadSpeedometers(ResourceManager resourceManager) + { + Optional< Resource > resource = resourceManager.getResource(ResourceLocation.fromNamespaceAndPath(MOD_ID, "models/speedometer.json")); + + if(resource.isEmpty()) + { + Config.setDisableVisualSpeedometer(true); + LOGGER.error("Failed to load speedometer config"); + return; + } + + try { + BufferedReader stream = resource.get().openAsReader(); + String tmp; + StringBuilder builder = new StringBuilder(); + while ((tmp = stream.readLine()) != null) { + builder.append(tmp); + } + JSONObject data = new JSONObject(builder.toString()); + ICON = new SpeedometerIcon(data, resourceManager); + } + catch (Exception e){ + Config.setDisableVisualSpeedometer(true); + LOGGER.error("Failed to load speedometer config", e); + return; + } + + LOGGER.info("Successfully loaded speedometer config from {}", resource.get().source().packId()); + } } diff --git a/common/src/main/java/me/zacharias/speedometer/SpeedometerIcon.java b/common/src/main/java/me/zacharias/speedometer/SpeedometerIcon.java new file mode 100644 index 0000000..f6cc1a2 --- /dev/null +++ b/common/src/main/java/me/zacharias/speedometer/SpeedometerIcon.java @@ -0,0 +1,176 @@ +package me.zacharias.speedometer; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import org.joml.Vector2i; +import org.json.JSONException; +import org.json.JSONObject; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import java.util.Optional; + +import static me.zacharias.speedometer.Speedometer.MOD_ID; + +public class SpeedometerIcon { + private BufferedImage speedometerIcon; + private Pointer pointer; + private int start; + private int end; + private float scale; + private int max; + private boolean overflow; + + public SpeedometerIcon(JSONObject config, ResourceManager resourceManager) throws MissingPropertyException, IOException, JSONException + { + if(!config.has("background")) throw new MissingPropertyException("background"); + + String background = config.getString("background"); + + if(background.contains(":")) + { + background = background.replaceFirst(":", ":textures/"); + } + else + { + background = "textures/"+background; + } + + Optional speedometerIcon = resourceManager.getResource(ResourceLocation.read(background).getOrThrow(s -> new MissingPropertyException("background"))); + if(speedometerIcon.isEmpty()) throw new MissingPropertyException("background"); + + InputStream stream = speedometerIcon.get().open(); + this.speedometerIcon = ImageIO.read(stream); + stream.close(); + + if(!config.has("start")) throw new MissingPropertyException("start"); + this.start = config.getInt("start"); + + if(!config.has("end")) throw new MissingPropertyException("end"); + this.end = config.getInt("end"); + + if(!config.has("scale")) throw new MissingPropertyException("scale"); + this.scale = config.getFloat("scale"); + + if(!config.has("pointer")) throw new MissingPropertyException("pointer"); + this.pointer = new Pointer(config.getJSONObject("pointer"), resourceManager, new Vector2i(this.speedometerIcon.getWidth(), this.speedometerIcon.getHeight())); + + if(!config.has("maxSpeed")) throw new MissingPropertyException("maxSpeed"); + this.max = config.getInt("maxSpeed"); + + if(!config.has("overflow")) throw new MissingPropertyException("overflow"); + this.overflow = config.getBoolean("overflow"); + } + + public BufferedImage getSpeedometerIcon(double speed) + { + Graphics2D graphics = ImageHandler.clone(speedometerIcon).createGraphics(); + pointer.draw(graphics, start, end, max, overflow, Math.pow(speed, scale)); + return speedometerIcon; + } +} + +class Pointer +{ + private BufferedImage image; + private Vector2i start; + private int length; + private boolean g = false; + + public Pointer(JSONObject pointer, ResourceManager resourceManager, Vector2i size) throws MissingPropertyException, IOException, JSONException + { + if(!pointer.has("start")) throw new MissingPropertyException("pointer/start"); + if(pointer.get("start") instanceof JSONObject jsonObject) + { + if(!jsonObject.has("x")) throw new MissingPropertyException("pointer/start/x"); + if(!jsonObject.has("y")) throw new MissingPropertyException("pointer/start/y"); + start = new Vector2i(jsonObject.getInt("x"), jsonObject.getInt("y")); + } + else if(pointer.get("start") instanceof String str) + { + if(str.isEmpty()) throw new MissingPropertyException("pointer/start"); + + if(str.matches("^\\([0-9]+,( )?[0-9]\\)+$")) + { + String[] split = str.split(","); + start = new Vector2i(Integer.parseInt(split[0].substring(1)), Integer.parseInt(split[1].substring(0, split[1].length()-1))); + } + else if(str.equalsIgnoreCase("center")) + { + start = new Vector2i(size.x / 2, size.y / 2); + } + else throw new MissingPropertyException("pointer/start"); + + } + + if(pointer.has("image")) + { + String imageResourceLocation = pointer.getString("image"); + + if(imageResourceLocation.contains(":")) + { + imageResourceLocation = imageResourceLocation.replaceFirst(":", ":textures/"); + } + else + { + imageResourceLocation = "textures/"+imageResourceLocation; + } + + Optional image = resourceManager.getResource(ResourceLocation.read(imageResourceLocation).getOrThrow(s -> new MissingPropertyException("pointer/image"))); + if(image.isEmpty()) throw new MissingPropertyException("pointer/image"); + + InputStream stream = image.get().open(); + this.image = ImageIO.read(stream); + stream.close(); + } + else if(pointer.has("length")) + { + if(pointer.get("length") instanceof String str) + { + length = switch (str.toLowerCase()) + { + case "half" -> size.x / 2; + case "full" -> size.x; + default -> throw new MissingPropertyException("pointer/length"); + }; + } + else if(pointer.get("length") instanceof Integer integer) + { + length = integer; + } + else throw new MissingPropertyException("pointer/length"); + } + else throw new MissingPropertyException("pointer/image or pointer/length"); + } + + public void draw(Graphics2D g2d, int start, int end, int max, boolean overflow, double speed) + { + double angle = (speed * end)+start; + if(angle > max && overflow) angle = end; + + if(Objects.nonNull(image)) + { + BufferedImage image = ImageHandler.rotate(this.image, angle); + if(angle>start+10 && !g) { + try { + File output = new File("./dev.png"); + ImageIO.write(image, "png", output); + } catch (IOException e) { + throw new RuntimeException(e); + } + g = true; + } + g2d.drawImage(image, this.start.x, this.start.y, null); + } + else + { + + } + } +} diff --git a/common/src/main/resources/assets/speedometer/meter/meter-19.png b/common/src/main/resources/assets/speedometer/meter/meter-19.png deleted file mode 100644 index d2e7d4f..0000000 Binary files a/common/src/main/resources/assets/speedometer/meter/meter-19.png and /dev/null differ diff --git a/common/src/main/resources/assets/speedometer/meter/meter-67.png b/common/src/main/resources/assets/speedometer/meter/meter-67.png deleted file mode 100644 index 24fd3c8..0000000 Binary files a/common/src/main/resources/assets/speedometer/meter/meter-67.png and /dev/null differ diff --git a/common/src/main/resources/assets/speedometer/models/speedometer.json b/common/src/main/resources/assets/speedometer/models/speedometer.json new file mode 100644 index 0000000..c6f3287 --- /dev/null +++ b/common/src/main/resources/assets/speedometer/models/speedometer.json @@ -0,0 +1,13 @@ +{ + "background": "speedometer:meter/speedometer.png", + "start": 45, + "end": 215, + "maxSpeed": 120, + "overflow": true, + "pointer": { + "image": "speedometer:meter/pointer.png", + "start": "(0,0)" + }, + "scale": 1, + "name": "Test" +} \ No newline at end of file diff --git a/common/src/main/resources/assets/speedometer/meter/meter-115.png b/common/src/main/resources/assets/speedometer/textures/meter/speedometer.png similarity index 100% rename from common/src/main/resources/assets/speedometer/meter/meter-115.png rename to common/src/main/resources/assets/speedometer/textures/meter/speedometer.png diff --git a/fabric/src/main/resources/pack.mcmeta b/common/src/main/resources/pack.mcmeta similarity index 72% rename from fabric/src/main/resources/pack.mcmeta rename to common/src/main/resources/pack.mcmeta index 6493c61..b51a819 100644 --- a/fabric/src/main/resources/pack.mcmeta +++ b/common/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 15, + "pack_format": 34, "description": "speedometer resources" } } \ No newline at end of file diff --git a/fabric/src/main/java/me/zacharias/speedometer/fabric/SpeedometerFabric.java b/fabric/src/main/java/me/zacharias/speedometer/fabric/SpeedometerFabric.java index e7bb368..2619936 100644 --- a/fabric/src/main/java/me/zacharias/speedometer/fabric/SpeedometerFabric.java +++ b/fabric/src/main/java/me/zacharias/speedometer/fabric/SpeedometerFabric.java @@ -2,11 +2,17 @@ package me.zacharias.speedometer.fabric; import me.zacharias.speedometer.Speedometer; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; import net.kyori.adventure.text.minimessage.MiniMessage; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; +import net.minecraft.server.packs.resources.ResourceManager; +import org.intellij.lang.annotations.Identifier; import java.awt.*; @@ -14,5 +20,16 @@ public class SpeedometerFabric implements ModInitializer { @Override public void onInitialize() { Speedometer.init(); + ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() { + @Override + public void onResourceManagerReload(ResourceManager resourceManager) { + Speedometer.loadSpeedometers(resourceManager); + } + + @Override + public ResourceLocation getFabricId() { + return ResourceLocation.fromNamespaceAndPath("speedometer", "Loading the visual speedometers"); + } + }); } } \ No newline at end of file diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 4f058f0..d12bdd9 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -3,7 +3,7 @@ "id": "speedometer", "version": "${version}", - "name": "speedometer", + "name": "Speedometer", "description": "just displaying your speed", "authors": ["Zacharias"], "contact": { @@ -15,12 +15,15 @@ "icon": "icon.png", "environment": "client", - "entrypoints": { + "entrypoint": { "main": ["me.zacharias.speedometer.fabric.SpeedometerFabric"] }, "depends": { "fabricloader": ">=0.15.11", "minecraft": ">=1.21", "architectury": ">=13.0.1" + }, + "suggests": { + "cloth-config1": ">=15.0.127" } } diff --git a/gradle.properties b/gradle.properties index 90e13e8..4843bb7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,14 +3,14 @@ org.gradle.jvmargs=-Xmx8G minecraft_version=1.21 archives_base_name=speedometer -mod_version=6.0.1 +mod_version=6.2 maven_group=me.zacharias -architectury_version=13.0.1 +architectury_version=13.0.4 fabric_loader_version=0.15.11 -fabric_api_version=0.100.3+1.21 +fabric_api_version=0.100.6+1.21 -neoforge_version = 21.0.21-beta +neoforge_version = 21.0.78-beta cloth_config_version = 15.0.127 \ No newline at end of file diff --git a/neoforge/src/main/java/me/zacharias/speedometer/forge/SpeedometerNeoForge.java b/neoforge/src/main/java/me/zacharias/speedometer/forge/SpeedometerNeoForge.java index 4a470d8..cdabfad 100644 --- a/neoforge/src/main/java/me/zacharias/speedometer/forge/SpeedometerNeoForge.java +++ b/neoforge/src/main/java/me/zacharias/speedometer/forge/SpeedometerNeoForge.java @@ -1,7 +1,21 @@ package me.zacharias.speedometer.forge; +import com.mojang.datafixers.util.Unit; import me.zacharias.speedometer.Speedometer; +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.client.ClientNeoForgeMod; +import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; +import net.neoforged.neoforge.common.NeoForge; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; @Mod(Speedometer.MOD_ID) public class SpeedometerNeoForge { @@ -9,4 +23,23 @@ public class SpeedometerNeoForge { // Submit our event bus to let architectury register our content on the right time Speedometer.init(); } +} + +@EventBusSubscriber(modid = Speedometer.MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +class stuff +{ + @SubscribeEvent + private static void onResourceReload(RegisterClientReloadListenersEvent event) { + event.registerReloadListener(new SimplePreparableReloadListener() { + @Override + protected Unit prepare(ResourceManager arg, ProfilerFiller arg2) { + return Unit.INSTANCE; + } + + @Override + protected void apply(Unit object, ResourceManager resourceManager, ProfilerFiller arg2) { + Speedometer.loadSpeedometers(resourceManager); + } + }); + } } \ No newline at end of file diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index 04d5055..eb8a06f 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -3,35 +3,48 @@ # The overall format is standard TOML format, v0.5.0. # Note that there are a couple of TOML lists in this file. # Find more information on toml format here: https://github.com/toml-lang/toml + # The name of the mod loader type to load - for regular FML @Mod mods it should be javafml modLoader="javafml" #mandatory + # A version range to match for said mod loader - for regular FML @Mod it will be the forge version loaderVersion="[2,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. + # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. license="All Rights Reserved" + # A URL to refer people to when problems occur with this mod -issueTrackerURL="https://github.com/zaze06/speedometer/issues" +issueTrackerURL="https://github.com/zaze06/Speedometer/issues" + # A list of mods - how many allowed here is determined by the individual mod loader [[mods]] #mandatory + # The modid of the mod modId="speedometer" #mandatory + # The version number of the mod - there's a few well known ${} variables useable here or just hardcode it # ${version} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata # see the associated build.gradle script for how to populate this completely automatically during a build version="${version}" #mandatory + # A display name for the mod -displayName="speedometer" #mandatory +displayName="Speedometer" #mandatory + # A URL to query for updates for this mod. See the JSON update specification -updateJSONURL="https://raw.githubusercontent.com/zaze06/Speedometer/master/forge/src/main/resources/updateChecker.json" #optional +updateJSONURL="https://raw.githubusercontent.com/zaze06/Speedometer/master/neoforge/src/main/resources/updateChecker.json" #optional + # A URL for the "homepage" for this mod, displayed in the mod UI displayURL="https://modrinth.com/mod/speedometer" #optional + # A file name (in the root of the mod JAR) containing a logo for display logoFile="icon.png" #optional + # A text field displayed in the mod UI #credits="Thanks for this example mod goes to Java" #optional # A text field displayed in the mod UI authors="Zacharias" #optional + # Display Test controls the display for your mod in the server connection screen # MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. # IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. @@ -42,8 +55,9 @@ displayTest="IGNORE_ALL_VERSION" # MATCH_VERSION is the default if nothing is sp # The description text for the mod (multi line!) (#mandatory) description=''' -just displaying your speed +Just displaying your speed ''' + # A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. [[dependencies.speedometer]] #optional # the modid of the dependency @@ -51,16 +65,14 @@ just displaying your speed # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[2,)" #mandatory + versionRange="[21.0.78-beta,)" #mandatory # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory ordering="NONE" # Side this dependency is applied on - BOTH, CLIENT or SERVER side="CLIENT" -# Here's another dependency [[dependencies.speedometer]] modId="minecraft" mandatory=true - # This version range declares a minimum of the current minecraft version up to but not including the next major version versionRange="[1.21,1.22)" ordering="NONE" side="BOTH" diff --git a/neoforge/src/main/resources/pack.mcmeta b/neoforge/src/main/resources/pack.mcmeta deleted file mode 100644 index a66d0b8..0000000 --- a/neoforge/src/main/resources/pack.mcmeta +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pack": { - "pack_format": 15, - "description": "speedometer resources", - "forge:server_data_pack_format": 12 - } -} \ No newline at end of file diff --git a/neoforge/src/main/resources/updateChecker.json b/neoforge/src/main/resources/updateChecker.json index 15a3e9f..fd4d84b 100644 --- a/neoforge/src/main/resources/updateChecker.json +++ b/neoforge/src/main/resources/updateChecker.json @@ -3,7 +3,8 @@ "1.21": { "6.0": "Lost support for Forge and gain NeoForge support", "6.0.1": "Small bug fix in Parser", - "6.1": "Small bug fix in Parser" + "6.1": "Small bug fix in Parser", + "6.2": "Making speedometer and pointer resource pack based" }, "promos": { "1.21-latest": "6.1", diff --git a/schemas/speedometer_config_schema.json b/schemas/speedometer_config_schema.json new file mode 100644 index 0000000..160f917 --- /dev/null +++ b/schemas/speedometer_config_schema.json @@ -0,0 +1,110 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "A name for your speedometer" + }, + "background": { + "type": "string", + "description": "Path to the background texture file (e.g., 'meter/speedometer.png')" + }, + "start": { + "type": "integer", + "description": "Start value for the speedometer scale in degrees" + }, + "end": { + "type": "integer", + "description": "End value for the speedometer scale in degrees" + }, + "maxSpeed": { + "type": "number", + "description": "The max speed, as in the end point angle in Blocks/s" + }, + "overflow": { + "type": "boolean", + "description": "Dose the pointer overflow after maxSpeed" + }, + "pointer": { + "type": "object", + "properties": { + "color": { + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$", + "description": "Color code for the pointer (e.g., '#8a0000')" + }, + "start": { + "oneOf": [ + { + "type": "string", + "enum": ["center", "left", "right"], + "description": "Starting position of the pointer" + }, + { + "type": "string", + "pattern": "^\\([0-9]+,( )?[0-9]\\)+$", + "description": "Starting position of the pointer" + }, + { + "type": "object", + "properties": { + "x": { + "type": "number", + "description": "X position" + }, + "y": { + "type": "number", + "description": "Y position" + } + }, + "required": ["x", "y"], + "description": "Starting position of the pointer", + "additionalProperties": false + } + ] + }, + "length": { + "oneOf": [ + { + "type": "string", + "enum": ["half", "full"], + "description": "Length of the pointer relative to the scale" + }, + { + "type": "number", + "description": "Length of the pointer relative to the scale" + } + ] + }, + "image":{ + "type": "string", + "description": "Image location for a pointer" + } + }, + "required": ["start"], + "anyOf": [ + { + "required": [ + "image" + ] + }, + { + "required": [ + "color", + "length" + ] + } + ], + "additionalProperties": false + }, + "scale": { + "type": "number", + "minimum": 0.1, + "maximum": 2.0, + "description": "Scale factor for the speedometer" + } + }, + "required": ["background", "start", "end", "pointer", "scale", "maxSpeed", "overflow"], + "additionalProperties": false +}