diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e923916..252c150 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,10 +16,12 @@ jobs: os: [ubuntu-22.04] runs-on: ${{ matrix.os }} steps: + - name: install advzip + run: sudo apt-get install advancecomp - 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: @@ -33,4 +35,4 @@ jobs: uses: actions/upload-artifact@v4 with: name: Artifacts - path: build/libs/ + path: platforms/**/build/optimized-mod/ 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/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..6bcb870 --- /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 + alias(libs.plugins.libipnGradle) apply false +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, "seconds") +} + + + +subprojects { + group = "net.cardinalboats" + apply { + plugin(rootProject.libs.plugins.detekt.get().pluginId) + } + + detekt { + config.setFrom(rootProject.files("config/detekt/detekt.yml")) + } + version = "2.0.0" + +} + +tasks.withType().configureEach { + reports { + html.required.set(true) + html.outputLocation.set(file("build/reports/detekt.html")) + } +} 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/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/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.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..1288ba9 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,16 @@ +[versions] +detekt = "1+" +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"} +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" } +modrinth = { id = "com.modrinth.minotaur", version.ref = "modrinthVer"} 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/platforms/fabric-1.21.6/.gitignore b/platforms/fabric-1.21.6/.gitignore new file mode 100644 index 0000000..73c9b8f --- /dev/null +++ b/platforms/fabric-1.21.6/.gitignore @@ -0,0 +1,4 @@ +runs/ +.gradle/ +build/ +run/ diff --git a/platforms/fabric-1.21.6/build.gradle.kts b/platforms/fabric-1.21.6/build.gradle.kts new file mode 100644 index 0000000..b894b04 --- /dev/null +++ b/platforms/fabric-1.21.6/build.gradle.kts @@ -0,0 +1,68 @@ +import com.modrinth.minotaur.dependencies.ModDependency +import org.anti_ad.gradle.plugins.libipn.base.JarPostProcess + +val cloth_config_version: String by project + +repositories { + maven ("https://maven.shedaniel.me/") +} + + +dependencies { + modImplementation ("me.shedaniel.cloth:cloth-config-fabric:$cloth_config_version") +} + +configurations.all { + resolutionStrategy.cacheChangingModulesFor(0, "seconds") +} + +plugins { + alias(libs.plugins.libipnGradle) + alias(libs.plugins.modrinth) +} + +libIPN { + this.enableShadow = false + this.enableProGuard = false + jarPostProcessConfig = { + 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) + } +} diff --git a/platforms/fabric-1.21.6/gradle.properties b/platforms/fabric-1.21.6/gradle.properties new file mode 100644 index 0000000..848d76c --- /dev/null +++ b/platforms/fabric-1.21.6/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.6/src/integrations/modmenu b/platforms/fabric-1.21.6/src/integrations/modmenu new file mode 120000 index 0000000..f1355b4 --- /dev/null +++ b/platforms/fabric-1.21.6/src/integrations/modmenu @@ -0,0 +1 @@ +../../../shared/integrations/modmenu \ No newline at end of file diff --git a/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java similarity index 88% rename from src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java index 2305af1..fc769fc 100644 --- a/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java +++ b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/BoatPlacementSnap.java @@ -7,11 +7,12 @@ 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; +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")) diff --git a/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java similarity index 84% rename from src/main/java/net/cardinalboats/mixin/ChatMoveLie.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java index 9941e67..af6fb57 100644 --- a/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java +++ b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveLie.java @@ -8,19 +8,20 @@ import net.minecraft.client.gui.screen.ChatScreen; import net.minecraft.client.input.KeyboardInput; -import static net.cardinalboats.CardinalBoatsInit.LieAboutMovingForward; +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 (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; + lieAboutMovingForward = false; } } return original; diff --git a/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java similarity index 83% rename from src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java rename to platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java index 85494f5..30611b1 100644 --- a/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java +++ b/platforms/fabric-1.21.6/src/main/java/net/cardinalboats/mixin/ChatMoveStartLying.java @@ -1,6 +1,6 @@ package net.cardinalboats.mixin; -import net.cardinalboats.config.ModConfig; +import net.cardinalboats.config.CIBConfig; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.entity.vehicle.AbstractBoatEntity; @@ -10,8 +10,7 @@ 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; +import static net.cardinalboats.UtilKt.lieAboutMovingForward; @Mixin(value = MinecraftClient.class, priority = 1000) public abstract class ChatMoveStartLying { @@ -22,11 +21,11 @@ void moveChatBoi(CallbackInfo ci) { // on opening the chat assert this.player != null; - if (player.getVehicle() instanceof AbstractBoatEntity && ModConfig.getInstance().moveWhileChatting) { + 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; + lieAboutMovingForward = true; } } } diff --git a/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/CardinalBoatsInit.kt new file mode 100644 index 0000000..ff4a456 --- /dev/null +++ b/platforms/fabric-1.21.6/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.6/src/main/kotlin/net/cardinalboats/ManualSnap.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/ManualSnap.kt new file mode 100644 index 0000000..913a877 --- /dev/null +++ b/platforms/fabric-1.21.6/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.6/src/main/kotlin/net/cardinalboats/TurnPriming.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/TurnPriming.kt new file mode 100644 index 0000000..39b0f1a --- /dev/null +++ b/platforms/fabric-1.21.6/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.6/src/main/kotlin/net/cardinalboats/Util.kt b/platforms/fabric-1.21.6/src/main/kotlin/net/cardinalboats/Util.kt new file mode 100644 index 0000000..546126b --- /dev/null +++ b/platforms/fabric-1.21.6/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/src/main/resources/cardinalboats.accesswidener b/platforms/fabric-1.21.6/src/main/resources/cardinalboats.accesswidener similarity index 100% rename from src/main/resources/cardinalboats.accesswidener rename to platforms/fabric-1.21.6/src/main/resources/cardinalboats.accesswidener diff --git a/src/main/resources/cardinalboats.mixins.json b/platforms/fabric-1.21.6/src/main/resources/cardinalboats.mixins.json similarity index 100% rename from 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.6/src/modloader b/platforms/fabric-1.21.6/src/modloader new file mode 120000 index 0000000..d24a001 --- /dev/null +++ b/platforms/fabric-1.21.6/src/modloader @@ -0,0 +1 @@ +../../shared/modloader/fabric/src/main \ No newline at end of file diff --git a/platforms/fabric-1.21.6/src/shared b/platforms/fabric-1.21.6/src/shared new file mode 120000 index 0000000..e990e09 --- /dev/null +++ b/platforms/fabric-1.21.6/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/src/main/java/net/cardinalboats/config/ModConfig.java b/platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java similarity index 78% rename from src/main/java/net/cardinalboats/config/ModConfig.java rename to platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java index 6ddaa57..19b92ed 100644 --- a/src/main/java/net/cardinalboats/config/ModConfig.java +++ b/platforms/shared/main/java/net/cardinalboats/config/CIBConfig.java @@ -9,7 +9,7 @@ import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer; @Config(name = "CardinalBoat") -public class ModConfig implements ConfigData { +public class CIBConfig implements ConfigData { @ConfigEntry.Gui.Tooltip public boolean doChatShit = true; @@ -33,10 +33,10 @@ public class ModConfig implements ConfigData { public boolean smartCenterPrimedTurn = true; public static void init() { - AutoConfig.register(ModConfig.class, Toml4jConfigSerializer::new); + AutoConfig.register(CIBConfig.class, Toml4jConfigSerializer::new); } - public static ModConfig getInstance() { - return AutoConfig.getConfigHolder(ModConfig.class).getConfig(); + public static CIBConfig getInstance() { + return AutoConfig.getConfigHolder(CIBConfig.class).getConfig(); } } diff --git a/src/main/resources/assets/cardinalboats/icon.png b/platforms/shared/main/resources/assets/cardinalboats/icon.png similarity index 100% rename from src/main/resources/assets/cardinalboats/icon.png rename to platforms/shared/main/resources/assets/cardinalboats/icon.png diff --git a/src/main/resources/assets/cardinalboats/lang/en_us.json b/platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json similarity index 100% rename from src/main/resources/assets/cardinalboats/lang/en_us.json rename to platforms/shared/main/resources/assets/cardinalboats/lang/en_us.json 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." + } +} 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/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..da31b12 --- /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.6") +//include(":platforms:forge-1.21.5") +//include(":platforms:neoforge-1.21.5") + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.+" +} + 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/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/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" - } -}