From 8e3e9cb6a90ad1310a197284b688ef9670aaff53 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:41:33 +0300 Subject: [PATCH 01/10] Remove the old build scripts. --- build.gradle | 58 ------ settings.gradle | 18 -- .../net/cardinalboats/CardinalBoatsInit.java | 15 -- .../java/net/cardinalboats/ManualSnap.java | 46 ----- .../java/net/cardinalboats/TurnPriming.java | 187 ------------------ src/main/java/net/cardinalboats/Util.java | 62 ------ .../net/cardinalboats/config/ModConfig.java | 42 ---- .../config/ModMenuIntegration.java | 12 -- .../mixin/BoatPlacementSnap.java | 23 --- .../net/cardinalboats/mixin/ChatMoveLie.java | 28 --- .../mixin/ChatMoveStartLying.java | 33 ---- .../resources/assets/cardinalboats/icon.png | Bin 58126 -> 0 bytes .../assets/cardinalboats/lang/en_us.json | 43 ---- .../resources/cardinalboats.accesswidener | 3 - src/main/resources/cardinalboats.mixins.json | 16 -- src/main/resources/fabric.mod.json | 31 --- 16 files changed, 617 deletions(-) delete mode 100644 build.gradle delete mode 100644 settings.gradle delete mode 100644 src/main/java/net/cardinalboats/CardinalBoatsInit.java delete mode 100644 src/main/java/net/cardinalboats/ManualSnap.java delete mode 100644 src/main/java/net/cardinalboats/TurnPriming.java delete mode 100644 src/main/java/net/cardinalboats/Util.java delete mode 100644 src/main/java/net/cardinalboats/config/ModConfig.java delete mode 100644 src/main/java/net/cardinalboats/config/ModMenuIntegration.java delete mode 100644 src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java delete mode 100644 src/main/java/net/cardinalboats/mixin/ChatMoveLie.java delete mode 100644 src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java delete mode 100644 src/main/resources/assets/cardinalboats/icon.png delete mode 100644 src/main/resources/assets/cardinalboats/lang/en_us.json delete mode 100644 src/main/resources/cardinalboats.accesswidener delete mode 100644 src/main/resources/cardinalboats.mixins.json delete mode 100644 src/main/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 421482c..0000000 --- a/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -plugins { - id 'fabric-loom' version '1.10-SNAPSHOT' - id 'maven-publish' -} - -sourceCompatibility = JavaVersion.VERSION_21 -targetCompatibility = JavaVersion.VERSION_21 - -archivesBaseName = project.archives_base_name -version = project.mod_version -group = project.maven_group - -repositories { - maven { url "https://maven.shedaniel.me/" } - maven { url "https://maven.terraformersmc.com/releases/" } - maven { url 'https://jitpack.io' } -} - -dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" - modImplementation "me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config_version}" - modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -tasks.withType(JavaCompile).configureEach { - // Minecraft 1.21 upwards uses Java 21. - it.options.release = 21 -} - -java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - // withSourcesJar() -} - -jar { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}"} - } -} - -loom { - accessWidenerPath.set(file("src/main/resources/cardinalboats.accesswidener")) -} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index c4bdcd3..0000000 --- a/settings.gradle +++ /dev/null @@ -1,18 +0,0 @@ -pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - mavenCentral() - gradlePluginPortal() - } - plugins { - id 'org.jetbrains.kotlin.jvm' version '2.1.0' - } -} -plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' -} - -rootProject.name = "Cardinal-Ice-Boats" diff --git a/src/main/java/net/cardinalboats/CardinalBoatsInit.java b/src/main/java/net/cardinalboats/CardinalBoatsInit.java deleted file mode 100644 index 0cd27f8..0000000 --- a/src/main/java/net/cardinalboats/CardinalBoatsInit.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.cardinalboats; - -import net.cardinalboats.config.ModConfig; -import net.fabricmc.api.ClientModInitializer; - -public class CardinalBoatsInit implements ClientModInitializer { - public static boolean LieAboutMovingForward = false; - - @Override - public void onInitializeClient() { - TurnPriming.init(); - ManualSnap.init(); - ModConfig.init(); - } -} diff --git a/src/main/java/net/cardinalboats/ManualSnap.java b/src/main/java/net/cardinalboats/ManualSnap.java deleted file mode 100644 index ea7f887..0000000 --- a/src/main/java/net/cardinalboats/ManualSnap.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.cardinalboats; - -import net.cardinalboats.config.ModConfig; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; -import net.minecraft.entity.vehicle.AbstractBoatEntity; - -public class ManualSnap { - public static final KeyBinding manualSnapKey = new KeyBinding( - "key.cardinalboats.snapManual", - InputUtil.Type.KEYSYM, - InputUtil.GLFW_KEY_UP, - "category.cardinalboats.key_category_title" - ); - - public static final KeyBinding snap180 = new KeyBinding( - "key.cardinalboats.snap180", - InputUtil.Type.KEYSYM, - InputUtil.GLFW_KEY_DOWN, - "category.cardinalboats.key_category_title" - ); - - // Run by fabric initializer - public static void init() { - KeyBindingHelper.registerKeyBinding(manualSnapKey); - KeyBindingHelper.registerKeyBinding(snap180); - - ClientTickEvents.END_CLIENT_TICK.register(ManualSnap::tick); - } - - public static void tick(MinecraftClient minecraft) { - if (minecraft.player != null && minecraft.player.hasVehicle() && minecraft.player.getVehicle() instanceof AbstractBoatEntity boat && Util.isIce(boat.getSteppingBlockState())) { - while (manualSnapKey.wasPressed()) { - Util.rotateBoat(boat, Util.roundYRot(boat.getYaw(), ModConfig.getInstance().eightWaySnapKey? 45:90), true); - } - while (snap180.wasPressed()) { - Util.rotateBoat(boat, boat.getYaw() % 360 - 180, ModConfig.getInstance().maintainVelocityOnTurns); - } - } else { - while (manualSnapKey.wasPressed() || snap180.wasPressed()) {} - } - } -} diff --git a/src/main/java/net/cardinalboats/TurnPriming.java b/src/main/java/net/cardinalboats/TurnPriming.java deleted file mode 100644 index 5b9ebd3..0000000 --- a/src/main/java/net/cardinalboats/TurnPriming.java +++ /dev/null @@ -1,187 +0,0 @@ -package net.cardinalboats; - -import net.cardinalboats.config.ModConfig; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.minecraft.block.AirBlock; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.vehicle.AbstractBoatEntity; -import net.minecraft.text.Text; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -import static net.minecraft.util.math.Direction.NORTH; -import static net.minecraft.util.math.Direction.SOUTH; -import static net.minecraft.util.math.Direction.EAST; -import static net.minecraft.util.math.Direction.WEST; - -public class TurnPriming { - public static final KeyBinding lQueueKey = new KeyBinding( - "key.cardinalboats.prime_left", - InputUtil.Type.KEYSYM, - InputUtil.GLFW_KEY_LEFT, - "category.cardinalboats.key_category_title" - ); - public static final KeyBinding rQueueKey = new KeyBinding( - "key.cardinalboats.prime_right", - InputUtil.Type.KEYSYM, - InputUtil.GLFW_KEY_RIGHT, - "category.cardinalboats.key_category_title" - ); - - public static final KeyBinding smartCenterKey = new KeyBinding( - "key.cardinalboats.smartCenter", - InputUtil.Type.KEYSYM, - InputUtil.GLFW_KEY_BACKSLASH, - "category.cardinalboats.key_category_title" - ); - - // Run by fabric initializer - public static void init() { - KeyBindingHelper.registerKeyBinding(lQueueKey); - KeyBindingHelper.registerKeyBinding(rQueueKey); - KeyBindingHelper.registerKeyBinding(smartCenterKey); - - ClientTickEvents.END_CLIENT_TICK.register(TurnPriming::tick); - } - - private static boolean lTurnPrimed = false; - private static boolean rTurnPrimed = false; - - public static void tick(MinecraftClient minecraft) { - if (minecraft.player != null && minecraft.player.hasVehicle() && minecraft.player.getVehicle() instanceof AbstractBoatEntity boat) { - if (Util.isIce(boat.getSteppingBlockState())) { - ClientPlayerEntity player = minecraft.player; - - while (lQueueKey.wasPressed()) { - Util.ClientChatLog(player, Text.translatable("info.cardinalboats.left_turn_queue").getString()); - lTurnPrimed = true; - rTurnPrimed = false; - } - while (rQueueKey.wasPressed()) { - Util.ClientChatLog(player, Text.translatable("info.cardinalboats.right_turn_queue").getString()); - rTurnPrimed = true; - lTurnPrimed = false; - } - - if (ModConfig.getInstance().alwaysSmartCenter && boat.getYaw() % 90 == 0) { smartCenter(boat); } - while (smartCenterKey.wasPressed()) { smartCenter(boat); } - - if (lTurnPrimed && shouldTurn(boat, minecraft.world, true)) { - Util.rotateBoat(boat, Util.roundYRot(boat.getYaw() - 90, 90), ModConfig.getInstance().maintainVelocityOnTurns); - lTurnPrimed = false; - Util.ClientChatLog(player, Text.translatable("info.cardinalboats.left_turn_complete").getString()); - if (ModConfig.getInstance().smartCenterPrimedTurn) smartCenter(boat); - } else if (rTurnPrimed && shouldTurn(boat, minecraft.world, false)) { - Util.rotateBoat(boat, Util.roundYRot(boat.getYaw() + 90, 90), ModConfig.getInstance().maintainVelocityOnTurns); - rTurnPrimed = false; - Util.ClientChatLog(player, Text.translatable("info.cardinalboats.right_turn_complete").getString()); - if (ModConfig.getInstance().smartCenterPrimedTurn) smartCenter(boat); - } - } else { - while (lQueueKey.wasPressed() || rQueueKey.wasPressed() || smartCenterKey.wasPressed()) {} - } - } else { - // if we aren't in the boat anymore, we don't care - if (lTurnPrimed || rTurnPrimed) { - Util.ClientChatLog(minecraft.player, Text.translatable("info.cardinalboats.cancel").getString()); - } - lTurnPrimed = false; - rTurnPrimed = false; - - // not in a boat, don't care about any presses these buttons get right now - while (lQueueKey.wasPressed() || rQueueKey.wasPressed() || smartCenterKey.wasPressed()) {} - } - } - - private static final Map toScanMapLeft = new HashMap<>() {{ - put(SOUTH, new int[][]{{ 3, 0}, { 3,-1}, { 3,-2}}); - put(NORTH, new int[][]{{-3, 0}, {-3, 1}, {-3, 2}}); - put(EAST, new int[][]{{ 0,-3}, {-1,-3}, {-2,-3}}); - put(WEST, new int[][]{{ 0, 3}, { 1, 3}, { 2, 3}}); - }}; - private static final Map toScanMapRight = new HashMap<>() {{ - put(SOUTH, new int[][]{{-3, 0}, {-3,-1}, {-3,-2}}); - put(NORTH, new int[][]{{ 3, 0}, { 3, 1}, { 3, 2}}); - put(EAST, new int[][]{{ 0, 3}, {-1, 3}, {-2, 3}}); - put(WEST, new int[][]{{ 0,-3}, { 1,-3}, { 2,-3}}); - }}; - private static final Map snapBlockMap = new HashMap<>() {{ - put(SOUTH, new int[][]{{ 0, 0}, { 0,-1}, { 0,-2}}); - put(NORTH, new int[][]{{ 0, 0}, { 0, 1}, { 0, 2}}); - put(EAST, new int[][]{{ 0, 0}, {-1, 0}, {-2, 0}}); - put(WEST, new int[][]{{ 0, 0}, { 1, 0}, { 2, 0}}); - }}; - - public static boolean shouldTurn(AbstractBoatEntity boat, ClientWorld level, boolean left) { - int rootX = boat.getBlockX(); - int rootY = boat.getBlockY() - 1; - int rootZ = boat.getBlockZ(); - - // get the direction the boat is facing - // north/south/east/west - Direction direction = boat.getHorizontalFacing(); - int[][] map; - - // get the block offsets for left/right - if (left) { - map = toScanMapLeft.get(direction); - } else { - map = toScanMapRight.get(direction); - } - for (int i = 0; i < map.length; i++) { - BlockPos testBlockPos = new BlockPos(rootX + map[i][0], rootY, rootZ + map[i][1]); - if (Util.isIce(level.getBlockState(testBlockPos))) { - int[] snapBlock = snapBlockMap.get(direction)[i]; - boat.setPosition(rootX + snapBlock[0] + 0.5, boat.getY(), rootZ + snapBlock[1] + 0.5); - return true; - } - } - - return false; - } - - public static void smartCenter(AbstractBoatEntity boat) { - World world = boat.getWorld(); - Direction direction = boat.getHorizontalFacing(); - int rootX = boat.getBlockX(); - int rootY = boat.getBlockY(); - int rootZ = boat.getBlockZ(); - - int scanAhead = ModConfig.getInstance().smartCenterLookAhead; - if (direction == NORTH || direction == SOUTH) { - int startZ = direction == NORTH ? -scanAhead : -1; - int endZ = direction == NORTH ? 1 : scanAhead; - double nudgeX = calculateNudge(world, startZ, endZ, z -> new BlockPos(rootX - 1, rootY, rootZ + z), z -> new BlockPos(rootX + 1, rootY, rootZ + z)); - boat.setPosition(rootX + 0.5 + nudgeX, boat.getY(), boat.getZ()); - } else { - int startX = direction == WEST ? -scanAhead : -1; - int endX = direction == WEST ? 1 : scanAhead; - double nudgeZ = calculateNudge(world, startX, endX, x -> new BlockPos(rootX + x, rootY, rootZ - 1), x -> new BlockPos(rootX + x, rootY, rootZ + 1)); - boat.setPosition(boat.getX(), boat.getY(), rootZ + 0.5 + nudgeZ); - } - } - - private static double calculateNudge(World world, int start, int end, Function leftBlockPosFunc, Function rightBlockPosFunc) { - int nudge = 0; - for (int i = start; i <= end; i++) { - BlockPos leftBlockPos = leftBlockPosFunc.apply(i); - BlockPos rightBlockPos = rightBlockPosFunc.apply(i); - if (!(world.getBlockState(leftBlockPos).getBlock() instanceof AirBlock)) - nudge += 1; - if (!(world.getBlockState(rightBlockPos).getBlock() instanceof AirBlock)) - nudge -= 1; - } - return MathHelper.clamp(nudge, -0.2, 0.2); - } -} diff --git a/src/main/java/net/cardinalboats/Util.java b/src/main/java/net/cardinalboats/Util.java deleted file mode 100644 index 3b868fc..0000000 --- a/src/main/java/net/cardinalboats/Util.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.cardinalboats; - -import net.cardinalboats.config.ModConfig; -import net.minecraft.block.BlockState; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.vehicle.AbstractBoatEntity; -import net.minecraft.text.Text; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import java.util.regex.Pattern; - -import static net.minecraft.util.math.MathHelper.RADIANS_PER_DEGREE; - -public class Util { - private static final Pattern icePattern = Pattern.compile("(\\b|_)ice\\b", Pattern.CASE_INSENSITIVE); - - public static void rotateBoat(AbstractBoatEntity boat, Float rotation, Boolean maintainVelocity) { - boat.setYaw(rotation); - boat.yawVelocity = 0; - boat.getControllingPassenger().setYaw(boat.getYaw()); - - if (maintainVelocity) { - // get current velocity vector length - double currentVelocity = boat.getVelocity().length(); - // create new vector normalized to rotation - Vec3d newVelocity = new Vec3d(0,0, currentVelocity).rotateY(-rotation*RADIANS_PER_DEGREE); // Trig magic - // give boat new thing - boat.setVelocity(newVelocity); - } else { - boat.setVelocity(Vec3d.ZERO); - } - } - - public static boolean isIce(BlockState blockState) { - return icePattern.matcher(blockState.getBlock().toString()).find(); - } - - public static void ClientChatLog(ClientPlayerEntity player, String message) { - if (player == null) return; - - if (ModConfig.getInstance().doChatShit) { - player.sendMessage(Text.of("[cardinalboats] " + message), false); - } - } - - public static boolean shouldSnap(World level, PlayerEntity player) { - // If we are putting a boat on a block - HitResult lookingAt = player.raycast(20.0D, 0.0F, false); - if (lookingAt != null && lookingAt.getType() == HitResult.Type.BLOCK) { - // If that block is ice, return true - return isIce(level.getBlockState(((BlockHitResult) lookingAt).getBlockPos())); - } - return false; - } - - public static float roundYRot(float yRot, int toNearest) { - return Math.round(yRot % 360 / toNearest) * toNearest; - } -} diff --git a/src/main/java/net/cardinalboats/config/ModConfig.java b/src/main/java/net/cardinalboats/config/ModConfig.java deleted file mode 100644 index 6ddaa57..0000000 --- a/src/main/java/net/cardinalboats/config/ModConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.cardinalboats.config; - -import me.shedaniel.autoconfig.AutoConfig; -import me.shedaniel.autoconfig.ConfigData; - - -import me.shedaniel.autoconfig.annotation.Config; -import me.shedaniel.autoconfig.annotation.ConfigEntry; -import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer; - -@Config(name = "CardinalBoat") -public class ModConfig implements ConfigData { - @ConfigEntry.Gui.Tooltip - public boolean doChatShit = true; - - @ConfigEntry.Gui.Tooltip - public boolean maintainVelocityOnTurns = false; - - @ConfigEntry.Gui.Tooltip - public boolean eightWaySnapKey = true; - - @ConfigEntry.Gui.Tooltip - public boolean moveWhileChatting = true; - - @ConfigEntry.Gui.Tooltip - public boolean alwaysSmartCenter = false; - - @ConfigEntry.Gui.Tooltip - @ConfigEntry.BoundedDiscrete(min = 1, max = 10) - public int smartCenterLookAhead = 5; - - @ConfigEntry.Gui.Tooltip - public boolean smartCenterPrimedTurn = true; - - public static void init() { - AutoConfig.register(ModConfig.class, Toml4jConfigSerializer::new); - } - - public static ModConfig getInstance() { - return AutoConfig.getConfigHolder(ModConfig.class).getConfig(); - } -} diff --git a/src/main/java/net/cardinalboats/config/ModMenuIntegration.java b/src/main/java/net/cardinalboats/config/ModMenuIntegration.java deleted file mode 100644 index 322b166..0000000 --- a/src/main/java/net/cardinalboats/config/ModMenuIntegration.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.cardinalboats.config; - -import com.terraformersmc.modmenu.api.ConfigScreenFactory; -import com.terraformersmc.modmenu.api.ModMenuApi; -import me.shedaniel.autoconfig.AutoConfig; - -public class ModMenuIntegration implements ModMenuApi { - @Override - public ConfigScreenFactory getModConfigScreenFactory() { - return parent -> AutoConfig.getConfigScreen(ModConfig.class, parent).get(); - } -} diff --git a/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java b/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java deleted file mode 100644 index 2305af1..0000000 --- a/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.cardinalboats.mixin; - -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import com.llamalad7.mixinextras.sugar.Local; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; - -import static net.cardinalboats.Util.roundYRot; -import static net.cardinalboats.Util.shouldSnap; - -import net.minecraft.item.BoatItem; - -@Mixin(BoatItem.class) -public class BoatPlacementSnap { - @ModifyExpressionValue(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getYaw()F")) - private float boatSnap(float original, @Local(argsOnly = true) PlayerEntity player, @Local(argsOnly = true) World world) { - if (shouldSnap(world, player)) - return roundYRot(player.getYaw(), 45); - return original; - } -} diff --git a/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java b/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java deleted file mode 100644 index 9941e67..0000000 --- a/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java +++ /dev/null @@ -1,28 +0,0 @@ -package net.cardinalboats.mixin; - -import net.minecraft.entity.vehicle.AbstractBoatEntity; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import com.llamalad7.mixinextras.injector.ModifyExpressionValue; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.ChatScreen; -import net.minecraft.client.input.KeyboardInput; - -import static net.cardinalboats.CardinalBoatsInit.LieAboutMovingForward; - -@Mixin(value = KeyboardInput.class, priority = 1000) -public class ChatMoveLie { - @ModifyExpressionValue(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;isPressed()Z", ordinal = 0)) - private boolean lie(boolean original) { - if (LieAboutMovingForward) { - if (MinecraftClient.getInstance().currentScreen instanceof ChatScreen && MinecraftClient.getInstance().player.getVehicle() instanceof AbstractBoatEntity) { - // lie about moving forward - return true; - } else { - // chat isn't open, turn off lying - LieAboutMovingForward = false; - } - } - return original; - } -} diff --git a/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java b/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java deleted file mode 100644 index 85494f5..0000000 --- a/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.cardinalboats.mixin; - -import net.cardinalboats.config.ModConfig; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.network.ClientPlayerEntity; -import net.minecraft.entity.vehicle.AbstractBoatEntity; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import static net.cardinalboats.CardinalBoatsInit.LieAboutMovingForward; - -@Mixin(value = MinecraftClient.class, priority = 1000) -public abstract class ChatMoveStartLying { - @Shadow @Nullable public ClientPlayerEntity player; - - @Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;openChatScreen(Ljava/lang/String;)V")) - void moveChatBoi(CallbackInfo ci) { - // on opening the chat - assert this.player != null; - - if (player.getVehicle() instanceof AbstractBoatEntity && ModConfig.getInstance().moveWhileChatting) { - // if the player is holding W - if (MinecraftClient.getInstance().options.forwardKey.isPressed()) { - // lie and tell the server that we are still moving forward despite having chat open - LieAboutMovingForward = true; - } - } - } -} diff --git a/src/main/resources/assets/cardinalboats/icon.png b/src/main/resources/assets/cardinalboats/icon.png deleted file mode 100644 index 9de402a095b427f1416662c6e118684807e5f1ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58126 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 BlD_}| diff --git a/src/main/resources/assets/cardinalboats/lang/en_us.json b/src/main/resources/assets/cardinalboats/lang/en_us.json deleted file mode 100644 index c5eff47..0000000 --- a/src/main/resources/assets/cardinalboats/lang/en_us.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "category.cardinalboats.key_category_title" : "Cardinal Ice Boats", - - "key.cardinalboats.snapManual" : "Re-Snap", - "key.cardinalboats.snap180" : "Instant Reverse", - "key.cardinalboats.smartCenter" : "Smart Center", - - "key.cardinalboats.prime_left": "Prime Left Turn", - "key.cardinalboats.prime_right": "Prime Right Turn", - - "info.cardinalboats.left_turn_queue" : "Left Turn Primed", - "info.cardinalboats.right_turn_queue" : "Right Turn Primed", - - "info.cardinalboats.left_turn_complete" : "Left Turn Completed", - "info.cardinalboats.right_turn_complete" : "Right Turn Completed", - - "info.cardinalboats.cancel" : "Primed turn cancelled. Player left boat.", - - "text.autoconfig.CardinalBoat.option.doChatShit" : "Print primed turn logs to chat", - "text.autoconfig.CardinalBoat.option.doChatShit.@Tooltip" : "Prints primed, completed, and cancelled messages to the chat.", - - "text.autoconfig.CardinalBoat.option.maintainVelocityOnTurns" : "Maintain Velocity on Primed Turns", - "text.autoconfig.CardinalBoat.option.maintainVelocityOnTurns.@Tooltip" : "Maintains forward velocity on Primed Turns, similar to the snap key.\nMay not work well on laggy servers.\n§4OP as f§ku§r§4ck, may get you banned.", - - "text.autoconfig.CardinalBoat.option.eightWaySnapKey" : "Snap Key Directionality", - "text.autoconfig.CardinalBoat.option.eightWaySnapKey.@Tooltip" : "§bEight-Way§r - Pressing Snap Key will align boat to nearest 45°\n§6Four-Way§r - Pressing Snap Key will align boat to nearest 90°", - "text.autoconfig.CardinalBoat.option.eightWaySnapKey.boolean.true" : "§bEight-Way", - "text.autoconfig.CardinalBoat.option.eightWaySnapKey.boolean.false" : "§6Four-Way", - - "text.autoconfig.CardinalBoat.option.alwaysSmartCenter" : "Always Smart Center", - "text.autoconfig.CardinalBoat.option.alwaysSmartCenter.@Tooltip" : "Runs smart center all the time when boat is perfectly cardinally aligned", - - "text.autoconfig.CardinalBoat.option.smartCenterLookAhead" : "Smart Center Lookahead", - "text.autoconfig.CardinalBoat.option.smartCenterLookAhead.@Tooltip" : "Number of blocks ahead of you that smart center scans for walls.", - - "text.autoconfig.CardinalBoat.option.smartCenterPrimedTurn" : "Smart Center on Primed Turns", - "text.autoconfig.CardinalBoat.option.smartCenterPrimedTurn.@Tooltip" : "Boat will automatically smart center itself after taking a primed turn", - - "text.autoconfig.CardinalBoat.option.moveWhileChatting" : "Keep Moving While Chatting", - "text.autoconfig.CardinalBoat.option.moveWhileChatting.@Tooltip" : "Allows you to chat while driving a boat.\nIf you open the chat while moving forward, it keeps moving forward for you.\n§mDon't text and drive.", - - "text.autoconfig.CardinalBoat.title" : "Cardinal Ice Boats Config" -} diff --git a/src/main/resources/cardinalboats.accesswidener b/src/main/resources/cardinalboats.accesswidener deleted file mode 100644 index b7793ec..0000000 --- a/src/main/resources/cardinalboats.accesswidener +++ /dev/null @@ -1,3 +0,0 @@ -accessWidener v1 named - -accessible field net/minecraft/entity/vehicle/AbstractBoatEntity yawVelocity F diff --git a/src/main/resources/cardinalboats.mixins.json b/src/main/resources/cardinalboats.mixins.json deleted file mode 100644 index fb9d1bd..0000000 --- a/src/main/resources/cardinalboats.mixins.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "net.cardinalboats.mixin", - "compatibilityLevel": "JAVA_21", - "client": [ - "ChatMoveLie", - "ChatMoveStartLying" - ], - "injectors": { - "defaultRequire": 1 - }, - "mixins": [ - "BoatPlacementSnap" - ] -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json deleted file mode 100644 index aa6ed2d..0000000 --- a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "schemaVersion": 1, - "id": "cardinalboats", - "version": "${version}", - "name": "Cardinal Ice Boats", - "description": "Provides Several QOL Utilities for ice boating", - "authors": [ - "CodeF53#0241" - ], - "contact": { - "homepage": "https://modrinth.com/mod/cardinalboats", - "sources": "https://github.com/CodeF53/CardinalIceBoats", - "issues": "https://github.com/CodeF53/CardinalIceBoats/issues" - }, - "license": "CC0", - "icon": "assets/cardinalboats/icon.png", - "environment": "*", - "entrypoints": { - "client": [ "net.cardinalboats.CardinalBoatsInit" ], - "modmenu": [ "net.cardinalboats.config.ModMenuIntegration" ] - }, - "accessWidener": "cardinalboats.accesswidener", - "mixins": [ "cardinalboats.mixins.json" ], - "depends": { - "fabricloader": ">=0.16.10", - "fabric": "*", - "cloth-config": "*", - "minecraft": ">=1.21.2", - "java": ">=21" - } -} From efd77d7749245cdec26bc446bb71876583de04ff Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:50:05 +0300 Subject: [PATCH 02/10] Add the new build system. --- build.gradle.kts | 36 ++ config/detekt/detekt.yml | 785 +++++++++++++++++++++++ gradle.properties | 43 +- gradle/gradle-daemon-jvm.properties | 2 + gradle/libs.versions.toml | 12 + gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 96 +++ 7 files changed, 959 insertions(+), 17 deletions(-) create mode 100644 build.gradle.kts create mode 100644 config/detekt/detekt.yml create mode 100644 gradle/gradle-daemon-jvm.properties create mode 100644 gradle/libs.versions.toml create mode 100644 settings.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..f6cb9d8 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,36 @@ +import io.gitlab.arturbosch.detekt.Detekt + +plugins { + alias(libs.plugins.kotlin) apply false + alias(libs.plugins.kotlinSer) apply false + alias(libs.plugins.detekt) + alias(libs.plugins.shadow) apply false + alias(libs.plugins.loom) apply false + id("libipn-gradle") version "1.0.0-SNAPSHOT" apply false +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, "seconds") +} + + + +subprojects { + group = "org.anti_ad.mc" + apply { + plugin(rootProject.libs.plugins.detekt.get().pluginId) + } + + detekt { + config.setFrom(rootProject.files("config/detekt/detekt.yml")) + } + version = "1.0.0" + +} + +tasks.withType().configureEach { + reports { + html.required.set(true) + html.outputLocation.set(file("build/reports/detekt.html")) + } +} diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 0000000..a3c77c3 --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,785 @@ +build: + maxIssues: 0 + excludeCorrectable: false + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +config: + validation: true + warningsAsErrors: false + checkExhaustiveness: false + # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' + excludes: '' + +processors: + active: true + exclude: + - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' + +console-reports: + active: true + exclude: + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + - 'FindingsReport' + - 'FileBasedFindingsReport' + # - 'LiteFindingsReport' + +output-reports: + active: true + exclude: + # - 'TxtOutputReport' + # - 'XmlOutputReport' + # - 'HtmlOutputReport' + # - 'MdOutputReport' + # - 'SarifOutputReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + KDocReferencesNonPublicProperty: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + OutdatedDocumentation: + active: false + matchTypeParameters: true + matchDeclarationsOrder: true + allowParamOnConstructorProperties: false + UndocumentedPublicClass: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + searchInProtectedClass: false + UndocumentedPublicFunction: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + searchProtectedFunction: false + UndocumentedPublicProperty: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + searchProtectedProperty: false + +complexity: + active: true + CognitiveComplexMethod: + active: false + threshold: 15 + ComplexCondition: + active: true + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + ignoreOverloaded: false + CyclomaticComplexMethod: + active: true + threshold: 15 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [] + LargeClass: + active: true + threshold: 600 + LongMethod: + active: true + threshold: 250 + LongParameterList: + active: true + functionThreshold: 6 + constructorThreshold: 7 + ignoreDefaultParameters: false + ignoreDataClasses: true + ignoreAnnotatedParameter: [] + MethodOverloading: + active: false + threshold: 6 + NamedArguments: + active: false + threshold: 3 + ignoreArgumentsMatchingNames: false + NestedBlockDepth: + active: true + threshold: 10 + NestedScopeFunctions: + active: false + threshold: 1 + functions: + - 'kotlin.apply' + - 'kotlin.run' + - 'kotlin.with' + - 'kotlin.let' + - 'kotlin.also' + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + thresholdInFiles: 60 + thresholdInClasses: 40 + thresholdInInterfaces: 40 + thresholdInObjects: 40 + thresholdInEnums: 40 + ignoreDeprecated: false + ignorePrivate: true + ignoreOverridden: true + ignoreAnnotatedFunctions: [] + +coroutines: + active: true + GlobalCoroutineUsage: + active: false + InjectDispatcher: + active: true + dispatcherNames: + - 'IO' + - 'Default' + - 'Unconfined' + RedundantSuspendModifier: + active: true + SleepInsteadOfDelay: + active: true + SuspendFunSwallowedCancellation: + active: false + SuspendFunWithCoroutineScopeReceiver: + active: false + SuspendFunWithFlowReturnType: + active: true + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: '_|(ignore|expected).*' + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverridden: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyTryBlock: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: true + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' + InstanceOfCheckForException: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: false + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: false + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +naming: + active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are)' + ClassNaming: + active: true + classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + privateParameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + EnumNaming: + active: true + enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: [] + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + functionPattern: '[a-z][a-zA-Z0-9]*' + excludeClassPattern: '$^' + FunctionParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + InvalidPackageDeclaration: + active: true + rootPackage: '' + requireRootInDeclaration: false + LambdaParameterNaming: + active: false + parameterPattern: '[a-z][A-Za-z0-9]*|_' + MatchingDeclarationName: + active: true + mustBeFirst: true + MemberNameEqualsClassName: + active: true + ignoreOverridden: true + NoNameShadowing: + active: true + NonBooleanPropertyPrefixedWithIs: + active: false + ObjectPropertyNaming: + active: true + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '[_a-z]+(\.[_a-z][_A-Za-z0-9]*)*' + TopLevelPropertyNaming: + active: true + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: true + variablePattern: '[_A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + +performance: + active: true + ArrayPrimitive: + active: true + CouldBeSequence: + active: false + threshold: 3 + ForEachOnRange: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + SpreadOperator: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + UnnecessaryPartOfBinaryExpression: + active: false + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + AvoidReferentialEquality: + active: true + forbiddenTypePatterns: + - 'kotlin.String' + CastNullableToNonNullableType: + active: false + CastToNullableType: + active: false + Deprecation: + active: false + DontDowncastCollectionTypes: + active: false + DoubleMutabilityForCollection: + active: true + mutableTypes: + - 'kotlin.collections.MutableList' + - 'kotlin.collections.MutableMap' + - 'kotlin.collections.MutableSet' + - 'java.util.ArrayList' + - 'java.util.LinkedHashSet' + - 'java.util.HashSet' + - 'java.util.LinkedHashMap' + - 'java.util.HashMap' + ElseCaseInsteadOfExhaustiveWhen: + active: false + ignoredSubjectTypes: [] + EqualsAlwaysReturnsTrueOrFalse: + active: true + EqualsWithHashCodeExist: + active: true + ExitOutsideMain: + active: false + ExplicitGarbageCollectionCall: + active: true + HasPlatformType: + active: true + IgnoredReturnValue: + active: true + restrictToConfig: true + returnValueAnnotations: + - 'CheckResult' + - '*.CheckResult' + - 'CheckReturnValue' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - 'CanIgnoreReturnValue' + - '*.CanIgnoreReturnValue' + returnValueTypes: + - 'kotlin.sequences.Sequence' + - 'kotlinx.coroutines.flow.*Flow' + - 'java.util.stream.*Stream' + ignoreFunctionCall: [] + ImplicitDefaultLocale: + active: true + ImplicitUnitReturnType: + active: false + allowExplicitReturnType: true + InvalidRange: + active: true + IteratorHasNextCallsNextMethod: + active: true + IteratorNotThrowingNoSuchElementException: + active: true + LateinitUsage: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + ignoreOnClassesPattern: '' + MapGetWithNotNullAssertionOperator: + active: true + MissingPackageDeclaration: + active: false + excludes: ['**/*.kts'] + NullCheckOnMutableProperty: + active: false + NullableToStringCall: + active: false + PropertyUsedBeforeDeclaration: + active: false + UnconditionalJumpStatementInLoop: + active: false + UnnecessaryNotNullCheck: + active: false + UnnecessaryNotNullOperator: + active: true + UnnecessarySafeCall: + active: false + UnreachableCatchBlock: + active: true + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**'] + UnsafeCast: + active: true + UnusedUnaryOperator: + active: true + UselessPostfixExpression: + active: true + WrongEqualsTypeParameter: + active: true + +style: + active: true + AlsoCouldBeApply: + active: false + BracesOnIfStatements: + active: false + singleLine: 'never' + multiLine: 'always' + BracesOnWhenStatements: + active: false + singleLine: 'necessary' + multiLine: 'consistent' + CanBeNonNullable: + active: false + CascadingCallWrapping: + active: false + includeElvis: true + ClassOrdering: + active: false + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: + - 'to' + allowOperators: false + DataClassShouldBeImmutable: + active: false + DestructuringDeclarationWithTooManyEntries: + active: true + maxDestructuringEntries: 3 + DoubleNegativeLambda: + active: false + negativeFunctions: + - reason: 'Use `takeIf` instead.' + value: 'takeUnless' + - reason: 'Use `all` instead.' + value: 'none' + negativeFunctionNameParts: + - 'not' + - 'non' + EqualsNullCall: + active: true + EqualsOnSignatureLine: + active: false + ExplicitCollectionElementAccessMethod: + active: false + ExplicitItLambdaParameter: + active: true + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenAnnotation: + active: false + annotations: + - reason: 'it is a java annotation. Use `Suppress` instead.' + value: 'java.lang.SuppressWarnings' + - reason: 'it is a java annotation. Use `kotlin.Deprecated` instead.' + value: 'java.lang.Deprecated' + - reason: 'it is a java annotation. Use `kotlin.annotation.MustBeDocumented` instead.' + value: 'java.lang.annotation.Documented' + - reason: 'it is a java annotation. Use `kotlin.annotation.Target` instead.' + value: 'java.lang.annotation.Target' + - reason: 'it is a java annotation. Use `kotlin.annotation.Retention` instead.' + value: 'java.lang.annotation.Retention' + - reason: 'it is a java annotation. Use `kotlin.annotation.Repeatable` instead.' + value: 'java.lang.annotation.Repeatable' + - reason: 'Kotlin does not support @Inherited annotation, see https://youtrack.jetbrains.com/issue/KT-22265' + value: 'java.lang.annotation.Inherited' + ForbiddenComment: + active: true + comments: + - reason: 'Forbidden FIXME todo marker in comment, please fix the problem.' + value: 'FIXME:' + - reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.' + value: 'STOPSHIP:' + - reason: 'Forbidden TODO todo marker in comment, please do the changes.' + value: 'TODO:' + allowedPatterns: '' + ForbiddenImport: + active: false + imports: [] + forbiddenPatterns: '' + ForbiddenMethodCall: + active: false + methods: + - reason: 'print does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.print' + - reason: 'println does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.println' + ForbiddenSuppress: + active: false + rules: [] + ForbiddenVoid: + active: true + ignoreOverridden: false + ignoreUsageInGenerics: false + FunctionOnlyReturningConstant: + active: true + ignoreOverridableFunction: true + ignoreActualFunction: true + excludedFunctions: [] + LoopWithTooManyJumpStatements: + active: true + maxJumpCount: 1 + MagicNumber: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + ignoreHashCodeFunction: true + ignorePropertyDeclaration: false + ignoreLocalVariableDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: false + ignoreNamedArgument: true + ignoreEnums: false + ignoreRanges: false + ignoreExtensionFunctions: true + MandatoryBracesLoops: + active: false + MaxChainedCallsOnSameLine: + active: false + maxChainedCalls: 5 + MaxLineLength: + active: true + maxLineLength: 200 + excludePackageStatements: true + excludeImportStatements: true + excludeCommentStatements: false + excludeRawStrings: true + MayBeConst: + active: true + ModifierOrder: + active: true + MultilineLambdaItParameter: + active: false + MultilineRawStringIndentation: + active: false + indentSize: 4 + trimmingMethods: + - 'trimIndent' + - 'trimMargin' + NestedClassesVisibility: + active: true + NewLineAtEndOfFile: + active: true + NoTabs: + active: false + NullableBooleanCheck: + active: false + ObjectLiteralToLambda: + active: true + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: true + RedundantExplicitType: + active: false + RedundantHigherOrderMapUsage: + active: true + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 2 + excludedFunctions: + - 'equals' + excludeLabeled: false + excludeReturnFromLambda: true + excludeGuardClauses: false + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: true + SpacingBetweenPackageAndImports: + active: false + StringShouldBeRawString: + active: false + maxEscapedCharacterCount: 2 + ignoredCharacters: [] + ThrowsCount: + active: true + max: 2 + excludeGuardClauses: false + TrailingWhitespace: + active: false + TrimMultilineRawString: + active: false + trimmingMethods: + - 'trimIndent' + - 'trimMargin' + UnderscoresInNumericLiterals: + active: false + acceptableLength: 4 + allowNonStandardGrouping: false + UnnecessaryAbstractClass: + active: true + UnnecessaryAnnotationUseSiteTarget: + active: false + UnnecessaryApply: + active: true + UnnecessaryBackticks: + active: false + UnnecessaryBracesAroundTrailingLambda: + active: false + UnnecessaryFilter: + active: true + UnnecessaryInheritance: + active: true + UnnecessaryInnerClass: + active: false + UnnecessaryLet: + active: false + UnnecessaryParentheses: + active: false + allowForUnclearPrecedence: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: false + UnusedParameter: + active: true + allowedNames: 'ignored|expected' + UnusedPrivateClass: + active: true + UnusedPrivateMember: + active: true + allowedNames: '' + UnusedPrivateProperty: + active: true + allowedNames: '_|ignored|expected|serialVersionUID' + UseAnyOrNoneInsteadOfFind: + active: true + UseArrayLiteralsInAnnotations: + active: true + UseCheckNotNull: + active: true + UseCheckOrError: + active: true + UseDataClass: + active: false + allowVars: false + UseEmptyCounterpart: + active: false + UseIfEmptyOrIfBlank: + active: false + UseIfInsteadOfWhen: + active: false + ignoreWhenContainingVariableDeclaration: false + UseIsNullOrEmpty: + active: true + UseLet: + active: false + UseOrEmpty: + active: true + UseRequire: + active: true + UseRequireNotNull: + active: true + UseSumOfInsteadOfFlatMapSize: + active: false + UselessCallOnNotNull: + active: true + UtilityClassWithPublicConstructor: + active: true + VarCouldBeVal: + active: true + ignoreLateinitVar: false + WildcardImport: + active: false + excludeImports: + - 'java.util.*' diff --git a/gradle.properties b/gradle.properties index 4a431c6..3e75186 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,19 +1,30 @@ -# Done to increase the memory available to gradle. -org.gradle.jvmargs=-Xmx4G -org.gradle.parallel=true -# Fabric Properties -# check these on https://fabricmc.net/develop -minecraft_version=1.21.5 -yarn_mappings=1.21.5+build.1 -loader_version=0.16.10 +mod.description=Provides Several QOL Utilities for ice boating: +mod.scm=https://github.com/CodeF53/CardinalIceBoats +mod.tracker=https://discord.gg/23YCxmveUM +mod.docs=https://discord.gg/23YCxmveUM +mod.license=CC0-1.0-UNI +mod.contributors="" +mod.authors="CodeF53, Mirinimi" +mod.display.name="Cardinal Ice Boats." +mod.id=cardinalboats +mod.icon="assets/cardinalboats/icon.png" +mod.gen.package.name=net.iceboats.generated -# Mod Properties -mod_version=1.4.6 -maven_group=net.cardinalboats -archives_base_name=cardinalboats +#mod.build.libipn.version=6.5.0 +#mod.libipn.version=6.5.0 +#mod.libipn.version.max=6.6 -# Dependencies -fabric_api_version=0.119.5+1.21.5 -cloth_config_version=18.0.145 -mod_menu_version=14.0.0-rc.2 +#mod.ipn.version=2.1.9 + + + +org.gradle.vfs.watch=true +kapt.use.worker.api=true +#kapt.include.compile.classpath=true +org.gradle.parallel=false +org.gradle.caching=false +org.gradle.warning.mode=all +#org.gradle.logging.level=info + +org.gradle.daemon=false diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000..63e5bbd --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,2 @@ +#This file is generated by updateDaemonJvm +toolchainVersion=21 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..5a3e477 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +[versions] +detekt = "1+" +kotlin = "2.0.21" +shadowVer = "8.+" +loomVer = "1.9-SNAPSHOT" + +[plugins] +detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"} +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"} +kotlinSer = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"} +shadow = { id = "com.gradleup.shadow", version.ref = "shadowVer"} +loom = { id = "fabric-loom", version.ref = "loomVer"} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1706211..9358489 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Fri Jun 21 21:04:42 MDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..d941db1 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,96 @@ + +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + maven { url = uri("https://repo.spongepowered.org/repository/maven-public/") } + maven { url = uri("https://maven.minecraftforge.net") } + maven { + url = uri("https://maven.fabricmc.net/") + } + maven { url = uri("https://maven.neoforged.net/releases/") } + maven { url = uri("https://plugins.gradle.org/m2/") } + + maven { + name = "libIPN-Snapshots" + mavenContent { + snapshotsOnly() + } + content { + includeGroup ("libipn-gradle") + includeGroup ("org.anti_ad.mc") + includeGroup ("org.anti_ad.mc.plugins") + includeGroup ("ca.solo-studios") + } + + url = uri("https://maven.ipn-mod.org/snapshots") + } + maven { + name = "libIPN-Releases" + mavenContent { + releasesOnly() + } + content { + includeGroup ("libipn-gradle") + includeGroup ("org.anti_ad.mc") + includeGroup ("org.anti_ad.mc.plugins") + includeGroup ("ca.solo-studios") + } + url = uri("https://maven.ipn-mod.org/releases") + } + + } +} + +dependencyResolutionManagement { + repositories { + gradlePluginPortal() + mavenCentral() + google() + maven { url = uri("https://repo.spongepowered.org/repository/maven-public/") } + maven { url = uri("https://maven.minecraftforge.net") } + maven { url = uri("https://maven.fabricmc.net/") } + maven { url = uri("https://maven.neoforged.net/releases/") } + maven { url = uri("https://plugins.gradle.org/m2/") } + + maven { + name = "libIPN-Snapshots" + mavenContent { + snapshotsOnly() + } + content { + includeGroup ("libipn-gradle") + includeGroup ("org.anti_ad.mc") + includeGroup ("org.anti_ad.mc.plugins") + includeGroup ("ca.solo-studios") + } + url = uri("https://maven.ipn-mod.org/snapshots") + } + maven { + name = "libIPN-Releases" + mavenContent { + releasesOnly() + } + content { + includeGroup ("libipn-gradle") + includeGroup ("org.anti_ad.mc") + includeGroup ("org.anti_ad.mc.plugins") + includeGroup ("ca.solo-studios") + } + url = uri("https://maven.ipn-mod.org/releases") + } + } + + +} + +rootProject.name = "CardinalIceBoats" + +include(":platforms:fabric-1.21.5") +//include(":platforms:forge-1.21.5") +//include(":platforms:neoforge-1.21.5") + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.+" +} + From 1715250711615a513f0f5f05207be7a22a9d0128 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:50:45 +0300 Subject: [PATCH 03/10] Add the kotlin code with new layout. --- platforms/fabric-1.21.5/.gitignore | 4 + platforms/fabric-1.21.5/build.gradle.kts | 28 +++ platforms/fabric-1.21.5/gradle.properties | 17 ++ .../fabric-1.21.5/src/integrations/modmenu | 1 + .../mixin/BoatPlacementSnap.java | 24 +++ .../net/cardinalboats/mixin/ChatMoveLie.java | 29 +++ .../mixin/ChatMoveStartLying.java | 32 +++ .../net/cardinalboats/CardinalBoatsInit.kt | 12 ++ .../kotlin/net/cardinalboats/ManualSnap.kt | 53 +++++ .../kotlin/net/cardinalboats/TurnPriming.kt | 200 ++++++++++++++++++ .../src/main/kotlin/net/cardinalboats/Util.kt | 65 ++++++ .../resources/cardinalboats.accesswidener | 3 + .../main/resources/cardinalboats.mixins.json | 16 ++ platforms/fabric-1.21.5/src/modloader | 1 + platforms/fabric-1.21.5/src/shared | 1 + .../integration/modmenu/CIBModMenu.kt | 16 ++ .../net/cardinalboats/config/CIBConfig.java | 42 ++++ .../resources/assets/cardinalboats/icon.png | Bin 0 -> 58126 bytes .../assets/cardinalboats/lang/en_us.json | 43 ++++ .../fabric/src/main/resources/fabric.mod.json | 24 +++ .../src/main/resources/META-INF/mods.toml | 28 +++ .../forge/src/main/resources/pack.mcmeta | 7 + .../resources/META-INF/accesstransformer.cfg | 10 + .../resources/META-INF/neoforge.mods.toml | 29 +++ .../neoforge/src/main/resources/pack.mcmeta | 7 + 25 files changed, 692 insertions(+) create mode 100644 platforms/fabric-1.21.5/.gitignore create mode 100644 platforms/fabric-1.21.5/build.gradle.kts create mode 100644 platforms/fabric-1.21.5/gradle.properties create mode 120000 platforms/fabric-1.21.5/src/integrations/modmenu create mode 100644 platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java create mode 100644 platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java create mode 100644 platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java create mode 100644 platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt create mode 100644 platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt create mode 100644 platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt create mode 100644 platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt create mode 100644 platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener create mode 100644 platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json create mode 120000 platforms/fabric-1.21.5/src/modloader create mode 120000 platforms/fabric-1.21.5/src/shared create mode 100644 platforms/shared/integrations/modmenu/src/main/kotlin/net/cardinalboats/integration/modmenu/CIBModMenu.kt create mode 100644 platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java create mode 100644 platforms/shared/main/resources/assets/cardinalboats/icon.png create mode 100644 platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json create mode 100644 platforms/shared/modloader/fabric/src/main/resources/fabric.mod.json create mode 100644 platforms/shared/modloader/forge/src/main/resources/META-INF/mods.toml create mode 100644 platforms/shared/modloader/forge/src/main/resources/pack.mcmeta create mode 100644 platforms/shared/modloader/neoforge/src/main/resources/META-INF/accesstransformer.cfg create mode 100644 platforms/shared/modloader/neoforge/src/main/resources/META-INF/neoforge.mods.toml create mode 100644 platforms/shared/modloader/neoforge/src/main/resources/pack.mcmeta diff --git a/platforms/fabric-1.21.5/.gitignore b/platforms/fabric-1.21.5/.gitignore new file mode 100644 index 0000000..73c9b8f --- /dev/null +++ b/platforms/fabric-1.21.5/.gitignore @@ -0,0 +1,4 @@ +runs/ +.gradle/ +build/ +run/ diff --git a/platforms/fabric-1.21.5/build.gradle.kts b/platforms/fabric-1.21.5/build.gradle.kts new file mode 100644 index 0000000..fe438ee --- /dev/null +++ b/platforms/fabric-1.21.5/build.gradle.kts @@ -0,0 +1,28 @@ +import org.anti_ad.gradle.plugins.libipn.base.modId + +val cloth_config_version: String by project +logger.lifecycle(""" + mod-id: $modId +""".trimIndent()) +repositories { + maven ("https://maven.shedaniel.me/") +} + + +dependencies { + modImplementation ("me.shedaniel.cloth:cloth-config-fabric:$cloth_config_version") +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, "seconds") +} + +plugins { + id("libipn-gradle") +} + +libIPN { + jarPostProcessConfig = { + this.advzipArguments = mutableListOf("-4", "-z", "-i", "100") + } +} diff --git a/platforms/fabric-1.21.5/gradle.properties b/platforms/fabric-1.21.5/gradle.properties new file mode 100644 index 0000000..848d76c --- /dev/null +++ b/platforms/fabric-1.21.5/gradle.properties @@ -0,0 +1,17 @@ +mod.fabric.loader.version=0.16.14 +mod.fabric.api.version=0.128.1+1.21.6 +mod.fabric.language.kotlin.version=1.12.3+kotlin.2.0.21 + +mod.yarn.mappings.version=1.21.6+build.1 + + +mod.build.minecraft.version=1.21.6 +mod.supported.minecraft.version.min=1.21.6 +mod.supported.minecraft.version.max=1.22 + +mod.modmenu.version=15.0.0-beta.3 + +mod.client.entry.point=net.cardinalboats.CardinalBoatsInit +mod.modmenu.factory.class.name=net.cardinalboats.integration.modmenu.CIBModMenu + +cloth_config_version=19.0.147 diff --git a/platforms/fabric-1.21.5/src/integrations/modmenu b/platforms/fabric-1.21.5/src/integrations/modmenu new file mode 120000 index 0000000..f1355b4 --- /dev/null +++ b/platforms/fabric-1.21.5/src/integrations/modmenu @@ -0,0 +1 @@ +../../../shared/integrations/modmenu \ No newline at end of file diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java new file mode 100644 index 0000000..fc769fc --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java @@ -0,0 +1,24 @@ +package net.cardinalboats.mixin; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + + +import net.minecraft.item.BoatItem; + +import static net.cardinalboats.UtilKt.roundYRot; +import static net.cardinalboats.UtilKt.shouldSnap; + +@Mixin(BoatItem.class) +public class BoatPlacementSnap { + @ModifyExpressionValue(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getYaw()F")) + private float boatSnap(float original, @Local(argsOnly = true) PlayerEntity player, @Local(argsOnly = true) World world) { + if (shouldSnap(world, player)) + return roundYRot(player.getYaw(), 45); + return original; + } +} diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java new file mode 100644 index 0000000..af6fb57 --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java @@ -0,0 +1,29 @@ +package net.cardinalboats.mixin; + +import net.minecraft.entity.vehicle.AbstractBoatEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ChatScreen; +import net.minecraft.client.input.KeyboardInput; + +import static net.cardinalboats.UtilKt.lieAboutMovingForward; + + +@Mixin(value = KeyboardInput.class, priority = 1000) +public class ChatMoveLie { + @ModifyExpressionValue(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;isPressed()Z", ordinal = 0)) + private boolean lie(boolean original) { + if (lieAboutMovingForward) { + if (MinecraftClient.getInstance().currentScreen instanceof ChatScreen && MinecraftClient.getInstance().player.getVehicle() instanceof AbstractBoatEntity) { + // lie about moving forward + return true; + } else { + // chat isn't open, turn off lying + lieAboutMovingForward = false; + } + } + return original; + } +} diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java new file mode 100644 index 0000000..30611b1 --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java @@ -0,0 +1,32 @@ +package net.cardinalboats.mixin; + +import net.cardinalboats.config.CIBConfig; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.entity.vehicle.AbstractBoatEntity; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import static net.cardinalboats.UtilKt.lieAboutMovingForward; + +@Mixin(value = MinecraftClient.class, priority = 1000) +public abstract class ChatMoveStartLying { + @Shadow @Nullable public ClientPlayerEntity player; + + @Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;openChatScreen(Ljava/lang/String;)V")) + void moveChatBoi(CallbackInfo ci) { + // on opening the chat + assert this.player != null; + + if (player.getVehicle() instanceof AbstractBoatEntity && CIBConfig.getInstance().moveWhileChatting) { + // if the player is holding W + if (MinecraftClient.getInstance().options.forwardKey.isPressed()) { + // lie and tell the server that we are still moving forward despite having chat open + lieAboutMovingForward = true; + } + } + } +} diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt new file mode 100644 index 0000000..ff4a456 --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt @@ -0,0 +1,12 @@ +package net.cardinalboats + +import net.cardinalboats.config.CIBConfig +import net.fabricmc.api.ClientModInitializer + +class CardinalBoatsInit : ClientModInitializer { + override fun onInitializeClient() { + TurnPriming.init() + ManualSnap.init() + CIBConfig.init() + } +} diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt new file mode 100644 index 0000000..913a877 --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt @@ -0,0 +1,53 @@ +package net.cardinalboats + +import net.cardinalboats.config.CIBConfig +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper +import net.minecraft.client.MinecraftClient +import net.minecraft.client.option.KeyBinding +import net.minecraft.client.util.InputUtil +import net.minecraft.entity.vehicle.AbstractBoatEntity + +object ManualSnap { + + val manualSnapKey = KeyBinding( + "key.cardinalboats.snapManual", + InputUtil.Type.KEYSYM, + InputUtil.GLFW_KEY_UP, + "category.cardinalboats.key_category_title" + ) + + val snap180 = KeyBinding( + "key.cardinalboats.snap180", + InputUtil.Type.KEYSYM, + InputUtil.GLFW_KEY_DOWN, + "category.cardinalboats.key_category_title" + ) + + // Run by fabric initializer + fun init() { + KeyBindingHelper.registerKeyBinding(manualSnapKey) + KeyBindingHelper.registerKeyBinding(snap180) + + ClientTickEvents.END_CLIENT_TICK.register(ManualSnap::tick) + } + + @Suppress("EmptyWhileBlock", "MagicNumber") + fun tick(minecraft: MinecraftClient) { + val player = minecraft.player + if (player != null && player.hasVehicle() && player.vehicle is AbstractBoatEntity) { + val boat = player.vehicle as AbstractBoatEntity + if (isIce(boat.steppingBlockState)) { + while (manualSnapKey.wasPressed()) { + val snapAngle = if (CIBConfig.getInstance().eightWaySnapKey) 45 else 90 + rotateBoat(boat, roundYRot(boat.yaw, snapAngle), true) + } + while (snap180.wasPressed()) { + rotateBoat(boat, boat.yaw % 360 - 180, CIBConfig.getInstance().maintainVelocityOnTurns) + } + } + } else { + while (manualSnapKey.wasPressed() || snap180.wasPressed()) {} + } + } +} diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt new file mode 100644 index 0000000..39b0f1a --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt @@ -0,0 +1,200 @@ +package net.cardinalboats + +import net.cardinalboats.config.CIBConfig +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper +import net.minecraft.block.AirBlock +import net.minecraft.client.MinecraftClient +import net.minecraft.client.option.KeyBinding +import net.minecraft.client.util.InputUtil +import net.minecraft.client.world.ClientWorld +import net.minecraft.entity.vehicle.AbstractBoatEntity +import net.minecraft.text.Text +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Direction.* +import net.minecraft.util.math.MathHelper +import net.minecraft.world.World +import java.util.function.Function + +@Suppress("MagicNumber") +object TurnPriming { + @JvmField + val lQueueKey = KeyBinding( + "key.cardinalboats.prime_left", + InputUtil.Type.KEYSYM, + InputUtil.GLFW_KEY_LEFT, + "category.cardinalboats.key_category_title" + ) + + @JvmField + val rQueueKey = KeyBinding( + "key.cardinalboats.prime_right", + InputUtil.Type.KEYSYM, + InputUtil.GLFW_KEY_RIGHT, + "category.cardinalboats.key_category_title" + ) + + @JvmField + val smartCenterKey = KeyBinding( + "key.cardinalboats.smartCenter", + InputUtil.Type.KEYSYM, + InputUtil.GLFW_KEY_BACKSLASH, + "category.cardinalboats.key_category_title" + ) + + // Run by fabric initializer + fun init() { + KeyBindingHelper.registerKeyBinding(lQueueKey) + KeyBindingHelper.registerKeyBinding(rQueueKey) + KeyBindingHelper.registerKeyBinding(smartCenterKey) + + ClientTickEvents.END_CLIENT_TICK.register { minecraft -> tick(minecraft) } + } + + private var lTurnPrimed = false + private var rTurnPrimed = false + + private val toScanMapLeft = mapOf( + SOUTH to arrayOf(intArrayOf(3, 0), intArrayOf(3, -1), intArrayOf(3, -2)), + NORTH to arrayOf(intArrayOf(-3, 0), intArrayOf(-3, 1), intArrayOf(-3, 2)), + EAST to arrayOf(intArrayOf(0, -3), intArrayOf(-1, -3), intArrayOf(-2, -3)), + WEST to arrayOf(intArrayOf(0, 3), intArrayOf(1, 3), intArrayOf(2, 3)) + ) + + private val toScanMapRight = mapOf( + SOUTH to arrayOf(intArrayOf(-3, 0), intArrayOf(-3, -1), intArrayOf(-3, -2)), + NORTH to arrayOf(intArrayOf(3, 0), intArrayOf(3, 1), intArrayOf(3, 2)), + EAST to arrayOf(intArrayOf(0, 3), intArrayOf(-1, 3), intArrayOf(-2, 3)), + WEST to arrayOf(intArrayOf(0, -3), intArrayOf(1, -3), intArrayOf(2, -3)) + ) + + private val snapBlockMap = mapOf( + SOUTH to arrayOf(intArrayOf(0, 0), intArrayOf(0, -1), intArrayOf(0, -2)), + NORTH to arrayOf(intArrayOf(0, 0), intArrayOf(0, 1), intArrayOf(0, 2)), + EAST to arrayOf(intArrayOf(0, 0), intArrayOf(-1, 0), intArrayOf(-2, 0)), + WEST to arrayOf(intArrayOf(0, 0), intArrayOf(1, 0), intArrayOf(2, 0)) + ) + + @Suppress("EmptyWhileBlock", "MagicNumber", "CyclomaticComplexMethod") + fun tick(minecraft: MinecraftClient) { + val player = minecraft.player + if (player != null && player.hasVehicle() && player.vehicle is AbstractBoatEntity) { + val boat = player.vehicle as AbstractBoatEntity + if (isIce(boat.steppingBlockState)) { + while (lQueueKey.wasPressed()) { + clientChatLog(player, Text.translatable("info.cardinalboats.left_turn_queue").string) + lTurnPrimed = true + rTurnPrimed = false + } + while (rQueueKey.wasPressed()) { + clientChatLog(player, Text.translatable("info.cardinalboats.right_turn_queue").string) + rTurnPrimed = true + lTurnPrimed = false + } + + if (CIBConfig.getInstance().alwaysSmartCenter && boat.yaw % 90 == 0f) { + smartCenter(boat) + } + + while (smartCenterKey.wasPressed()) { + smartCenter(boat) + } + + val world = minecraft.world!! + + if (lTurnPrimed && shouldTurn(boat, world, true)) { + rotateBoat(boat, roundYRot(boat.yaw - 90, 90), CIBConfig.getInstance().maintainVelocityOnTurns) + lTurnPrimed = false + clientChatLog(player, Text.translatable("info.cardinalboats.left_turn_complete").string) + if (CIBConfig.getInstance().smartCenterPrimedTurn) smartCenter(boat) + } else if (rTurnPrimed && shouldTurn(boat, world, false)) { + rotateBoat(boat, roundYRot(boat.yaw + 90, 90), CIBConfig.getInstance().maintainVelocityOnTurns) + rTurnPrimed = false + clientChatLog(player, Text.translatable("info.cardinalboats.right_turn_complete").string) + if (CIBConfig.getInstance().smartCenterPrimedTurn) smartCenter(boat) + } + } else { + while (lQueueKey.wasPressed() || rQueueKey.wasPressed() || smartCenterKey.wasPressed()) {} + } + } else { + // if we aren't in the boat anymore, we don't care + if (lTurnPrimed || rTurnPrimed) { + clientChatLog(minecraft.player, Text.translatable("info.cardinalboats.cancel").string) + } + lTurnPrimed = false + rTurnPrimed = false + + // not in a boat, don't care about any presses these buttons get right now + while (lQueueKey.wasPressed() || rQueueKey.wasPressed() || smartCenterKey.wasPressed()) {} + } + } + + fun shouldTurn(boat: AbstractBoatEntity, level: ClientWorld, left: Boolean): Boolean { + val rootX = boat.blockX + val rootY = boat.blockY - 1 + val rootZ = boat.blockZ + + // get the direction the boat is facing + // north/south/east/west + val direction = boat.horizontalFacing + val map: Array + + // get the block offsets for left/right + map = if (left) { + toScanMapLeft[direction]!! + } else { + toScanMapRight[direction]!! + } + + for (i in map.indices) { + val testBlockPos = BlockPos(rootX + map[i][0], rootY, rootZ + map[i][1]) + if (isIce(level.getBlockState(testBlockPos))) { + val snapBlock = snapBlockMap[direction]!![i] + boat.setPosition(rootX + snapBlock[0] + 0.5, boat.y, rootZ + snapBlock[1] + 0.5) + return true + } + } + + return false + } + + fun smartCenter(boat: AbstractBoatEntity) { + val world = boat.world + val direction = boat.horizontalFacing + val rootX = boat.blockX + val rootY = boat.blockY + val rootZ = boat.blockZ + + val scanAhead = CIBConfig.getInstance().smartCenterLookAhead + if (direction == NORTH || direction == SOUTH) { + val startZ = if (direction == NORTH) -scanAhead else -1 + val endZ = if (direction == NORTH) 1 else scanAhead + val nudgeX = calculateNudge(world, startZ, endZ, + { z -> BlockPos(rootX - 1, rootY, rootZ + z) }, + { z -> BlockPos(rootX + 1, rootY, rootZ + z) } + ) + boat.setPosition(rootX + 0.5 + nudgeX, boat.y, boat.z) + } else { + val startX = if (direction == WEST) -scanAhead else -1 + val endX = if (direction == WEST) 1 else scanAhead + val nudgeZ = calculateNudge(world, startX, endX, + { x -> BlockPos(rootX + x, rootY, rootZ - 1) }, + { x -> BlockPos(rootX + x, rootY, rootZ + 1) } + ) + boat.setPosition(boat.x, boat.y, rootZ + 0.5 + nudgeZ) + } + } + + private fun calculateNudge(world: World, start: Int, end: Int, leftBlockPosFunc: Function, rightBlockPosFunc: Function): Double { + var nudge = 0 + for (i in start..end) { + val leftBlockPos = leftBlockPosFunc.apply(i) + val rightBlockPos = rightBlockPosFunc.apply(i) + if (world.getBlockState(leftBlockPos).block !is AirBlock) + nudge += 1 + if (world.getBlockState(rightBlockPos).block !is AirBlock) + nudge -= 1 + } + return MathHelper.clamp(nudge.toDouble(), -0.2, 0.2) + } +} diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt new file mode 100644 index 0000000..546126b --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt @@ -0,0 +1,65 @@ +package net.cardinalboats + +import net.cardinalboats.config.CIBConfig +import net.minecraft.block.BlockState +import net.minecraft.client.network.ClientPlayerEntity +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.vehicle.AbstractBoatEntity +import net.minecraft.text.Text +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.HitResult +import net.minecraft.util.math.Vec3d +import net.minecraft.world.World +import java.util.regex.Pattern + +import net.minecraft.util.math.MathHelper.RADIANS_PER_DEGREE + +private val icePattern = Pattern.compile("(\\b|_)ice\\b", Pattern.CASE_INSENSITIVE) + +@JvmField +public var lieAboutMovingForward = false; + +fun rotateBoat(boat: AbstractBoatEntity, rotation: Float, maintainVelocity: Boolean) { + boat.yaw = rotation + boat.yawVelocity = 0f + boat.controllingPassenger?.yaw = boat.yaw + + if (maintainVelocity) { + // get current velocity vector length + val currentVelocity = boat.velocity.length() + // create new vector normalized to rotation + val newVelocity = Vec3d(0.0, 0.0, currentVelocity).rotateY(-rotation * RADIANS_PER_DEGREE) // Trig magic + // give boat new thing + boat.velocity = newVelocity + } else { + boat.velocity = Vec3d.ZERO + } +} + +fun isIce(blockState: BlockState): Boolean { + return icePattern.matcher(blockState.block.toString()).find() +} + +fun clientChatLog(player: ClientPlayerEntity?, message: String) { + if (player == null) return + + if (CIBConfig.getInstance().doChatShit) { + player.sendMessage(Text.of("[cardinalboats] $message"), false) + } +} + +@Suppress("MagicNumber") +fun shouldSnap(level: World, player: PlayerEntity): Boolean { + // If we are putting a boat on a block + val lookingAt = player.raycast(20.0, 0.0f, false) + if (lookingAt != null && lookingAt.type == HitResult.Type.BLOCK) { + // If that block is ice, return true + return isIce(level.getBlockState((lookingAt as BlockHitResult).blockPos)) + } + return false +} + +@Suppress("MagicNumber") +fun roundYRot(yRot: Float, toNearest: Int): Float { + return (Math.round(yRot % 360 / toNearest) * toNearest).toFloat() +} diff --git a/platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener b/platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener new file mode 100644 index 0000000..b7793ec --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener @@ -0,0 +1,3 @@ +accessWidener v1 named + +accessible field net/minecraft/entity/vehicle/AbstractBoatEntity yawVelocity F diff --git a/platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json b/platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json new file mode 100644 index 0000000..fb9d1bd --- /dev/null +++ b/platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.cardinalboats.mixin", + "compatibilityLevel": "JAVA_21", + "client": [ + "ChatMoveLie", + "ChatMoveStartLying" + ], + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + "BoatPlacementSnap" + ] +} diff --git a/platforms/fabric-1.21.5/src/modloader b/platforms/fabric-1.21.5/src/modloader new file mode 120000 index 0000000..d24a001 --- /dev/null +++ b/platforms/fabric-1.21.5/src/modloader @@ -0,0 +1 @@ +../../shared/modloader/fabric/src/main \ No newline at end of file diff --git a/platforms/fabric-1.21.5/src/shared b/platforms/fabric-1.21.5/src/shared new file mode 120000 index 0000000..e990e09 --- /dev/null +++ b/platforms/fabric-1.21.5/src/shared @@ -0,0 +1 @@ +../../shared/main \ No newline at end of file diff --git a/platforms/shared/integrations/modmenu/src/main/kotlin/net/cardinalboats/integration/modmenu/CIBModMenu.kt b/platforms/shared/integrations/modmenu/src/main/kotlin/net/cardinalboats/integration/modmenu/CIBModMenu.kt new file mode 100644 index 0000000..046db9f --- /dev/null +++ b/platforms/shared/integrations/modmenu/src/main/kotlin/net/cardinalboats/integration/modmenu/CIBModMenu.kt @@ -0,0 +1,16 @@ +package net.cardinalboats.integration.modmenu + +import com.terraformersmc.modmenu.api.ConfigScreenFactory +import com.terraformersmc.modmenu.api.ModMenuApi +import me.shedaniel.autoconfig.AutoConfig +import net.cardinalboats.config.CIBConfig + +class CIBModMenu: ModMenuApi { + + override fun getModConfigScreenFactory(): ConfigScreenFactory<*>? { + return ConfigScreenFactory { + AutoConfig.getConfigScreen(CIBConfig::class.java, it).get() + } + } + +} diff --git a/platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java b/platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java new file mode 100644 index 0000000..19b92ed --- /dev/null +++ b/platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java @@ -0,0 +1,42 @@ +package net.cardinalboats.config; + +import me.shedaniel.autoconfig.AutoConfig; +import me.shedaniel.autoconfig.ConfigData; + + +import me.shedaniel.autoconfig.annotation.Config; +import me.shedaniel.autoconfig.annotation.ConfigEntry; +import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer; + +@Config(name = "CardinalBoat") +public class CIBConfig implements ConfigData { + @ConfigEntry.Gui.Tooltip + public boolean doChatShit = true; + + @ConfigEntry.Gui.Tooltip + public boolean maintainVelocityOnTurns = false; + + @ConfigEntry.Gui.Tooltip + public boolean eightWaySnapKey = true; + + @ConfigEntry.Gui.Tooltip + public boolean moveWhileChatting = true; + + @ConfigEntry.Gui.Tooltip + public boolean alwaysSmartCenter = false; + + @ConfigEntry.Gui.Tooltip + @ConfigEntry.BoundedDiscrete(min = 1, max = 10) + public int smartCenterLookAhead = 5; + + @ConfigEntry.Gui.Tooltip + public boolean smartCenterPrimedTurn = true; + + public static void init() { + AutoConfig.register(CIBConfig.class, Toml4jConfigSerializer::new); + } + + public static CIBConfig getInstance() { + return AutoConfig.getConfigHolder(CIBConfig.class).getConfig(); + } +} diff --git a/platforms/shared/main/resources/assets/cardinalboats/icon.png b/platforms/shared/main/resources/assets/cardinalboats/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9de402a095b427f1416662c6e118684807e5f1ef GIT binary patch literal 58126 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 BlD_}| literal 0 HcmV?d00001 diff --git a/platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json b/platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json new file mode 100644 index 0000000..c5eff47 --- /dev/null +++ b/platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json @@ -0,0 +1,43 @@ +{ + "category.cardinalboats.key_category_title" : "Cardinal Ice Boats", + + "key.cardinalboats.snapManual" : "Re-Snap", + "key.cardinalboats.snap180" : "Instant Reverse", + "key.cardinalboats.smartCenter" : "Smart Center", + + "key.cardinalboats.prime_left": "Prime Left Turn", + "key.cardinalboats.prime_right": "Prime Right Turn", + + "info.cardinalboats.left_turn_queue" : "Left Turn Primed", + "info.cardinalboats.right_turn_queue" : "Right Turn Primed", + + "info.cardinalboats.left_turn_complete" : "Left Turn Completed", + "info.cardinalboats.right_turn_complete" : "Right Turn Completed", + + "info.cardinalboats.cancel" : "Primed turn cancelled. Player left boat.", + + "text.autoconfig.CardinalBoat.option.doChatShit" : "Print primed turn logs to chat", + "text.autoconfig.CardinalBoat.option.doChatShit.@Tooltip" : "Prints primed, completed, and cancelled messages to the chat.", + + "text.autoconfig.CardinalBoat.option.maintainVelocityOnTurns" : "Maintain Velocity on Primed Turns", + "text.autoconfig.CardinalBoat.option.maintainVelocityOnTurns.@Tooltip" : "Maintains forward velocity on Primed Turns, similar to the snap key.\nMay not work well on laggy servers.\n§4OP as f§ku§r§4ck, may get you banned.", + + "text.autoconfig.CardinalBoat.option.eightWaySnapKey" : "Snap Key Directionality", + "text.autoconfig.CardinalBoat.option.eightWaySnapKey.@Tooltip" : "§bEight-Way§r - Pressing Snap Key will align boat to nearest 45°\n§6Four-Way§r - Pressing Snap Key will align boat to nearest 90°", + "text.autoconfig.CardinalBoat.option.eightWaySnapKey.boolean.true" : "§bEight-Way", + "text.autoconfig.CardinalBoat.option.eightWaySnapKey.boolean.false" : "§6Four-Way", + + "text.autoconfig.CardinalBoat.option.alwaysSmartCenter" : "Always Smart Center", + "text.autoconfig.CardinalBoat.option.alwaysSmartCenter.@Tooltip" : "Runs smart center all the time when boat is perfectly cardinally aligned", + + "text.autoconfig.CardinalBoat.option.smartCenterLookAhead" : "Smart Center Lookahead", + "text.autoconfig.CardinalBoat.option.smartCenterLookAhead.@Tooltip" : "Number of blocks ahead of you that smart center scans for walls.", + + "text.autoconfig.CardinalBoat.option.smartCenterPrimedTurn" : "Smart Center on Primed Turns", + "text.autoconfig.CardinalBoat.option.smartCenterPrimedTurn.@Tooltip" : "Boat will automatically smart center itself after taking a primed turn", + + "text.autoconfig.CardinalBoat.option.moveWhileChatting" : "Keep Moving While Chatting", + "text.autoconfig.CardinalBoat.option.moveWhileChatting.@Tooltip" : "Allows you to chat while driving a boat.\nIf you open the chat while moving forward, it keeps moving forward for you.\n§mDon't text and drive.", + + "text.autoconfig.CardinalBoat.title" : "Cardinal Ice Boats Config" +} diff --git a/platforms/shared/modloader/fabric/src/main/resources/fabric.mod.json b/platforms/shared/modloader/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..3a86c90 --- /dev/null +++ b/platforms/shared/modloader/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,24 @@ +{ + "schemaVersion": 1, + "id": "@MODID@", + "version": @VERSION@, + "name": @DISPLAY_NAME@, + "description": @DESCRIPTION@, + @AUTHORS@ + @CONTRIBUTORS@ + "contact": { + "homepage": @WIKI@, + "issues": @ISSUES@ + }, + "license": @LICENSE@, + "icon": @ICON@, + "environment": "client", + "entrypoints": { + @ENTRY_POINTS@ + }, + @MIXINS@ + @ACCESS_WIDENER@ + "depends": { + @GENERATED_DEPENDENCIES@ + } +} diff --git a/platforms/shared/modloader/forge/src/main/resources/META-INF/mods.toml b/platforms/shared/modloader/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..7f805c9 --- /dev/null +++ b/platforms/shared/modloader/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,28 @@ +modLoader="kotlinforforge" +loaderVersion="[@KFF_LOADER_VERSION@,)" + +issueTrackerURL=@ISSUES@ + +license=@LICENSE@ + +[[mods]] +modId="@MODID@" +version=@VERSION@ +displayName=@DISPLAY_NAME@ +displayURL=@WIKI@ +logoFile=@ICON@ +credits=''' +@CONTRIBUTORS@ +''' +authors=''' +@AUTHORS@ +''' + +description=''' +@DESCRIPTION@ +''' + +[[mixins]] +config="mixins.@MODID@.json" + +@GENERATED_DEPENDENCIES@ diff --git a/platforms/shared/modloader/forge/src/main/resources/pack.mcmeta b/platforms/shared/modloader/forge/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..9054a8c --- /dev/null +++ b/platforms/shared/modloader/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "InvTweaks Emu for IPN", + "pack_format": 4, + "_comment": "A pack_format of 4 requires json lang files. Note: we require v4 pack meta for all mods." + } +} diff --git a/platforms/shared/modloader/neoforge/src/main/resources/META-INF/accesstransformer.cfg b/platforms/shared/modloader/neoforge/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..25eb005 --- /dev/null +++ b/platforms/shared/modloader/neoforge/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,10 @@ +public net.minecraft.client.gui.screens.inventory.MerchantScreen f_99118_ # tradeOfferButtons +public net.minecraft.client.gui.screens.inventory.MerchantScreen f_99119_ # scrollOff +public net.minecraft.client.gui.screens.inventory.MerchantScreen f_99117_ # shopItem +public net.minecraft.client.gui.screens.inventory.MerchantScreen m_99200_()V # postButtonClick +public net.minecraft.client.gui.screens.inventory.MerchantScreen$TradeOfferButton +public net.minecraft.world.inventory.ItemCombinerMenu f_266110_ # inputSlotIndexes +public net.minecraft.world.inventory.ItemCombinerMenu f_266048_ # resultSlotIndex +public net.minecraft.world.inventory.ItemCombinerMenu f_39769_ # inputSlots +public net.minecraft.client.gui.screens.inventory.AnvilScreen f_97871_ # name +public net.minecraft.world.item.ItemStack (Lnet/minecraft/world/level/ItemLike;ILnet/minecraft/core/component/PatchedDataComponentMap;)V diff --git a/platforms/shared/modloader/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/platforms/shared/modloader/neoforge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..67e0735 --- /dev/null +++ b/platforms/shared/modloader/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,29 @@ +modLoader="kotlinforforge" +loaderVersion="[@KFF_LOADER_VERSION@,)" + +issueTrackerURL=@ISSUES@ + +license=@LICENSE@ + +[[mods]] +modId="@MODID@" +version=@VERSION@ +displayName=@DISPLAY_NAME@ +displayURL=@WIKI@ +logoFile=@ICON@ +credits=''' +@CONTRIBUTORS@ +''' +authors=''' +@AUTHORS@ +''' + +description=''' +@DESCRIPTION@ +''' + +@ACCESS_TRANSFORMER_FILES@ + +@MIXINS@ + +@GENERATED_DEPENDENCIES@ diff --git a/platforms/shared/modloader/neoforge/src/main/resources/pack.mcmeta b/platforms/shared/modloader/neoforge/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..9054a8c --- /dev/null +++ b/platforms/shared/modloader/neoforge/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "InvTweaks Emu for IPN", + "pack_format": 4, + "_comment": "A pack_format of 4 requires json lang files. Note: we require v4 pack meta for all mods." + } +} From efd5f981b1e7c0ff8921a60132be2b8128564cb3 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:51:15 +0300 Subject: [PATCH 04/10] Updated github workflow. --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e923916..4f39e14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,8 @@ jobs: os: [ubuntu-22.04] runs-on: ${{ matrix.os }} steps: + - name: install advzip + run: apt install advzip - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper @@ -33,4 +35,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: Artifacts - path: build/libs/ + path: build/optimized-mod/ From 784ec8e1ba01731f2b50c67b527640df3eafed82 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:54:52 +0300 Subject: [PATCH 05/10] Hopefully fix the github action. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f39e14..c7cddee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: install advzip - run: apt install advzip + run: sudo apt-get install advzip - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper From 5da86af5abdcde63884702abbdd5963d34fdc309 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 14:57:01 +0300 Subject: [PATCH 06/10] finger crossed. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c7cddee..ebd285f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: install advzip - run: sudo apt-get install advzip + run: sudo apt-get install advancecomp - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper From 092cbb45086e7cec4e3e9c92df6ff69dc3f632cf Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 15:02:06 +0300 Subject: [PATCH 07/10] Update the gradle wrapper validation action. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ebd285f..2dc141b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: - name: checkout repository uses: actions/checkout@v4 - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/actions/wrapper-validation@v3.5.0 - name: setup jdk ${{ matrix.java }} uses: actions/setup-java@v4 with: From 9672403b079cb8017490d5960d8db90c55d92806 Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 16:20:18 +0300 Subject: [PATCH 08/10] fix artifacts collection. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2dc141b..252c150 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,4 +35,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: Artifacts - path: build/optimized-mod/ + path: platforms/**/build/optimized-mod/ From ba685e4bb6082977a99d8b82cf473c9a729be08a Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 16:47:54 +0300 Subject: [PATCH 09/10] final touches and proper Minecraft version. --- build.gradle.kts | 6 +++--- gradle/libs.versions.toml | 4 +++- .../{fabric-1.21.5 => fabric-1.21.6}/.gitignore | 0 .../build.gradle.kts | 12 +++++------- .../gradle.properties | 0 .../src/integrations/modmenu | 0 .../net/cardinalboats/mixin/BoatPlacementSnap.java | 0 .../java/net/cardinalboats/mixin/ChatMoveLie.java | 0 .../net/cardinalboats/mixin/ChatMoveStartLying.java | 0 .../kotlin/net/cardinalboats/CardinalBoatsInit.kt | 0 .../src/main/kotlin/net/cardinalboats/ManualSnap.kt | 0 .../src/main/kotlin/net/cardinalboats/TurnPriming.kt | 0 .../src/main/kotlin/net/cardinalboats/Util.kt | 0 .../src/main/resources/cardinalboats.accesswidener | 0 .../src/main/resources/cardinalboats.mixins.json | 0 .../{fabric-1.21.5 => fabric-1.21.6}/src/modloader | 0 .../{fabric-1.21.5 => fabric-1.21.6}/src/shared | 0 settings.gradle.kts | 2 +- 18 files changed, 12 insertions(+), 12 deletions(-) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/.gitignore (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/build.gradle.kts (63%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/gradle.properties (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/integrations/modmenu (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/kotlin/net/cardinalboats/ManualSnap.kt (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/kotlin/net/cardinalboats/TurnPriming.kt (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/kotlin/net/cardinalboats/Util.kt (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/resources/cardinalboats.accesswidener (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/main/resources/cardinalboats.mixins.json (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/modloader (100%) rename platforms/{fabric-1.21.5 => fabric-1.21.6}/src/shared (100%) diff --git a/build.gradle.kts b/build.gradle.kts index f6cb9d8..6bcb870 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { alias(libs.plugins.detekt) alias(libs.plugins.shadow) apply false alias(libs.plugins.loom) apply false - id("libipn-gradle") version "1.0.0-SNAPSHOT" apply false + alias(libs.plugins.libipnGradle) apply false } configurations.all { @@ -16,7 +16,7 @@ configurations.all { subprojects { - group = "org.anti_ad.mc" + group = "net.cardinalboats" apply { plugin(rootProject.libs.plugins.detekt.get().pluginId) } @@ -24,7 +24,7 @@ subprojects { detekt { config.setFrom(rootProject.files("config/detekt/detekt.yml")) } - version = "1.0.0" + version = "2.0.0" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a3e477..cdfb767 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,8 @@ detekt = "1+" kotlin = "2.0.21" shadowVer = "8.+" -loomVer = "1.9-SNAPSHOT" +loomVer = "1.10-SNAPSHOT" +libipnGradleVer = "1.0.0-SNAPSHOT" [plugins] detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"} @@ -10,3 +11,4 @@ kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"} kotlinSer = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"} shadow = { id = "com.gradleup.shadow", version.ref = "shadowVer"} loom = { id = "fabric-loom", version.ref = "loomVer"} +libipnGradle = { id = "libipn-gradle", version.ref = "libipnGradleVer" } diff --git a/platforms/fabric-1.21.5/.gitignore b/platforms/fabric-1.21.6/.gitignore similarity index 100% rename from platforms/fabric-1.21.5/.gitignore rename to platforms/fabric-1.21.6/.gitignore diff --git a/platforms/fabric-1.21.5/build.gradle.kts b/platforms/fabric-1.21.6/build.gradle.kts similarity index 63% rename from platforms/fabric-1.21.5/build.gradle.kts rename to platforms/fabric-1.21.6/build.gradle.kts index fe438ee..c4f92eb 100644 --- a/platforms/fabric-1.21.5/build.gradle.kts +++ b/platforms/fabric-1.21.6/build.gradle.kts @@ -1,9 +1,5 @@ -import org.anti_ad.gradle.plugins.libipn.base.modId - val cloth_config_version: String by project -logger.lifecycle(""" - mod-id: $modId -""".trimIndent()) + repositories { maven ("https://maven.shedaniel.me/") } @@ -18,11 +14,13 @@ configurations.all { } plugins { - id("libipn-gradle") + alias(libs.plugins.libipnGradle) } libIPN { + this.enableShadow = false + this.enableProGuard = false jarPostProcessConfig = { - this.advzipArguments = mutableListOf("-4", "-z", "-i", "100") + this.advzipArguments = listOf("-4", "-z", "-i", "100") } } diff --git a/platforms/fabric-1.21.5/gradle.properties b/platforms/fabric-1.21.6/gradle.properties similarity index 100% rename from platforms/fabric-1.21.5/gradle.properties rename to platforms/fabric-1.21.6/gradle.properties diff --git a/platforms/fabric-1.21.5/src/integrations/modmenu b/platforms/fabric-1.21.6/src/integrations/modmenu similarity index 100% rename from platforms/fabric-1.21.5/src/integrations/modmenu rename to platforms/fabric-1.21.6/src/integrations/modmenu diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java similarity index 100% rename from platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java similarity index 100% rename from platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java diff --git a/platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java similarity index 100% rename from platforms/fabric-1.21.5/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt similarity index 100% rename from platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt rename to platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/ManualSnap.kt similarity index 100% rename from platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/ManualSnap.kt rename to platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/ManualSnap.kt diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/TurnPriming.kt similarity index 100% rename from platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/TurnPriming.kt rename to platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/TurnPriming.kt diff --git a/platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/Util.kt similarity index 100% rename from platforms/fabric-1.21.5/src/main/kotlin/net/cardinalboats/Util.kt rename to platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/Util.kt diff --git a/platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener b/platforms/fabric-1.21.6/src/main/resources/cardinalboats.accesswidener similarity index 100% rename from platforms/fabric-1.21.5/src/main/resources/cardinalboats.accesswidener rename to platforms/fabric-1.21.6/src/main/resources/cardinalboats.accesswidener diff --git a/platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json b/platforms/fabric-1.21.6/src/main/resources/cardinalboats.mixins.json similarity index 100% rename from platforms/fabric-1.21.5/src/main/resources/cardinalboats.mixins.json rename to platforms/fabric-1.21.6/src/main/resources/cardinalboats.mixins.json diff --git a/platforms/fabric-1.21.5/src/modloader b/platforms/fabric-1.21.6/src/modloader similarity index 100% rename from platforms/fabric-1.21.5/src/modloader rename to platforms/fabric-1.21.6/src/modloader diff --git a/platforms/fabric-1.21.5/src/shared b/platforms/fabric-1.21.6/src/shared similarity index 100% rename from platforms/fabric-1.21.5/src/shared rename to platforms/fabric-1.21.6/src/shared diff --git a/settings.gradle.kts b/settings.gradle.kts index d941db1..da31b12 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -86,7 +86,7 @@ dependencyResolutionManagement { rootProject.name = "CardinalIceBoats" -include(":platforms:fabric-1.21.5") +include(":platforms:fabric-1.21.6") //include(":platforms:forge-1.21.5") //include(":platforms:neoforge-1.21.5") From 5873d40cfc90400ce8a93c4b5db78cda5aabc2bd Mon Sep 17 00:00:00 2001 From: "Plamen K. Kosseff" Date: Sun, 29 Jun 2025 17:43:42 +0300 Subject: [PATCH 10/10] added automatic release to modrinth added changes log added automatic release notes --- changelog.md | 13 ++++ description/.gitignore | 2 + description/build_release_notes.py | 23 ++++++ do-release.sh | 96 ++++++++++++++++++++++++ gradle/libs.versions.toml | 2 + platforms/fabric-1.21.6/build.gradle.kts | 42 +++++++++++ 6 files changed, 178 insertions(+) create mode 100644 changelog.md create mode 100644 description/.gitignore create mode 100644 description/build_release_notes.py create mode 100755 do-release.sh diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..506dafe --- /dev/null +++ b/changelog.md @@ -0,0 +1,13 @@ + + +### 2.0.0 + +- support for 1.21.6 +- now implemented in Kotlin +- new requirement [Fabric Language Kotlin](https://modrinth.com/mod/fabric-language-kotlin) + + + + + + diff --git a/description/.gitignore b/description/.gitignore new file mode 100644 index 0000000..a4bb503 --- /dev/null +++ b/description/.gitignore @@ -0,0 +1,2 @@ +out +venv diff --git a/description/build_release_notes.py b/description/build_release_notes.py new file mode 100644 index 0000000..c821866 --- /dev/null +++ b/description/build_release_notes.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +#-*- coding: utf-8 -*- + +import pypandoc +from pathlib import Path + +def main(): + Path("out/debug").mkdir(parents=True, exist_ok=True) + + html = pypandoc.convert_file( + "release_notes.md", + "md", + format="md", + extra_args=["--wrap=preserve"], + filters=["pandoc-include"] + ) + + with open("out/pandoc-release_notes.md", "wb") as f: + f.write(html.encode("utf-8")) + + +if __name__ == "__main__": + main() diff --git a/do-release.sh b/do-release.sh new file mode 100755 index 0000000..1141ec1 --- /dev/null +++ b/do-release.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# +# Inventory Profiles Next +# +# Copyright (c) 2024 Plamen K. Kosseff +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +if [[ n$IPNEXT_RELEASE != "n" ]]; then + . ~/.config/secrets/modrinth.sh + . ~/.config/secrets/curseforge.sh +fi + + +PROJECT_URL=$(git remote get-url origin) +PROJECT_NAME="CardinalIceBoats" + +BUILD_PATH="" + +if [[ n$1 != "n" ]]; then + BUILD_PATH="$1:" +fi + +echo "BUILD_PATH=${BUILD_PATH}" + +pushd . + +mkdir /tmp/IPN +cd /tmp/IPN + +if [[ -e /tmp/IPN/${PROJECT_NAME} ]]; then + rm -rf /tmp/IPN/${PROJECT_NAME} +fi + +git clone ${PROJECT_URL} ${PROJECT_NAME} + +if [[ ! -e ../venv ]]; then + python -m venv ../venv + . ../venv/bin/activate + pip install pandoc + pip install pypandoc + pip install premailer + pip install pandoc_include +else + . ../venv/bin/activate +fi + +cd ${PROJECT_NAME}/description + +python build_html.py +python build_release_notes.py + +cd .. + +export _JAVA_OPTIONS=-Xmx8G + +GRADLE_ARG="--exclude-task compileTestJava --exclude-task test ${BUILD_PATH}build" + + +if [[ n${IPNEXT_M} != "n" ]]; then + GRADLE_ARG="${GRADLE_ARG} ${BUILD_PATH}modrinth" +fi + +if [[ n${IPNEXT_C} != "n" ]]; then + GRADLE_ARG="${GRADLE_ARG} ${BUILD_PATH}curseforge" +fi + +if [[ n${IPNEXT_P} != "n" ]]; then + GRADLE_ARG="${GRADLE_ARG} ${BUILD_PATH}publishAllPublicationsToIpnOfficialRepoRepository" +fi + + +GRADLE_ARG="--max-workers 32 ${GRADLE_ARG}" + +echo will run "./gradlew ${GRADLE_ARG}" +echo + +./gradlew ${GRADLE_ARG} + + +pwd + +popd diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdfb767..1288ba9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ kotlin = "2.0.21" shadowVer = "8.+" loomVer = "1.10-SNAPSHOT" libipnGradleVer = "1.0.0-SNAPSHOT" +modrinthVer = "2.+" [plugins] detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt"} @@ -12,3 +13,4 @@ kotlinSer = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "k shadow = { id = "com.gradleup.shadow", version.ref = "shadowVer"} loom = { id = "fabric-loom", version.ref = "loomVer"} libipnGradle = { id = "libipn-gradle", version.ref = "libipnGradleVer" } +modrinth = { id = "com.modrinth.minotaur", version.ref = "modrinthVer"} diff --git a/platforms/fabric-1.21.6/build.gradle.kts b/platforms/fabric-1.21.6/build.gradle.kts index c4f92eb..b894b04 100644 --- a/platforms/fabric-1.21.6/build.gradle.kts +++ b/platforms/fabric-1.21.6/build.gradle.kts @@ -1,3 +1,6 @@ +import com.modrinth.minotaur.dependencies.ModDependency +import org.anti_ad.gradle.plugins.libipn.base.JarPostProcess + val cloth_config_version: String by project repositories { @@ -15,6 +18,7 @@ configurations.all { plugins { alias(libs.plugins.libipnGradle) + alias(libs.plugins.modrinth) } libIPN { @@ -24,3 +28,41 @@ libIPN { this.advzipArguments = listOf("-4", "-z", "-i", "100") } } + + +afterEvaluate { + modrinth { + val mod_loader = libIPN.modLoader.get() + val mod_version = libIPN.modVersion.get() + val minecraft_version = libIPN.supportedMinecraftVersionMin.get() + + this.failSilently.set(true) + + if (System.getenv("IPNEXT_RELEASE") != null) { + token.set(System.getenv("MODRINTH_TOKEN")) + } + + projectId.set("1m9s2ZhL") + versionNumber.set("$mod_loader-$minecraft_version-$mod_version") // Will fail if Modrinth has this version already + val postprocessedremappedJarFile = tasks.named("libIPN-JarPostProcess").get().outputs.files.first() + uploadFile.set(postprocessedremappedJarFile as Any) // This is the java jar task. If it can't find the jar, try 'jar.outputs.getFiles().asPath' in place of 'jar' + gameVersions.addAll(minecraft_version) + logger.lifecycle(""" + +*************************************************+ + Will release ${postprocessedremappedJarFile.path} + +*************************************************+ + """.trimIndent()) + versionName.set("CardinalIceBoats $mod_version for $mod_loader $minecraft_version") + project.rootDir.resolve("description/out/pandoc-release_notes.md").takeIf { it.exists() }?.let { + this.changelog.set(it.readText()) + } + + loaders.add(mod_loader) + dependencies.set(mutableListOf(ModDependency("P7dR8mSH", "required"), + ModDependency("Ha28R6CL", "required"), + ModDependency("9s6osm5g", "required"), + ModDependency("mOgUt4GM", "optional"))) + + this.versionType.set(masecla.modrinth4j.model.version.ProjectVersion.VersionType.RELEASE.name) + } +}