diff --git a/build.gradle b/build.gradle index a9c2c24..ee4213a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,412 +1,67 @@ -//version: 1699290261 -/* - DO NOT CHANGE THIS FILE! - Also, you may replace this file at any time if there is an update available. - Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/master/build.gradle for updates. - */ - - -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.gtnewhorizons.retrofuturagradle.ObfuscationAttribute -import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar -import com.gtnewhorizons.retrofuturagradle.minecraft.RunMinecraftTask -import com.gtnewhorizons.retrofuturagradle.util.Distribution -import com.matthewprenger.cursegradle.CurseArtifact -import com.matthewprenger.cursegradle.CurseRelation -import com.modrinth.minotaur.dependencies.ModDependency -import com.modrinth.minotaur.dependencies.VersionDependency -import org.gradle.internal.logging.text.StyledTextOutput.Style -import org.gradle.internal.logging.text.StyledTextOutputFactory -import org.gradle.internal.xml.XmlTransformer -import org.jetbrains.gradle.ext.Application -import org.jetbrains.gradle.ext.Gradle - -import javax.inject.Inject -import java.nio.file.Files -import java.nio.file.Paths -import java.util.concurrent.TimeUnit - buildscript { repositories { mavenCentral() - - maven { - name 'forge' - url 'https://maven.minecraftforge.net' - } + maven { url "https://maven.minecraftforge.net" } maven { - // GTNH RetroFuturaGradle and ASM Fork - name "GTNH Maven" - url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/" - allowInsecureProtocol = true + name = "GTNH Maven" + url = uri("https://nexus.gtnewhorizons.com/repository/public/") } maven { - name 'sonatype' - url 'https://oss.sonatype.org/content/repositories/snapshots/' + name = "LegacyModdingMC" + url = uri("https://maven.legacy-modding.dev/releases") } - maven { - name 'Scala CI dependencies' - url 'https://repo1.maven.org/maven2/' - } - - mavenLocal() } } + plugins { - id 'java-library' - id "org.jetbrains.gradle.plugin.idea-ext" version "1.1.7" - id 'eclipse' - id 'scala' - id 'maven-publish' - id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false - id 'org.jetbrains.kotlin.kapt' version '1.8.0' apply false - id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false - id 'org.ajoberstar.grgit' version '4.1.1' // 4.1.1 is the last jvm8 supporting version, unused, available for addon.gradle - id 'com.github.johnrengelman.shadow' version '8.1.1' apply false - id 'com.palantir.git-version' version '3.0.0' apply false - id 'de.undercouch.download' version '5.4.0' - id 'com.github.gmazzo.buildconfig' version '3.1.0' apply false // Unused, available for addon.gradle - id 'com.diffplug.spotless' version '6.13.0' apply false // 6.13.0 is the last jvm8 supporting version - id 'com.modrinth.minotaur' version '2.+' apply false - id 'com.matthewprenger.cursegradle' version '1.4.0' apply false + id 'java' id 'com.gtnewhorizons.retrofuturagradle' version '1.3.24' } -print("You might want to check out './gradlew :faq' if your build fails.\n") - -boolean settingsupdated = verifySettingsGradle() -settingsupdated = verifyGitAttributes() || settingsupdated -if (settingsupdated) - throw new GradleException("Settings has been updated, please re-run task.") - -// In submodules, .git is a file pointing to the real git dir -if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) { - apply plugin: 'com.palantir.git-version' -} - -def out = services.get(StyledTextOutputFactory).create('an-output') - -def projectJavaVersion = JavaLanguageVersion.of(8) - -boolean disableSpotless = project.hasProperty("disableSpotless") ? project.disableSpotless.toBoolean() : false -boolean disableCheckstyle = project.hasProperty("disableCheckstyle") ? project.disableCheckstyle.toBoolean() : false - -final String CHECKSTYLE_CONFIG = """ - - - - - - - - - - - -""" - -checkPropertyExists("modName") -checkPropertyExists("modVersion") -checkPropertyExists("modId") -checkPropertyExists("modGroup") -checkPropertyExists("autoUpdateBuildScript") -checkPropertyExists("minecraftVersion") -checkPropertyExists("forgeVersion") -checkPropertyExists("replaceGradleTokenInFile") -checkPropertyExists("gradleTokenVersion") -checkPropertyExists("apiPackage") -checkPropertyExists("accessTransformersFile") -checkPropertyExists("usesMixins") -checkPropertyExists("mixinPlugin") -checkPropertyExists("mixinsPackage") -checkPropertyExists("coreModClass") -checkPropertyExists("containsMixinsAndOrCoreModOnly") -checkPropertyExists("usesShadowedDependencies") -checkPropertyExists("developmentEnvironmentUserName") - -propertyDefaultIfUnset("generateGradleTokenClass", "") -propertyDefaultIfUnset("includeWellKnownRepositories", true) -propertyDefaultIfUnset("noPublishedSources", false) -propertyDefaultIfUnset("usesMixinDebug", project.usesMixins) -propertyDefaultIfUnset("forceEnableMixins", false) -propertyDefaultIfUnset("channel", "stable") -propertyDefaultIfUnset("mappingsVersion", "12") -propertyDefaultIfUnset("usesMavenPublishing", true) -propertyDefaultIfUnset("mavenPublishUrl", "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases") -propertyDefaultIfUnset("modrinthProjectId", "") -propertyDefaultIfUnset("modrinthRelations", "") -propertyDefaultIfUnset("curseForgeProjectId", "") -propertyDefaultIfUnset("curseForgeRelations", "") -propertyDefaultIfUnset("minimizeShadowedDependencies", true) -propertyDefaultIfUnset("relocateShadowedDependencies", true) -// Deprecated properties (kept for backwards compat) -propertyDefaultIfUnset("gradleTokenModId", "") -propertyDefaultIfUnset("gradleTokenModName", "") -propertyDefaultIfUnset("gradleTokenGroupName", "") - -propertyDefaultIfUnset("enableModernJavaSyntax", false) // On by default for new projects only -propertyDefaultIfUnset("enableGenericInjection", false) // On by default for new projects only - -// this is meant to be set using the user wide property file. by default we do nothing. -propertyDefaultIfUnset("ideaOverrideBuildType", "") // Can be nothing, "gradle" or "idea" - -project.extensions.add(com.diffplug.blowdryer.Blowdryer, "Blowdryer", com.diffplug.blowdryer.Blowdryer) // Make blowdryer available in "apply from:" scripts -if (!disableSpotless) { - apply plugin: 'com.diffplug.spotless' - apply from: Blowdryer.file('spotless.gradle') -} - -if (!disableCheckstyle) { - apply plugin: 'checkstyle' - tasks.named("checkstylePatchedMc") { enabled = false } - tasks.named("checkstyleMcLauncher") { enabled = false } - tasks.named("checkstyleIdeVirtualMain") { enabled = false } - tasks.named("checkstyleInjectedTags") { enabled = false } - checkstyle { - config = resources.text.fromString(CHECKSTYLE_CONFIG) - } -} - -String javaSourceDir = "src/main/java/" -String scalaSourceDir = "src/main/scala/" -String kotlinSourceDir = "src/main/kotlin/" - -if (usesShadowedDependencies.toBoolean()) { - apply plugin: "com.github.johnrengelman.shadow" -} +group = modGroup +version = modVersion +archivesBaseName = modName java { toolchain { - if (enableModernJavaSyntax.toBoolean()) { - languageVersion.set(JavaLanguageVersion.of(17)) - } else { - languageVersion.set(projectJavaVersion) - } - vendor.set(JvmVendorSpec.AZUL) + languageVersion.set(JavaLanguageVersion.of(8)) } - if (!noPublishedSources) { - withSourcesJar() - } -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" -} - -tasks.withType(ScalaCompile).configureEach { - options.encoding = "UTF-8" -} - -pluginManager.withPlugin('org.jetbrains.kotlin.jvm') { - // If Kotlin is enabled in the project - kotlin { - jvmToolchain(8) - } - // Kotlin hacks our source sets, so we hack Kotlin's tasks - def disabledKotlinTaskList = [ - "kaptGenerateStubsMcLauncherKotlin", - "kaptGenerateStubsPatchedMcKotlin", - "kaptGenerateStubsInjectedTagsKotlin", - "compileMcLauncherKotlin", - "compilePatchedMcKotlin", - "compileInjectedTagsKotlin", - "kaptMcLauncherKotlin", - "kaptPatchedMcKotlin", - "kaptInjectedTagsKotlin", - "kspMcLauncherKotlin", - "kspPatchedMcKotlin", - "kspInjectedTagsKotlin", - ] - tasks.configureEach { task -> - if (task.name in disabledKotlinTaskList) { - task.enabled = false - } - } -} - -configurations { - create("runtimeOnlyNonPublishable") { - description = "Runtime only dependencies that are not published alongside the jar" - canBeConsumed = false - canBeResolved = false - } - - create("devOnlyNonPublishable") { - description = "Runtime and compiletime dependencies that are not published alongside the jar (compileOnly + runtimeOnlyNonPublishable)" - canBeConsumed = false - canBeResolved = false - } - compileOnly.extendsFrom(devOnlyNonPublishable) - runtimeOnlyNonPublishable.extendsFrom(devOnlyNonPublishable) } if (enableModernJavaSyntax.toBoolean()) { - repositories { - mavenCentral { - mavenContent { - includeGroup("me.eigenraven.java8unsupported") - } - } - } - dependencies { annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0' - // workaround for https://github.com/bsideup/jabel/issues/174 - annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0' compileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') { - transitive = false // We only care about the 1 annotation class + transitive = false } - // Allow using jdk.unsupported classes like sun.misc.Unsafe in the compiled code, working around JDK-8206937. - patchedMinecraft('me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0') } tasks.withType(JavaCompile).configureEach { - if (it.name in ["compileMcLauncherJava", "compilePatchedMcJava"]) { - return - } - sourceCompatibility = 17 // for the IDE support + sourceCompatibility = 17 options.release.set(8) javaCompiler.set(javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(17)) - vendor.set(JvmVendorSpec.AZUL) }) } } -eclipse { - classpath { - downloadSources = true - downloadJavadoc = true - } -} - -final String modGroupPath = modGroup.toString().replace('.' as char, '/' as char) -final String apiPackagePath = apiPackage.toString().replace('.' as char, '/' as char) - -String targetPackageJava = javaSourceDir + modGroupPath -String targetPackageScala = scalaSourceDir + modGroupPath -String targetPackageKotlin = kotlinSourceDir + modGroupPath -if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { - throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) -} - -if (apiPackage) { - targetPackageJava = javaSourceDir + modGroupPath + "/" + apiPackagePath - targetPackageScala = scalaSourceDir + modGroupPath + "/" + apiPackagePath - targetPackageKotlin = kotlinSourceDir + modGroupPath + "/" + apiPackagePath - if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { - throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) - } -} - -if (accessTransformersFile) { - for (atFile in accessTransformersFile.split(" ")) { - String targetFile = "src/main/resources/META-INF/" + atFile.trim() - if (!getFile(targetFile).exists()) { - throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile) - } - tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(targetFile) - tasks.srgifyBinpatchedJar.accessTransformerFiles.from(targetFile) - } -} else { - boolean atsFound = false - for (File at : sourceSets.getByName("main").resources.files) { - if (at.name.toLowerCase().endsWith("_at.cfg")) { - atsFound = true - tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at) - tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at) - } - } - for (File at : sourceSets.getByName("api").resources.files) { - if (at.name.toLowerCase().endsWith("_at.cfg")) { - atsFound = true - tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at) - tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at) - } - } - if (atsFound) { - logger.warn("Found and added access transformers in the resources folder, please configure gradle.properties to explicitly mention them by name") - } -} - -if (usesMixins.toBoolean()) { - if (mixinsPackage.isEmpty()) { - throw new GradleException("\"usesMixins\" requires \"mixinsPackage\" to be set!") - } - final String mixinPackagePath = mixinsPackage.toString().replaceAll("\\.", "/") - final String mixinPluginPath = mixinPlugin.toString().replaceAll("\\.", "/") - - targetPackageJava = javaSourceDir + modGroupPath + "/" + mixinPackagePath - targetPackageScala = scalaSourceDir + modGroupPath + "/" + mixinPackagePath - targetPackageKotlin = kotlinSourceDir + modGroupPath + "/" + mixinPackagePath - if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) { - throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin) - } - - if (!mixinPlugin.isEmpty()) { - String targetFileJava = javaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java" - String targetFileScala = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".scala" - String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + mixinPluginPath + ".java" - String targetFileKotlin = kotlinSourceDir + modGroupPath + "/" + mixinPluginPath + ".kt" - if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) { - throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin) - } - } -} - -if (coreModClass) { - final String coreModPath = coreModClass.toString().replaceAll("\\.", "/") - String targetFileJava = javaSourceDir + modGroupPath + "/" + coreModPath + ".java" - String targetFileScala = scalaSourceDir + modGroupPath + "/" + coreModPath + ".scala" - String targetFileScalaJava = scalaSourceDir + modGroupPath + "/" + coreModPath + ".java" - String targetFileKotlin = kotlinSourceDir + modGroupPath + "/" + coreModPath + ".kt" - if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) { - throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin) - } -} - -configurations.configureEach { - resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS) - - // Make sure GregTech build won't time out - System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String) - System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String) -} - -// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version -try { - 'git config core.fileMode false'.execute() -} -catch (Exception ignored) { - out.style(Style.Failure).println("git isn't installed at all") -} - -// Pulls version first from the VERSION env and then git tag -String identifiedVersion = modVersion -String versionOverride = modVersion -version = identifiedVersion - -group = "com.github.GTNewHorizons" -if (project.hasProperty("customArchiveBaseName") && customArchiveBaseName) { - base { - archivesName = customArchiveBaseName +if (generateGradleTokenClass) { + tasks.named("injectTags").configure { + outputClassName.set(generateGradleTokenClass) } -} else { - base { - archivesName = modId + tasks.named("compileJava").configure { + dependsOn("injectTags") } } +sourceCompatibility = 1.8 +targetCompatibility = 1.8 minecraft { - if (replaceGradleTokenInFile) { - for (f in replaceGradleTokenInFile.split(',')) { - tagReplacementFiles.add f - } - } + mcVersion = minecraftVersion + username = developmentEnvironmentUserName + if (gradleTokenModId) { injectedTags.put gradleTokenModId, modId } @@ -419,1167 +74,71 @@ minecraft { if (gradleTokenGroupName) { injectedTags.put gradleTokenGroupName, modGroup } - if (enableGenericInjection.toBoolean()) { - injectMissingGenerics.set(true) - } - - username = developmentEnvironmentUserName.toString() - - lwjgl3Version = "3.3.2" - - // Enable assertions in the current mod - extraRunJvmArguments.add("-ea:${modGroup}") if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) { - if (usesMixinDebug.toBoolean()) { - extraRunJvmArguments.addAll([ - "-Dmixin.debug.countInjections=true", - "-Dmixin.debug.verbose=true", - "-Dmixin.debug.export=true" - ]) - } + extraRunJvmArguments.add("-Dmixin.env.disableRefMap=true") } - // Blowdryer is present in some old mod builds, do not propagate it further as a dependency - // IC2 has no reobf jars in its Maven - groupsToExcludeFromAutoReobfMapping.addAll(["com.diffplug", "com.diffplug.durian", "net.industrial-craft"]) -} - -if (generateGradleTokenClass) { - tasks.injectTags.outputClassName.set(generateGradleTokenClass) -} - -// Custom reobf auto-mappings -configurations.configureEach { - dependencies.configureEach { dep -> - if (dep instanceof org.gradle.api.artifacts.ExternalModuleDependency) { - if (dep.group == "net.industrial-craft" && dep.name == "industrialcraft-2") { - // https://www.curseforge.com/minecraft/mc-mods/industrial-craft/files/2353971 - project.dependencies.reobfJarConfiguration("curse.maven:ic2-242638:2353971") - } - } - } - def obfuscationAttr = it.attributes.getAttribute(ObfuscationAttribute.OBFUSCATION_ATTRIBUTE) - if (obfuscationAttr != null && obfuscationAttr.name == ObfuscationAttribute.SRG) { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - // Remap CoFH core cursemaven dev jar to the obfuscated version for runObfClient/Server - if (details.requested.group == 'curse.maven' && details.requested.name.endsWith('-69162') && details.requested.version == '2388751') { - details.useVersion '2388750' - details.because 'Pick obfuscated jar' - } - } - } -} - -// Ensure tests have access to minecraft classes -sourceSets { - test { - java { - compileClasspath += sourceSets.patchedMc.output + sourceSets.mcLauncher.output - runtimeClasspath += sourceSets.patchedMc.output + sourceSets.mcLauncher.output - } - } -} - -if (file('addon.gradle.kts').exists()) { - apply from: 'addon.gradle.kts' -} else if (file('addon.gradle').exists()) { - apply from: 'addon.gradle' -} - -// File for local tweaks not commited to Git -if (file('addon.local.gradle.kts').exists()) { - apply from: 'addon.local.gradle.kts' -} else if (file('addon.local.gradle').exists()) { - apply from: 'addon.local.gradle' -} - -// Allow unsafe repos but warn -repositories.configureEach { repo -> - if (repo instanceof org.gradle.api.artifacts.repositories.UrlArtifactRepository) { - if (repo.getUrl() != null && repo.getUrl().getScheme() == "http" && !repo.allowInsecureProtocol) { - logger.warn("Deprecated: Allowing insecure connections for repo '${repo.name}' - add 'allowInsecureProtocol = true'") - repo.allowInsecureProtocol = true - } + if (coreModClass) { + extraRunJvmArguments.add("-Dfml.coreMods.load=${modGroup}.${coreModClass}") } } -if (file('repositories.gradle.kts').exists()) { - apply from: 'repositories.gradle.kts' -} else if (file('repositories.gradle').exists()) { - apply from: 'repositories.gradle' -} else { - logger.error("Neither repositories.gradle.kts nor repositories.gradle was found, make sure you extracted the full ExampleMod template.") - throw new RuntimeException("Missing repositories.gradle[.kts]") -} -configurations { - runtimeClasspath.extendsFrom(runtimeOnlyNonPublishable) - testRuntimeClasspath.extendsFrom(runtimeOnlyNonPublishable) - for (config in [compileClasspath, runtimeClasspath, testCompileClasspath, testRuntimeClasspath]) { - if (usesShadowedDependencies.toBoolean()) { - config.extendsFrom(shadowImplementation) - // TODO: remove Compile after all uses are refactored to Implementation - config.extendsFrom(shadeCompile) - config.extendsFrom(shadowCompile) - } - } - // A "bag-of-dependencies"-style configuration for backwards compatibility, gets put in "api" - create("compile") { - description = "Deprecated: use api or implementation instead, gets put in api" - canBeConsumed = false - canBeResolved = false - visible = false - } - create("testCompile") { - description = "Deprecated: use testImplementation instead" - canBeConsumed = false - canBeResolved = false - visible = false - } - api.extendsFrom(compile) - testImplementation.extendsFrom(testCompile) -} +repositories { + flatDir { dirs 'libs' } -afterEvaluate { - if (!configurations.compile.allDependencies.empty || !configurations.testCompile.allDependencies.empty) { - logger.warn("This project uses deprecated `compile` dependencies, please migrate to using `api` and `implementation`") - logger.warn("For more details, see https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/master/dependencies.gradle") - } -} + mavenCentral() -repositories { maven { - name 'Overmind forge repo mirror' - url 'https://gregtech.overminddl1.com/' + url = uri("https://maven.minecraftforge.net") } + maven { name = "GTNH Maven" - url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/" - allowInsecureProtocol = true + url = uri("https://nexus.gtnewhorizons.com/repository/public/") } + maven { - name 'sonatype' - url 'https://oss.sonatype.org/content/repositories/snapshots/' - content { - includeGroup "org.lwjgl" - } - } - if (includeWellKnownRepositories.toBoolean()) { - exclusiveContent { - forRepository { - maven { - name "CurseMaven" - url "https://cursemaven.com" - } - } - filter { - includeGroup "curse.maven" - } - } - exclusiveContent { - forRepository { - maven { - name = "Modrinth" - url = "https://api.modrinth.com/maven" - } - } - filter { - includeGroup "maven.modrinth" - } - } - maven { - name = "ic2" - url = getURL("https://maven.ic2.player.to/", "https://maven2.ic2.player.to/") - content { - includeGroup "net.industrial-craft" - } - metadataSources { - mavenPom() - artifact() - } - } - maven { - name "MMD Maven" - url "https://maven.mcmoddev.com/" - } + name = "LegacyModdingMC" + url = uri("https://maven.legacy-modding.dev/releases") } } -def mixinProviderGroup = "io.github.legacymoddingmc" -def mixinProviderModule = "unimixins" -def mixinProviderVersion = "0.1.13" -def mixinProviderSpecNoClassifer = "${mixinProviderGroup}:${mixinProviderModule}:${mixinProviderVersion}" -def mixinProviderSpec = "${mixinProviderSpecNoClassifer}:dev" -ext.mixinProviderSpec = mixinProviderSpec - -def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json' - dependencies { - if (usesMixins.toBoolean()) { - annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3') - annotationProcessor('com.google.guava:guava:24.1.1-jre') - annotationProcessor('com.google.code.gson:gson:2.8.6') - annotationProcessor(mixinProviderSpec) - if (usesMixinDebug.toBoolean()) { - runtimeOnlyNonPublishable('org.jetbrains:intellij-fernflower:1.2.1.16') - } - } - if (usesMixins.toBoolean()) { - implementation(modUtils.enableMixins(mixinProviderSpec, mixingConfigRefMap)) - } else if (forceEnableMixins.toBoolean()) { - runtimeOnlyNonPublishable(mixinProviderSpec) - } -} + implementation name: 'cindercore' + implementation name: 'lotr' + implementation name: 'optifine' + implementation name: 'variabletriggers' -pluginManager.withPlugin('org.jetbrains.kotlin.kapt') { if (usesMixins.toBoolean()) { - dependencies { - kapt(mixinProviderSpec) - } - } -} - -// Replace old mixin mods with unimixins -// https://docs.gradle.org/8.0.2/userguide/resolution_rules.html#sec:substitution_with_classifier -configurations.all { - resolutionStrategy.dependencySubstitution { - substitute module('com.gtnewhorizon:gtnhmixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods") - substitute module('com.github.GTNewHorizons:Mixingasm') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods") - substitute module('com.github.GTNewHorizons:SpongePoweredMixin') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods") - substitute module('com.github.GTNewHorizons:SpongeMixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Unimixins replaces other mixin mods") - substitute module('io.github.legacymoddingmc:unimixins') using module(mixinProviderSpecNoClassifer) withClassifier("dev") because("Our previous unimixins upload was missing the dev classifier") + annotationProcessor("io.github.legacymoddingmc:unimixins:0.1.13:dev") + implementation(modUtils.enableMixins("io.github.legacymoddingmc:unimixins:0.1.13:dev", "mixins.${modId}.refmap.json")) } } -dependencies { - constraints { - def minGtnhLibVersion = "0.0.13" - implementation("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { - because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") - } - runtimeOnly("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { - because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") - } - devOnlyNonPublishable("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { - because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") - } - runtimeOnlyNonPublishable("com.github.GTNewHorizons:GTNHLib:${minGtnhLibVersion}") { - because("fixes duplicate mod errors in java 17 configurations using old gtnhlib") - } - } -} - -if (file('dependencies.gradle.kts').exists()) { - apply from: 'dependencies.gradle.kts' -} else if (file('dependencies.gradle').exists()) { - apply from: 'dependencies.gradle' -} else { - logger.error("Neither dependencies.gradle.kts nor dependencies.gradle was found, make sure you extracted the full ExampleMod template.") - throw new RuntimeException("Missing dependencies.gradle[.kts]") -} - -tasks.register('generateAssets') { - group = "GTNH Buildscript" - description = "Generates a mixin config file at /src/main/resources/mixins.modid.json if needed" - onlyIf { usesMixins.toBoolean() } - doLast { - def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json") - if (!mixinConfigFile.exists()) { - def mixinPluginLine = "" - if (!mixinPlugin.isEmpty()) { - // We might not have a mixin plugin if we're using early/late mixins - mixinPluginLine += """\n "plugin": "${modGroup}.${mixinPlugin}", """ - } - - mixinConfigFile.text = """{ - "required": true, - "minVersion": "0.8.5-GTNH", - "package": "${modGroup}.${mixinsPackage}",${mixinPluginLine} - "refmap": "${mixingConfigRefMap}", - "target": "@env(DEFAULT)", - "compatibilityLevel": "JAVA_8", - "mixins": [], - "client": [], - "server": [] -} -""" - } - } -} - -if (usesMixins.toBoolean()) { - tasks.named("processResources").configure { - dependsOn("generateAssets") - } - - tasks.named("compileJava", JavaCompile).configure { - options.compilerArgs += [ - // Elan: from what I understand they are just some linter configs so you get some warning on how to properly code - "-XDenableSunApiLintControl", - "-XDignore.symbol.file" - ] +jar { + manifest { + attributes( + "FMLCorePlugin": "${modGroup}.${coreModClass}", + "FMLCorePluginContainsFMLMod": "true", + "TweakClass": "org.spongepowered.asm.launch.MixinTweaker", + "MixinConfigs": "mixins.${modId}.json", + "ForceLoadAsMod": "true" + ) } } -tasks.named("processResources", ProcessResources).configure { - // this will ensure that this task is redone when the versions change. +tasks.processResources { inputs.property "version", project.version inputs.property "mcversion", project.minecraft.mcVersion - exclude("spotless.gradle") - // replace stuff in mcmod.info, nothing else. replaces ${key} with value in text - filesMatching("mcmod.info") { - expand "minecraftVersion": project.minecraft.mcVersion, + filesMatching("mcmod.info") { + expand( + "minecraftVersion": project.minecraft.mcVersion, "modVersion": modVersion, "modId": modId, "modName": modName + ) } - - if (usesMixins.toBoolean()) { - dependsOn("compileJava", "compileScala") - } -} - -ext.java17Toolchain = (JavaToolchainSpec spec) -> { - spec.languageVersion.set(JavaLanguageVersion.of(17)) - spec.vendor.set(JvmVendorSpec.matching("jetbrains")) -} - -ext.java17DependenciesCfg = configurations.create("java17Dependencies") { - extendsFrom(configurations.getByName("runtimeClasspath")) // Ensure consistent transitive dependency resolution - canBeConsumed = false -} -ext.java17PatchDependenciesCfg = configurations.create("java17PatchDependencies") { - canBeConsumed = false -} - -dependencies { - def lwjgl3ifyVersion = '1.5.1' - if (modId != 'lwjgl3ify') { - java17Dependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}") - } - if (modId != 'hodgepodge') { - java17Dependencies('com.github.GTNewHorizons:Hodgepodge:2.3.17') - } - - java17PatchDependencies("com.github.GTNewHorizons:lwjgl3ify:${lwjgl3ifyVersion}:forgePatches") {transitive = false} -} - -ext.java17JvmArgs = [ - // Java 9+ support - "--illegal-access=warn", - "-Djava.security.manager=allow", - "-Dfile.encoding=UTF-8", - "--add-opens", "java.base/jdk.internal.loader=ALL-UNNAMED", - "--add-opens", "java.base/java.net=ALL-UNNAMED", - "--add-opens", "java.base/java.nio=ALL-UNNAMED", - "--add-opens", "java.base/java.io=ALL-UNNAMED", - "--add-opens", "java.base/java.lang=ALL-UNNAMED", - "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", - "--add-opens", "java.base/java.text=ALL-UNNAMED", - "--add-opens", "java.base/java.util=ALL-UNNAMED", - "--add-opens", "java.base/jdk.internal.reflect=ALL-UNNAMED", - "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", - "--add-opens", "jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED,java.naming", - "--add-opens", "java.desktop/sun.awt.image=ALL-UNNAMED", - "--add-modules", "jdk.dynalink", - "--add-opens", "jdk.dynalink/jdk.dynalink.beans=ALL-UNNAMED", - "--add-modules", "java.sql.rowset", - "--add-opens", "java.sql.rowset/javax.sql.rowset.serial=ALL-UNNAMED" -] - -ext.hotswapJvmArgs = [ - // DCEVM advanced hot reload - "-XX:+AllowEnhancedClassRedefinition", - "-XX:HotswapAgent=fatjar" -] - -ext.setupHotswapAgentTask = tasks.register("setupHotswapAgent") { - group = "GTNH Buildscript" - description = "Installs a recent version of HotSwapAgent into the Java 17 JetBrains runtime directory" - def hsaUrl = 'https://github.com/HotswapProjects/HotswapAgent/releases/download/1.4.2-SNAPSHOT/hotswap-agent-1.4.2-SNAPSHOT.jar' - def targetFolderProvider = javaToolchains.launcherFor(java17Toolchain).map {it.metadata.installationPath.dir("lib/hotswap")} - def targetFilename = "hotswap-agent.jar" - onlyIf { - !targetFolderProvider.get().file(targetFilename).asFile.exists() - } - doLast { - def targetFolder = targetFolderProvider.get() - targetFolder.asFile.mkdirs() - download.run { - src hsaUrl - dest targetFolder.file(targetFilename).asFile - overwrite false - tempAndMove true - } - } -} - -public abstract class RunHotswappableMinecraftTask extends RunMinecraftTask { - // IntelliJ doesn't seem to allow commandline arguments so we also support an env variable - private boolean enableHotswap = Boolean.valueOf(System.getenv("HOTSWAP")); - - @Input - public boolean getEnableHotswap() { return enableHotswap } - @Option(option = "hotswap", description = "Enables HotSwapAgent for enhanced class reloading under a debugger") - public boolean setEnableHotswap(boolean enable) { enableHotswap = enable } - - @Inject - public RunHotswappableMinecraftTask(Distribution side, String superTask, org.gradle.api.invocation.Gradle gradle) { - super(side, gradle) - - this.lwjglVersion = 3 - this.javaLauncher = project.javaToolchains.launcherFor(project.java17Toolchain) - this.extraJvmArgs.addAll(project.java17JvmArgs) - this.extraJvmArgs.addAll(project.provider(() -> enableHotswap ? project.hotswapJvmArgs : [])) - - this.classpath(project.java17PatchDependenciesCfg) - if (side == Distribution.CLIENT) { - this.classpath(project.minecraftTasks.lwjgl3Configuration) - } - // Use a raw provider instead of map to not create a dependency on the task - this.classpath(project.provider(() -> project.tasks.named(superTask, RunMinecraftTask).get().classpath)) - this.classpath.filter { file -> - !file.path.contains("2.9.4-nightly-20150209") // Remove lwjgl2 - } - this.classpath(project.java17DependenciesCfg) - } - - public void setup(Project project) { - super.setup(project) - if (project.usesMixins.toBoolean()) { - this.extraJvmArgs.addAll(project.provider(() -> { - def mixinCfg = project.configurations.detachedConfiguration(project.dependencies.create(project.mixinProviderSpec)) - mixinCfg.canBeConsumed = false - mixinCfg.transitive = false - enableHotswap ? ["-javaagent:" + mixinCfg.singleFile.absolutePath] : [] - })) - } - } -} - -def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient") -runClient17Task.configure { - setup(project) - group = "Modded Minecraft" - description = "Runs the modded client using Java 17, lwjgl3ify and Hodgepodge" - dependsOn(setupHotswapAgentTask, mcpTasks.launcherSources.classesTaskName, minecraftTasks.taskDownloadVanillaAssets, mcpTasks.taskPackagePatchedMc, 'jar') - mainClass = "GradleStart" - username = minecraft.username - userUUID = minecraft.userUUID -} - -def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer") -runServer17Task.configure { - setup(project) - group = "Modded Minecraft" - description = "Runs the modded server using Java 17, lwjgl3ify and Hodgepodge" - dependsOn(setupHotswapAgentTask, mcpTasks.launcherSources.classesTaskName, minecraftTasks.taskDownloadVanillaAssets, mcpTasks.taskPackagePatchedMc, 'jar') - mainClass = "GradleStartServer" - extraArgs.add("nogui") -} - -def getManifestAttributes() { - def manifestAttributes = [:] - if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) { - manifestAttributes += ["FMLCorePluginContainsFMLMod": true] - } - - if (accessTransformersFile) { - manifestAttributes += ["FMLAT": accessTransformersFile.toString()] - } - - if (coreModClass) { - manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass] - } - - if (usesMixins.toBoolean()) { - manifestAttributes += [ - "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", - "MixinConfigs" : "mixins." + modId + ".json", - "ForceLoadAsMod": !containsMixinsAndOrCoreModOnly.toBoolean() - ] - } - return manifestAttributes -} - -tasks.named("jar", Jar).configure { - manifest { - attributes(getManifestAttributes()) - } -} - -if (usesShadowedDependencies.toBoolean()) { - tasks.named("shadowJar", ShadowJar).configure { - manifest { - attributes(getManifestAttributes()) - } - - if (minimizeShadowedDependencies.toBoolean()) { - minimize() // This will only allow shading for actually used classes - } - configurations = [ - project.configurations.shadowImplementation, - project.configurations.shadowCompile, - project.configurations.shadeCompile - ] - archiveClassifier.set('dev') - if (relocateShadowedDependencies.toBoolean()) { - relocationPrefix = modGroup + ".shadow" - enableRelocation = true - } - } - configurations.runtimeElements.outgoing.artifacts.clear() - configurations.apiElements.outgoing.artifacts.clear() - configurations.runtimeElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar)) - configurations.apiElements.outgoing.artifact(tasks.named("shadowJar", ShadowJar)) - tasks.named("jar", Jar) { - enabled = false - finalizedBy(tasks.shadowJar) - } - tasks.named("reobfJar", ReobfuscatedJar) { - inputJar.set(tasks.named("shadowJar", ShadowJar).flatMap({it.archiveFile})) - } - AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.components.findByName("java") - javaComponent.withVariantsFromConfiguration(configurations.shadowRuntimeElements) { - skip() - } - for (runTask in ["runClient", "runServer", "runClient17", "runServer17"]) { - tasks.named(runTask).configure { - dependsOn("shadowJar") - } - } -} -ext.publishableDevJar = usesShadowedDependencies.toBoolean() ? tasks.shadowJar : tasks.jar -ext.publishableObfJar = tasks.reobfJar - -tasks.register('apiJar', Jar) { - from(sourceSets.main.allSource) { - include modGroupPath + "/" + apiPackagePath + '/**' - } - - from(sourceSets.main.output) { - include modGroupPath + "/" + apiPackagePath + '/**' - } - - from(sourceSets.main.resources.srcDirs) { - include("LICENSE") - } - - getArchiveClassifier().set('api') -} - -artifacts { - if (!noPublishedSources) { - archives tasks.named("sourcesJar") - } - if (apiPackage) { - archives tasks.named("apiJar") - } -} - -idea { - module { - downloadJavadoc = true - downloadSources = true - inheritOutputDirs = true - } - project { - settings { - if (ideaOverrideBuildType != "") { - delegateActions { - if ("gradle".equalsIgnoreCase(ideaOverrideBuildType)) { - delegateBuildRunToGradle = true - testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.GRADLE - } else if ("idea".equalsIgnoreCase(ideaOverrideBuildType)) { - delegateBuildRunToGradle = false - testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM - } else { - throw GradleScriptException('Accepted value for ideaOverrideBuildType is one of gradle or idea.') - } - } - } - runConfigurations { - "0. Build and Test"(Gradle) { - taskNames = ["build"] - } - "1. Run Client"(Gradle) { - taskNames = ["runClient"] - } - "2. Run Server"(Gradle) { - taskNames = ["runServer"] - } - "1a. Run Client (Java 17)"(Gradle) { - taskNames = ["runClient17"] - } - "2a. Run Server (Java 17)"(Gradle) { - taskNames = ["runServer17"] - } - "1b. Run Client (Java 17, Hotswap)"(Gradle) { - taskNames = ["runClient17"] - envs = ["HOTSWAP": "true"] - } - "2b. Run Server (Java 17, Hotswap)"(Gradle) { - taskNames = ["runServer17"] - envs = ["HOTSWAP": "true"] - } - "3. Run Obfuscated Client"(Gradle) { - taskNames = ["runObfClient"] - } - "4. Run Obfuscated Server"(Gradle) { - taskNames = ["runObfServer"] - } - if (!disableSpotless) { - "5. Apply spotless"(Gradle) { - taskNames = ["spotlessApply"] - } - } - def coreModArgs = "" - if (coreModClass) { - coreModArgs = ' "-Dfml.coreMods.load=' + modGroup + '.' + coreModClass + '"' - } - "Run Client (IJ Native)"(Application) { - mainClass = "GradleStart" - moduleName = project.name + ".ideVirtualMain" - afterEvaluate { - workingDirectory = tasks.runClient.workingDir.absolutePath - programParameters = tasks.runClient.calculateArgs(project).collect { '"' + it + '"' }.join(' ') - jvmArgs = tasks.runClient.calculateJvmArgs(project).collect { '"' + it + '"' }.join(' ') + - ' ' + tasks.runClient.systemProperties.collect { '"-D' + it.key + '=' + it.value.toString() + '"' }.join(' ') + - coreModArgs - } - } - "Run Server (IJ Native)"(Application) { - mainClass = "GradleStartServer" - moduleName = project.name + ".ideVirtualMain" - afterEvaluate { - workingDirectory = tasks.runServer.workingDir.absolutePath - programParameters = tasks.runServer.calculateArgs(project).collect { '"' + it + '"' }.join(' ') - jvmArgs = tasks.runServer.calculateJvmArgs(project).collect { '"' + it + '"' }.join(' ') + - ' ' + tasks.runServer.systemProperties.collect { '"-D' + it.key + '=' + it.value.toString() + '"' }.join(' ') + - coreModArgs - } - } - } - compiler.javac { - afterEvaluate { - javacAdditionalOptions = "-encoding utf8" - moduleJavacAdditionalOptions = [ - (project.name + ".main"): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ') - ] - } - } - withIDEADir { File ideaDir -> - if (!ideaDir.path.contains(".idea")) { - // If an .ipr file exists, the project root directory is passed here instead of the .idea subdirectory - ideaDir = new File(ideaDir, ".idea") - } - if (ideaDir.isDirectory()) { - def miscFile = new File(ideaDir, "misc.xml") - if (miscFile.isFile()) { - boolean dirty = false - def miscTransformer = new XmlTransformer() - miscTransformer.addAction { root -> - Node rootNode = root.asNode() - def rootManager = rootNode - .component.find { it.@name == 'ProjectRootManager' } - if (!rootManager) { - rootManager = rootNode.appendNode('component', ['name': 'ProjectRootManager', 'version': '2']) - dirty = true - } - def output = rootManager.output - if (!output) { - output = rootManager.appendNode('output') - dirty = true - } - if (!output.@url) { - // Only modify the output url if it doesn't yet have one, or if the existing one is blank somehow. - // This is a sensible default for most setups - output.@url = 'file://$PROJECT_DIR$/build/ideaBuild' - dirty = true - } - } - def result = miscTransformer.transform(miscFile.text) - if (dirty) { - miscFile.write(result) - } - } else { - miscFile.text = """ - - - - - -""" - } - } - } - } - } -} - -tasks.named("processIdeaSettings").configure { - dependsOn("injectTags") -} - -tasks.named("ideVirtualMainClasses").configure { - // Make IntelliJ "Build project" build the mod jars - dependsOn("jar", "reobfJar") - if (!disableSpotless) { - dependsOn("spotlessCheck") - } -} - -// workaround variable hiding in pom processing -def projectConfigs = project.configurations - -publishing { - publications { - create("maven", MavenPublication) { - from components.java - - if (apiPackage) { - artifact apiJar - } - - groupId = System.getenv("ARTIFACT_GROUP_ID") ?: project.group - artifactId = System.getenv("ARTIFACT_ID") ?: project.name - // Using the identified version, not project.version as it has the prepended 1.7.10 - version = System.getenv("RELEASE_VERSION") ?: identifiedVersion - } - } - repositories { - if (usesMavenPublishing.toBoolean() && System.getenv("MAVEN_USER") != null) { - maven { - url = mavenPublishUrl - allowInsecureProtocol = mavenPublishUrl.startsWith("http://") // Mostly for the GTNH maven - credentials { - username = System.getenv("MAVEN_USER") ?: "NONE" - password = System.getenv("MAVEN_PASSWORD") ?: "NONE" - } - } - } - } -} - -if (modrinthProjectId.size() != 0 && System.getenv("MODRINTH_TOKEN") != null) { - apply plugin: 'com.modrinth.minotaur' - - File changelogFile = new File(System.getenv("CHANGELOG_FILE") ?: "CHANGELOG.md") - - modrinth { - token = System.getenv("MODRINTH_TOKEN") - projectId = modrinthProjectId - versionNumber = identifiedVersion - versionType = identifiedVersion.endsWith("-pre") ? "beta" : "release" - changelog = changelogFile.exists() ? changelogFile.getText("UTF-8") : "" - uploadFile = publishableObfJar - additionalFiles = getSecondaryArtifacts() - gameVersions = [minecraftVersion] - loaders = ["forge"] - debugMode = false - } - - if (modrinthRelations.size() != 0) { - String[] deps = modrinthRelations.split(";") - deps.each { dep -> - if (dep.size() == 0) { - return - } - String[] parts = dep.split(":") - String[] qual = parts[0].split("-") - addModrinthDep(qual[0], qual[1], parts[1]) - } - } - if (usesMixins.toBoolean()) { - addModrinthDep("required", "project", "unimixins") - } - tasks.modrinth.dependsOn(build) - tasks.publish.dependsOn(tasks.modrinth) -} - -if (curseForgeProjectId.size() != 0 && System.getenv("CURSEFORGE_TOKEN") != null) { - apply plugin: 'com.matthewprenger.cursegradle' - - File changelogFile = new File(System.getenv("CHANGELOG_FILE") ?: "CHANGELOG.md") - - curseforge { - apiKey = System.getenv("CURSEFORGE_TOKEN") - project { - id = curseForgeProjectId - if (changelogFile.exists()) { - changelogType = "markdown" - changelog = changelogFile - } - releaseType = identifiedVersion.endsWith("-pre") ? "beta" : "release" - addGameVersion minecraftVersion - addGameVersion "Forge" - mainArtifact publishableObfJar - for (artifact in getSecondaryArtifacts()) addArtifact artifact - } - - options { - javaIntegration = false - forgeGradleIntegration = false - debug = false - } - } - - if (curseForgeRelations.size() != 0) { - String[] deps = curseForgeRelations.split(";") - deps.each { dep -> - if (dep.size() == 0) { - return - } - String[] parts = dep.split(":") - addCurseForgeRelation(parts[0], parts[1]) - } - } - if (usesMixins.toBoolean()) { - addCurseForgeRelation("requiredDependency", "unimixins") - } - tasks.curseforge.dependsOn(build) - tasks.publish.dependsOn(tasks.curseforge) -} - -def addModrinthDep(String scope, String type, String name) { - com.modrinth.minotaur.dependencies.Dependency dep; - if (!(scope in ["required", "optional", "incompatible", "embedded"])) { - throw new Exception("Invalid modrinth dependency scope: " + scope) - } - switch (type) { - case "project": - dep = new ModDependency(name, scope) - break - case "version": - dep = new VersionDependency(name, scope) - break - default: - throw new Exception("Invalid modrinth dependency type: " + type) - } - project.modrinth.dependencies.add(dep) -} - -def addCurseForgeRelation(String type, String name) { - if (!(type in ["requiredDependency", "embeddedLibrary", "optionalDependency", "tool", "incompatible"])) { - throw new Exception("Invalid CurseForge relation type: " + type) - } - CurseArtifact artifact = project.curseforge.curseProjects[0].mainArtifact - CurseRelation rel = (artifact.curseRelations ?: (artifact.curseRelations = new CurseRelation())) - rel."$type"(name) -} - -// Updating - -def buildscriptGradleVersion = "8.2.1" - -tasks.named('wrapper', Wrapper).configure { - gradleVersion = buildscriptGradleVersion -} - -tasks.register('updateBuildScript') { - group = 'GTNH Buildscript' - description = 'Updates the build script to the latest version' - - if (gradle.gradleVersion != buildscriptGradleVersion && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_GRADLE_UPDATE')) { - dependsOn('wrapper') - } - - doLast { - if (performBuildScriptUpdate()) return - - print("Build script already up-to-date!") - } -} - -if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISABLE_BUILDSCRIPT_UPDATE_CHECK') && isNewBuildScriptVersionAvailable()) { - if (autoUpdateBuildScript.toBoolean()) { - performBuildScriptUpdate() - } else { - out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'") - if (gradle.gradleVersion != buildscriptGradleVersion) { - out.style(Style.SuccessHeader).println("updateBuildScript can update gradle from ${gradle.gradleVersion} to ${buildscriptGradleVersion}\n") - } - } -} - -// If you want to add more cases to this task, implement them as arguments if total amount to print gets too large -tasks.register('faq') { - group = 'GTNH Buildscript' - description = 'Prints frequently asked questions about building a project' - - doLast { - print("If your build fails to fetch dependencies, run './gradlew updateDependencies'. " + - "Or you can manually check if the versions are still on the distributing sites - " + - "the links can be found in repositories.gradle and build.gradle:repositories, " + - "but not build.gradle:buildscript.repositories - those ones are for gradle plugin metadata.\n\n" + - "If your build fails to recognize the syntax of new Java versions, enable Jabel in your " + - "gradle.properties. See how it's done in GTNH ExampleMod/gradle.properties. " + - "However, keep in mind that Jabel enables only syntax features, but not APIs that were introduced in " + - "Java 9 or later.") - } -} - -static URL availableBuildScriptUrl() { - new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/build.gradle") -} - -static URL exampleSettingsGradleUrl() { - new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/settings.gradle.example") -} - -static URL exampleGitAttributesUrl() { - new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/.gitattributes") -} - - -boolean verifyGitAttributes() { - def gitattributesFile = getFile(".gitattributes") - if (!gitattributesFile.exists()) { - println("Downloading default .gitattributes") - exampleGitAttributesUrl().withInputStream { i -> gitattributesFile.withOutputStream { it << i } } - exec { - workingDir '.' - commandLine 'git', 'add', '--renormalize', '.' - } - return true - } - return false -} - -boolean verifySettingsGradle() { - def settingsFile = getFile("settings.gradle") - if (!settingsFile.exists()) { - println("Downloading default settings.gradle") - exampleSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } } - return true - } - return false -} - -boolean performBuildScriptUpdate() { - if (isNewBuildScriptVersionAvailable()) { - def buildscriptFile = getFile("build.gradle") - availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } } - def out = services.get(StyledTextOutputFactory).create('buildscript-update-output') - out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!") - boolean settingsupdated = verifySettingsGradle() - settingsupdated = verifyGitAttributes() || settingsupdated - if (settingsupdated) - throw new GradleException("Settings has been updated, please re-run task.") - return true - } - return false -} - -boolean isNewBuildScriptVersionAvailable() { - Map parameters = ["connectTimeout": 2000, "readTimeout": 2000] - - String currentBuildScript = getFile("build.gradle").getText() - String currentBuildScriptHash = getVersionHash(currentBuildScript) - String availableBuildScriptHash - try { - String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText() - availableBuildScriptHash = getVersionHash(availableBuildScript) - } catch (IOException e) { - logger.warn("Could not check for buildscript update availability: {}", e.message) - return false - } - - boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash - return !isUpToDate -} - -static String getVersionHash(String buildScriptContent) { - String versionLine = buildScriptContent.find("^//version: [a-z0-9]*") - if (versionLine != null) { - return versionLine.split(": ").last() - } - return "" -} - -// Parameter Deobfuscation - -tasks.register('deobfParams') { - group = 'GTNH Buildscript' - description = 'Rename all obfuscated parameter names inherited from Minecraft classes' - doLast { // TODO - - String mcpDir = "$project.gradle.gradleUserHomeDir/caches/minecraft/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion" - String mcpZIP = "$mcpDir/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip" - String paramsCSV = "$mcpDir/params.csv" - - download.run { - src "https://maven.minecraftforge.net/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion-$minecraftVersion/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip" - dest mcpZIP - overwrite false - } - - if (!file(paramsCSV).exists()) { - println("Extracting MCP archive ...") - copy { - from(zipTree(mcpZIP)) - into(mcpDir) - } - } - - println("Parsing params.csv ...") - Map params = new HashMap<>() - Files.lines(Paths.get(paramsCSV)).forEach { line -> - String[] cells = line.split(",") - if (cells.length > 2 && cells[0].matches("p_i?\\d+_\\d+_")) { - params.put(cells[0], cells[1]) - } - } - - out.style(Style.Success).println("Modified ${replaceParams(file("$projectDir/src/main/java"), params)} files!") - out.style(Style.Failure).println("Don't forget to verify that the code still works as before!\n It could be broken due to duplicate variables existing now\n or parameters taking priority over other variables.") - } -} - -static int replaceParams(File file, Map params) { - int fileCount = 0 - - if (file.isDirectory()) { - for (File f : file.listFiles()) { - fileCount += replaceParams(f, params) - } - return fileCount - } - println("Visiting ${file.getName()} ...") - try { - String content = new String(Files.readAllBytes(file.toPath())) - int hash = content.hashCode() - params.forEach { key, value -> - content = content.replaceAll(key, value) - } - if (hash != content.hashCode()) { - Files.write(file.toPath(), content.getBytes("UTF-8")) - return 1 - } - } catch (Exception e) { - e.printStackTrace() - } - return 0 -} - -// Dependency Deobfuscation (Deprecated, use the new RFG API documented in dependencies.gradle) - -def deobf(String sourceURL) { - try { - URL url = new URL(sourceURL) - String fileName = url.getFile() - - //get rid of directories: - int lastSlash = fileName.lastIndexOf("/") - if (lastSlash > 0) { - fileName = fileName.substring(lastSlash + 1) - } - //get rid of extension: - if (fileName.endsWith(".jar") || fileName.endsWith(".litemod")) { - fileName = fileName.substring(0, fileName.lastIndexOf(".")) - } - - String hostName = url.getHost() - if (hostName.startsWith("www.")) { - hostName = hostName.substring(4) - } - List parts = Arrays.asList(hostName.split("\\.")) - Collections.reverse(parts) - hostName = String.join(".", parts) - - return deobf(sourceURL, "$hostName/$fileName") - } catch (Exception ignored) { - return deobf(sourceURL, "deobf/${sourceURL.hashCode()}") - } -} - -def deobfMaven(String repoURL, String mavenDep) { - if (!repoURL.endsWith("/")) { - repoURL += "/" - } - String[] parts = mavenDep.split(":") - parts[0] = parts[0].replace('.', '/') - def jarURL = repoURL + parts[0] + "/" + parts[1] + "/" + parts[2] + "/" + parts[1] + "-" + parts[2] + ".jar" - return deobf(jarURL) -} - -def deobfCurse(String curseDep) { - return dependencies.rfg.deobf("curse.maven:$curseDep") -} - -// The method above is to be preferred. Use this method if the filename is not at the end of the URL. -def deobf(String sourceURL, String rawFileName) { - String bon2Version = "2.5.1" - String fileName = URLDecoder.decode(rawFileName, "UTF-8") - String cacheDir = "$project.gradle.gradleUserHomeDir/caches" - String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar" - - download.run { - src sourceURL - dest obfFile - quiet true - overwrite false - } - return dependencies.rfg.deobf(files(obfFile)) -} -// Helper methods - -def checkPropertyExists(String propertyName) { - if (!project.hasProperty(propertyName)) { - throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties") - } -} - -def propertyDefaultIfUnset(String propertyName, defaultValue) { - if (!project.hasProperty(propertyName) || project.property(propertyName) == "") { - project.ext.setProperty(propertyName, defaultValue) - } -} - -def getFile(String relativePath) { - return new File(projectDir, relativePath) -} - -def getSecondaryArtifacts() { - // Because noPublishedSources from the beginning of the script is somehow not visible here... - boolean noPublishedSources = project.hasProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false - def secondaryArtifacts = [publishableDevJar] - if (!noPublishedSources) secondaryArtifacts += [sourcesJar] - if (apiPackage) secondaryArtifacts += [apiJar] - return secondaryArtifacts -} - -def getURL(String main, String fallback) { - return pingURL(main, 10000) ? main : fallback -} - -// credit: https://stackoverflow.com/a/3584332 -def pingURL(String url, int timeout) { - url = url.replaceFirst("^https", "http") // Otherwise an exception may be thrown on invalid SSL certificates. - try { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection() - connection.setConnectTimeout(timeout) - connection.setReadTimeout(timeout) - connection.setRequestMethod("HEAD") - int responseCode = connection.getResponseCode() - return 200 <= responseCode && responseCode <= 399 - } catch (IOException ignored) { - return false - } -} - -// For easier scripting of things that require variables defined earlier in the buildscript -if (file('addon.late.gradle.kts').exists()) { - apply from: 'addon.late.gradle.kts' -} else if (file('addon.late.gradle').exists()) { - apply from: 'addon.late.gradle' -} - -// File for local tweaks not commited to Git -if (file('addon.late.local.gradle.kts').exists()) { - apply from: 'addon.late.local.gradle.kts' -} else if (file('addon.late.local.gradle').exists()) { - apply from: 'addon.late.local.gradle' } diff --git a/dependencies.gradle b/dependencies.gradle deleted file mode 100644 index 5651b6f..0000000 --- a/dependencies.gradle +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Add your dependencies here. Supported configurations: - * - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod - * Available at runtime and compiletime for mods depending on this mod - * - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API - * Available at runtime but not compiletime for mods depending on this mod - * - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods - * Not available at all for mods depending on this mod, only visible at compiletime for this mod - * - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod - * Available at compiletime but not runtime for mods depending on this mod - * - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency - * Not available at all for mods depending on this mod, only visible at runtime for this mod - * - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime, - * but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing - * - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime - * Available at runtime for mods depending on this mod - * - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry - * - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main - * - * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name - * Requires you to enable usesShadowedDependencies in gradle.properties - * - * - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient) - * - * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, - * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. - * - * To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven, - * or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file. - * - * Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not. - * The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published. - * - * For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph - */ -dependencies { - implementation files('libs/cindercore.jar') - implementation files('libs/lotr.jar') - implementation files('libs/optifine.jar') - implementation files('libs/variabletriggers.jar') -} diff --git a/gradle.properties b/gradle.properties index 8278628..7ca3422 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,153 +1,31 @@ modName = CinderLoE modVersion = 1.4.0 - -# This is a case-sensitive string to identify your mod. Convention is to use lower case. modId = cinder_loe - modGroup = com.zivilon.cinder_loe -# WHY is there no version field? -# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the -# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/ - -# Will update your build.gradle automatically whenever an update is available -autoUpdateBuildScript = false - minecraftVersion = 1.7.10 -forgeVersion = 10.13.4.1614 - -# Specify a MCP channel and mappings version for dependency deobfuscation and the deobfParams task. -channel = stable -mappingsVersion = 12 - -# Define other MCP mappings for dependency deobfuscation -remoteMappings = https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/ -# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you -# restart Minecraft in development. Choose this dependent on your mod: -# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name -# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty developmentEnvironmentUserName = Developer -# Enables using modern java syntax (up to version 17) via Jabel, while still targeting JVM 8. -# See https://github.com/bsideup/jabel for details on how this works. enableModernJavaSyntax = true -# Enables injecting missing generics into the decompiled source code for a better coding experience -# Turns most publicly visible List, Map, etc. into proper List, Map types -enableGenericInjection = false - # Generate a class with String fields for the mod id, name, version and group name named with the fields below generateGradleTokenClass = com.zivilon.cinder_loe.Tags gradleTokenModId = MODID gradleTokenModName = MODNAME gradleTokenVersion = gradleTokenGroupName = GROUPNAME -# [DEPRECATED] -# Multiple source files can be defined here by providing a comma-seperated list: Class1.java,Class2.java,Class3.java -# public static final String VERSION = "GRADLETOKEN_VERSION"; -# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's -# version in @Mod([...], version = VERSION, [...]) -# Leave these properties empty to skip individual token replacements -replaceGradleTokenInFile = - -# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can -# leave this property empty. -# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api -apiPackage = - -# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/ -# There can be multiple files in a space-separated list. -# Example value: mymodid_at.cfg nei_at.cfg -accessTransformersFile = # Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! usesMixins = true -# Adds some debug arguments like verbose output and export -usesMixinDebug = false -# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. -mixinPlugin = -# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! -mixinsPackage = mixins # Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! # This parameter is for legacy compatibility only # Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin coreModClass = coremod.CoreMod -# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class -# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false! -containsMixinsAndOrCoreModOnly = false # Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins. forceEnableMixins = false -# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your -# responsibility check the licence and request permission for distribution, if required. -usesShadowedDependencies = false -# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access -# their own classes, making the minimization unreliable. -minimizeShadowedDependencies = true -# If disabled, won't rename the shadowed classes. -relocateShadowedDependencies = true - -# Adds the GTNH maven, CurseMaven, IC2/Player maven, and some more well-known 1.7.10 repositories -includeWellKnownRepositories = false - -# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven. -# Authenticate with the MAVEN_USERNAME and MAVEN_PASSWORD environment variables. -# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle. -usesMavenPublishing = false -# mavenPublishUrl = http://jenkins.usrv.eu:8081/nexus/content/repositories/releases - -# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token. - -# The project's ID on Modrinth. Can be either the slug or the ID. -# Leave this empty if you don't want to publish on Modrinth. -modrinthProjectId = - -# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth. -# Syntax: scope1-type1:name1;scope2-type2:name2;... -# Where scope can be one of [required, optional, incompatible, embedded], -# type can be one of [project, version], -# and the name is the Modrinth project or version slug/id of the other mod. -# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech -# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true -modrinthRelations = - - -# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens. - -# The project's numeric ID on CurseForge. You can find this in the About Project box. -# Leave this empty if you don't want to publish on CurseForge. -curseForgeProjectId = - -# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge. -# Syntax: type1:name1;type2:name2;... -# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible], -# and the name is the CurseForge project slug of the other mod. -# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft -# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true -curseForgeRelations = - - # Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older # projects. New projects should not use this parameter. customArchiveBaseName = CinderLoE - -# Optional parameter to prevent the source code from being published -# noPublishedSources = - -# Uncomment this to disable spotless checks -# This should only be uncommented to keep it easier to sync with upstream/other forks. -# That is, if there is no other active fork/upstream, NEVER change this. -disableSpotless = true - -# Uncomment this to disable checkstyle checks (currently wildcard import check). - disableCheckstyle = true - -# Override the IDEA build type. Valid value is "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle" -# (force use delegated build). -# This is meant to be set in $HOME/.gradle/gradle.properties. -# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be always native build. -# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want! -# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you. -# ideaOverrideBuildType = idea diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/zivilon/cinder_loe/CinderEventHandler.java b/src/main/java/com/zivilon/cinder_loe/CinderEventHandler.java index 56e75ee..86b9fdc 100644 --- a/src/main/java/com/zivilon/cinder_loe/CinderEventHandler.java +++ b/src/main/java/com/zivilon/cinder_loe/CinderEventHandler.java @@ -2,12 +2,15 @@ package com.zivilon.cinder_loe; import com.zivilon.cinder_loe.entity.corrupt.CorruptMan; import com.zivilon.cinder_loe.items.BrokenHalo; +import com.zivilon.cinder_loe.network.PacketWarbandLocations; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.IFuelHandler; import cpw.mods.fml.common.eventhandler.EventPriority; import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; import cpw.mods.fml.common.registry.GameRegistry; import lotr.common.LOTRMod; +import lotr.common.LOTRDimension; import lotr.common.enchant.LOTREnchantment; import lotr.common.enchant.LOTREnchantmentHelper; import lotr.common.item.*; @@ -32,6 +35,7 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; import net.minecraft.world.WorldServer; +import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.LivingAttackEvent; import net.minecraftforge.event.entity.living.LivingHurtEvent; @@ -47,6 +51,23 @@ public class CinderEventHandler implements IFuelHandler { MinecraftForge.TERRAIN_GEN_BUS.register(this); GameRegistry.registerFuelHandler(this); } + + @SubscribeEvent + public void onWorldTick(TickEvent.WorldTickEvent event) { + World world = event.world; + if (world.isRemote) + return; + if (event.phase == TickEvent.Phase.END) { + if (world == DimensionManager.getWorld(LOTRDimension.MIDDLE_EARTH.dimensionID)) { + if (!world.playerEntities.isEmpty()) { + if (world.getTotalWorldTime() % 20L == 0L) { + PacketWarbandLocations.send_warband_locations(world); + } + } + } + } + } + @SubscribeEvent public void onArrowLoose(ArrowLooseEvent event) { Entity attacker = event.entityLiving; diff --git a/src/main/java/com/zivilon/cinder_loe/CinderLoE.java b/src/main/java/com/zivilon/cinder_loe/CinderLoE.java index e1a2279..4079fa5 100644 --- a/src/main/java/com/zivilon/cinder_loe/CinderLoE.java +++ b/src/main/java/com/zivilon/cinder_loe/CinderLoE.java @@ -7,6 +7,7 @@ import com.zivilon.cinder_loe.client.render.*; import com.zivilon.cinder_loe.client.render.corrupt.*; import com.zivilon.cinder_loe.client.render.projectile.*; import com.zivilon.cinder_loe.command.CommandCinderCharacter; +import com.zivilon.cinder_loe.command.CommandWarband; import com.zivilon.cinder_loe.entity.*; import com.zivilon.cinder_loe.entity.corrupt.*; import com.zivilon.cinder_loe.entity.npc.*; @@ -23,6 +24,7 @@ import com.zivilon.cinder_loe.entity.npc.radagast.*; import com.zivilon.cinder_loe.entity.projectile.*; import com.zivilon.cinder_loe.entity.trader.*; import com.zivilon.cinder_loe.items.*; +import com.zivilon.cinder_loe.network.*; import com.zivilon.cinder_loe.potion.LoEPotions; import com.zivilon.cinder_loe.tileentity.*; import com.zivilon.cinder_loe.util.Utilities; @@ -321,6 +323,7 @@ public class CinderLoE { registerBlocks(); registerItems(); ItemRegistration.registerItems(); + PacketRegistration.register(); registerEntities(); modEventHandler = new CinderEventHandler(); LoEPotions.registerPotions(); @@ -359,6 +362,7 @@ public class CinderLoE { public void serverStarting(FMLServerStartingEvent event) { CharacterRoleAPI.loadRolesFromFile(); event.registerServerCommand(new CommandCinderCharacter()); + event.registerServerCommand(new CommandWarband()); } public void registerEntities() { // Last ID added: 60 diff --git a/src/main/java/com/zivilon/cinder_loe/CinderLoE_Config.java b/src/main/java/com/zivilon/cinder_loe/CinderLoE_Config.java index dd81b1a..d8639bf 100644 --- a/src/main/java/com/zivilon/cinder_loe/CinderLoE_Config.java +++ b/src/main/java/com/zivilon/cinder_loe/CinderLoE_Config.java @@ -13,6 +13,7 @@ public class CinderLoE_Config { public static float enchantment_color_green; public static float enchantment_color_blue; public static String corrupt_faction; + public static String skeleton_faction; public static boolean objective_lindon; public static boolean objective_arnor; @@ -41,7 +42,8 @@ public class CinderLoE_Config { enchantment_color_green = config.getFloat("EnchantmentColorGreen", Configuration.CATEGORY_GENERAL, 0.19f, 0.0f, 1.0f, "Configure green color for enchantments"); enchantment_color_blue = config.getFloat("EnchantmentColorBlue", Configuration.CATEGORY_GENERAL, 0.608f, 0.0f, 1.0f, "Configure blue color for enchantments"); - corrupt_faction = config.getString("CorruptFaction", Configuration.CATEGORY_GENERAL, "MORDOR", "Configure the alignment the Corrupt npcs follow"); + corrupt_faction = config.getString("CorruptFaction", Configuration.CATEGORY_GENERAL, "UTUMNO", "Configure the alignment the Corrupt npcs follow"); + skeleton_faction = config.getString("SkeletonFaction", Configuration.CATEGORY_GENERAL, "UTUMNO", "Configure the alignment the Skeleton npcs follow"); objective_lindon = config.getBoolean("Lindon", Configuration.CATEGORY_GENERAL, false, "set true if Lindon Objective Complete"); objective_arnor = config.getBoolean("Arnor", Configuration.CATEGORY_GENERAL, false,"set true if Arnor Objective Complete"); diff --git a/src/main/java/com/zivilon/cinder_loe/command/CommandWarband.java b/src/main/java/com/zivilon/cinder_loe/command/CommandWarband.java new file mode 100644 index 0000000..2b4dc85 --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/command/CommandWarband.java @@ -0,0 +1,151 @@ +package com.zivilon.cinder_loe.command; + +import com.zivilon.cinder_loe.world.event.Warband; +import com.zivilon.cinder_loe.world.event.WarbandFaction; + +import net.minecraft.command.CommandBase; +import net.minecraft.command.ICommandSender; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.ChatComponentText; + +import lotr.common.world.map.LOTRWaypoint; + +import com.zivilon.cinder_loe.character.CharacterRoleAPI; +import com.zivilon.cinder_loe.util.Utilities; + +import java.util.UUID; + +public class CommandWarband extends CommandBase { + @Override + public String getCommandName() { + return "warband"; + } + + @Override + public String getCommandUsage(ICommandSender sender) { + return "/warband [faction_name] [waypoint] [x] [z]"; + } + + @Override + public int getRequiredPermissionLevel() { + return 4; + } + + @Override + public void processCommand(ICommandSender sender, String[] args) { + if(!validate_args(args)) { + sender.addChatMessage(new ChatComponentText("Incorrect arguments. Usage: " + getCommandUsage(sender))); + return; + } + + String action = args[0]; + System.out.println("Checking arg " + action); + switch (action) { + case "reset": + reset_warband(); + sender.addChatMessage(new ChatComponentText("Warband timer has been reset. A new warband may now spawn.")); + return; + case "list": + list_warbands(sender); + return; + case "summon": + summon_warband(sender, args); + return; + } + } + + public void summon_warband(ICommandSender sender, String[] args) { + WarbandFaction faction = WarbandFaction.get_warband_by_name(args[1]); + LOTRWaypoint waypoint = null; + String waypoint_name = null; + int x = 0; + int z = 0; + + if (args.length == 2) { + if (!(sender instanceof EntityPlayer)) { + System.out.println("Console must specify location to summon warband. Options:"); + System.out.println("/warband "); + System.out.println("/warband "); + return; + } + EntityPlayer player = (EntityPlayer)sender; + x = (int)player.posX; + z = (int)player.posZ; + Warband.initialize_warband(faction, x, z); + } + + if (args.length == 3) { + waypoint_name = args[2]; + waypoint = LOTRWaypoint.waypointForName(waypoint_name); + if (waypoint == null) { + sender.addChatMessage(new ChatComponentText("Invalid waypoint \"" + waypoint_name + "\"")); + } + Warband.initialize_warband(faction, waypoint); + return; + } + + if (args.length == 4) { + try { + x = Integer.parseInt(args[2]); + z = Integer.parseInt(args[3]); + } catch (Exception e) { + sender.addChatMessage(new ChatComponentText("Invalid coordinates provided")); + return; + } + Warband.initialize_warband(faction, x, z); + return; + } + + if (args.length > 4) { + try { + x = Integer.parseInt(args[3]); + z = Integer.parseInt(args[4]); + } catch (Exception e) { + sender.addChatMessage(new ChatComponentText("Invalid coordinates provided")); + return; + } + waypoint_name = args[2]; + waypoint = LOTRWaypoint.waypointForName(waypoint_name); + if (waypoint == null) { + sender.addChatMessage(new ChatComponentText("Invalid waypoint \"" + waypoint_name + "\"")); + return; + } + Warband.initialize_warband(faction, waypoint, x, z); + return; + } + } + + public static boolean validate_args(String[] args) { + System.out.println("Validating..."); + if (args.length < 1) return false; + String action = ""; + System.out.println("Checking arg \"" + args[0] + "\""); + if (args[0].equals("summon") || args[0].equals("reset") || args[0].equals("list")) { + action = args[0]; + } else { + System.out.println("Failed test 1"); + return false; + } + if (action.equals("summon")) { + if (args.length < 2) { + System.out.println("Failed test 2"); + return false; + } + WarbandFaction faction = WarbandFaction.get_warband_by_name(args[1]); + if (faction == null) return false; + } + return true; + } + + public static void reset_warband() { + // Set last warband to have happened 10 hours ago, thus allowing new warband + Warband.last_warband_timestamp = System.currentTimeMillis() / 1000L - (60*60*10); + } + public static void list_warbands(ICommandSender sender) { + sender.addChatMessage(new ChatComponentText("List of valid warbands:")); + for (WarbandFaction faction : WarbandFaction.values()) { + sender.addChatMessage(new ChatComponentText("- " + faction.name())); + } + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/droptables/DropTable.java b/src/main/java/com/zivilon/cinder_loe/droptables/DropTable.java index b472e03..c980bc3 100644 --- a/src/main/java/com/zivilon/cinder_loe/droptables/DropTable.java +++ b/src/main/java/com/zivilon/cinder_loe/droptables/DropTable.java @@ -27,7 +27,7 @@ public class DropTable { public static void drop_items(LOTREntityNPC entity, DropContext[] context_flags, int looting_level) { List drops = generate_drops(entity, context_flags, looting_level); - if (drops == null) return; + if (drops == null || drops.size() < 1) return; for (ItemStack drop : drops) { entity.npcDropItem(drop, 0.0F, false, false); } @@ -35,9 +35,12 @@ public class DropTable { public static List generate_drops(LOTREntityNPC entity, DropContext[] context_flags, int looting_level) { DropTable table = ((ILootableEntity)entity).get_drop_table(); - if (table == null) return null; - if (context_flags == null) context_flags = new DropContext[0]; - + if (table == null) { + return null; + } + if (context_flags == null) { + context_flags = new DropContext[0]; + } List results = new ArrayList<>(); for (DropInstance drop : table.drop_list) { ItemStack stack = get_drop(drop, looting_level, context_flags); @@ -49,8 +52,7 @@ public class DropTable { } public static ItemStack get_drop(DropInstance drop, int looting_level, DropContext[] context) { - if (!(Utilities.array_contains_array(drop.conditions, context))) return null; - + if (!(Utilities.array_contains_array(context, drop.conditions))) return null; if (drop instanceof SingleItemDrop) { return get_single_drop((SingleItemDrop)drop, looting_level); } diff --git a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptHobbit.java b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptHobbit.java index 36021e6..6a57528 100644 --- a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptHobbit.java +++ b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptHobbit.java @@ -1,5 +1,6 @@ package com.zivilon.cinder_loe.entity.corrupt; +import com.zivilon.cinder_loe.CinderLoE_Config; import lotr.common.LOTRAchievement; import lotr.common.LOTRFoods; import lotr.common.LOTRMod; @@ -58,7 +59,7 @@ public class CorruptHobbit extends LOTREntityHobbitBounder { } @Override public LOTRFaction getFaction() { - return this.faction != null ? this.faction : LOTRFaction.UTUMNO; + return LOTRFaction.valueOf(CinderLoE_Config.corrupt_faction); } @Override protected float getSoundPitch() { diff --git a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptMan.java b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptMan.java index 0a46069..ab2d75b 100644 --- a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptMan.java +++ b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptMan.java @@ -21,6 +21,8 @@ public class CorruptMan extends LOTREntityGondorMan { public CorruptMan(World world) { super(world); + ((EntityLiving) this).tasks.addTask(6, (EntityAIBase) new LOTREntityAIEat(this, LOTRFoods.ORC, 8000)); + ((EntityLiving) this).tasks.addTask(6, (EntityAIBase) new LOTREntityAIDrink(this, LOTRFoods.ORC_DRINK, 8000)); this.addTargetTasks(true); } @Override diff --git a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeleton.java b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeleton.java index 94777c3..fadbf8c 100644 --- a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeleton.java +++ b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeleton.java @@ -1,6 +1,7 @@ package com.zivilon.cinder_loe.entity.corrupt; import com.zivilon.cinder_loe.CinderLoE_Config; +import lotr.common.LOTRLevelData; import lotr.common.entity.ai.LOTREntityAIAttackOnCollide; import lotr.common.entity.npc.LOTREntityGondorMan; import lotr.common.entity.npc.LOTRNames; @@ -41,7 +42,15 @@ public class CorruptSkeleton extends CorruptMan { @Override public LOTRFaction getFaction() { - return LOTRFaction.UTUMNO; + /** + * ok doesnt work, will need an alternative, maybe a new method + if (hiredNPCInfo.getHiringPlayer() != null) { + if (LOTRLevelData.getData(hiredNPCInfo.getHiringPlayer()).getPledgeFaction() != null) { + return LOTRFaction.valueOf(String.valueOf(LOTRLevelData.getData(hiredNPCInfo.getHiringPlayer()).getPledgeFaction())); + } + } + */ + return LOTRFaction.valueOf(CinderLoE_Config.skeleton_faction); } @Override diff --git a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeletonArcher.java b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeletonArcher.java index 58ef61e..a6b7fe5 100644 --- a/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeletonArcher.java +++ b/src/main/java/com/zivilon/cinder_loe/entity/corrupt/CorruptSkeletonArcher.java @@ -57,12 +57,6 @@ public class CorruptSkeletonArcher extends CorruptSkeleton { } } - - @Override - public LOTRFaction getFaction() { - return LOTRFaction.UTUMNO; - } - @Override public String getNPCName() { return this.familyInfo.getName(); diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinEntityLivingBase.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinEntityLivingBase.java index 7f10045..ade4623 100644 --- a/src/main/java/com/zivilon/cinder_loe/mixins/MixinEntityLivingBase.java +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinEntityLivingBase.java @@ -1,6 +1,9 @@ package com.zivilon.cinder_loe.mixins; import com.zivilon.cinder_loe.util.*; +import com.zivilon.cinder_loe.world.event.Warband; +import com.zivilon.cinder_loe.world.event.WarbandLocationInfo; +import com.zivilon.cinder_loe.world.event.WarbandTracker; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.*; @@ -15,7 +18,10 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.potion.Potion; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ChatComponentText; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.ChatStyle; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; @@ -257,14 +263,36 @@ public abstract class MixinEntityLivingBase extends Entity implements IEntityLiv } } + public void setDead() { + super.setDead(); + if (this.warband_uuid != null && this.warband_uuid.equals(this.getUniqueID())) { + WarbandLocationInfo info = WarbandTracker.locations.get(this.warband_uuid); + String faction_name = ""; + if (info != null && info.warband != null && info.warband.faction != null) { + faction_name = info.warband.faction.faction.untranslatedFactionName(); + } + ChatComponentTranslation message; + if (!faction_name.equals("")) { + message = new ChatComponentTranslation( + "warband.defeated.faction", + new ChatComponentTranslation(faction_name) + ); + } else { + message = new ChatComponentTranslation( + "warband.defeated.no_faction" + ); + } + message.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GRAY)); + MinecraftServer.getServer().getConfigurationManager().sendChatMsg(message); + WarbandTracker.remove(this.warband_uuid); + } + } + @Inject(method = "onUpdate", at = @At("TAIL")) private void onUpdate(CallbackInfo ci) { if (despawn_timer > -1) { despawn_timer--; if (despawn_timer == 0) { - if (warband_uuid == ((EntityLivingBase)(Object)this).getUniqueID()) { - MinecraftServer.getServer().getConfigurationManager().sendChatMsg(new ChatComponentText(EnumChatFormatting.GRAY + "Warband has disbanded")); - } ((EntityLivingBase)(Object)this).setDead(); } } diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java index a4af150..c1fbe49 100644 --- a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java @@ -4,6 +4,7 @@ import com.zivilon.cinder_loe.CinderLoE; import com.zivilon.cinder_loe.client.model.*; import com.zivilon.cinder_loe.entity.Renegade; import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,35 +28,39 @@ import java.util.UUID; @Mixin(LOTREntityAIAttackOnCollide.class) public class MixinLOTREntityAIAttackOnCollide { - @Shadow + @Shadow(remap = false) protected World worldObj; - @Shadow + @Shadow(remap = false) protected EntityCreature theOwner; - @Shadow + @Shadow(remap = false) protected EntityLivingBase attackTarget; - @Shadow + @Shadow(remap = false) protected int attackTick; - @Shadow + @Shadow(remap = false) protected void updateLookAndPathing() {} public UUID leader_id; public Entity leader; @Overwrite public void updateTask() { + if (warband_task()) return; + update_vanilla_task(); + } + + private boolean warband_task() { EntityCreature entity = this.theOwner; UUID leader_id = ((IEntityLivingBase)entity).get_warband_uuid(); if (leader_id != null) { if (leader == null) - leader = find_entity_by_uuid(entity.worldObj, leader_id); + leader = Utilities.find_entity_by_uuid(entity.worldObj, leader_id); if (leader != null && entity.getDistanceSqToEntity(leader) > 576.0D) { entity.setAttackTarget(null); entity.getNavigator().tryMoveToEntityLiving(leader, 1.3D); - return; // Return here to not run default logic + return true; // Return here to not run default logic } } - - update_vanilla_task(); + return false; } private void update_vanilla_task() { @@ -95,13 +100,4 @@ public class MixinLOTREntityAIAttackOnCollide { this.theOwner.swingItem(); } } - - private Entity find_entity_by_uuid(World world, UUID uuid) { - for (Object obj : world.loadedEntityList) { - if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { - return (Entity)obj; - } - } - return null; - } } diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java index d52413c..7101456 100644 --- a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java @@ -3,6 +3,7 @@ package com.zivilon.cinder_loe.mixins; import com.zivilon.cinder_loe.entity.Renegade; import com.zivilon.cinder_loe.potion.LoEPotions; import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; import lotr.common.LOTRLevelData; import lotr.common.LOTRMod; @@ -52,25 +53,29 @@ public abstract class MixinLOTREntityAINearestAttackableTargetBasic extends Enti @Overwrite(remap = true) public boolean shouldExecute() { + if (warband_should_execute()) return false; + return original_should_execute(); + } + + private boolean warband_should_execute() { EntityCreature self = taskOwner; - if (!(self instanceof IEntityLivingBase)) return original_should_execute(); + if (!(self instanceof IEntityLivingBase)) return false; UUID leader_id = ((IEntityLivingBase) self).get_warband_uuid(); - if (leader_id == null) return original_should_execute(); + if (leader_id == null) return false; - Entity leader = find_entity_by_uuid(self.worldObj, leader_id); - if (leader == null) return original_should_execute(); + Entity leader = Utilities.find_entity_by_uuid(self.worldObj, leader_id); + if (leader == null) return false; double distance_squared = self.getDistanceSqToEntity(leader); if (distance_squared > 576.0D) { self.setAttackTarget(null); self.getNavigator().tryMoveToEntityLiving(leader, 1.3D); - return false; + return true; } - return original_should_execute(); + return false; } - public boolean original_should_execute() { if (this.targetChance > 0 && this.taskOwner.getRNG().nextInt(this.targetChance) != 0) return false; @@ -97,15 +102,6 @@ public abstract class MixinLOTREntityAINearestAttackableTargetBasic extends Enti return true; } - private Entity find_entity_by_uuid(World world, UUID uuid) { - for (Object obj : world.loadedEntityList) { - if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { - return (Entity)obj; - } - } - return null; - } - /** * @author Shinare * @reason Added corrupting potion effect that makes all NPCs hostile diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIOrcSkirmish.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIOrcSkirmish.java new file mode 100644 index 0000000..3d56d18 --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIOrcSkirmish.java @@ -0,0 +1,26 @@ +package com.zivilon.cinder_loe.mixins; + +import com.zivilon.cinder_loe.util.IEntityLivingBase; + +import lotr.common.entity.npc.LOTREntityOrc; +import lotr.common.entity.ai.LOTREntityAIOrcSkirmish; + +import net.minecraft.entity.EntityLivingBase; + +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.*; + +@Mixin(LOTREntityAIOrcSkirmish.class) +public class MixinLOTREntityAIOrcSkirmish { + + @Overwrite(remap = false) + private boolean canOrcSkirmish(EntityLivingBase entity) { + if (entity instanceof LOTREntityOrc) { + LOTREntityOrc orc = (LOTREntityOrc)entity; + if (((IEntityLivingBase)orc).get_warband_uuid() != null) return false; + return (!orc.isTrader() && !orc.hiredNPCInfo.isActive && orc.ridingEntity == null && orc.canOrcSkirmish()); + } + return false; + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java new file mode 100644 index 0000000..dad0ebb --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java @@ -0,0 +1,119 @@ +package com.zivilon.cinder_loe.mixins; + +import com.zivilon.cinder_loe.CinderLoE; +import com.zivilon.cinder_loe.client.model.*; +import com.zivilon.cinder_loe.entity.Renegade; +import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Overwrite; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.IRangedAttackMob; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; + +import lotr.common.entity.npc.LOTREntityNPC; +import lotr.common.entity.ai.LOTREntityAIRangedAttack; +import lotr.common.item.LOTRItemSpear; +import lotr.common.item.LOTRWeaponStats; + +import java.util.UUID; + +@Mixin(LOTREntityAIRangedAttack.class) +public class MixinLOTREntityAIRangedAttack { + + @Shadow(remap = false) + private EntityLiving theOwner; + @Shadow(remap = false) + private IRangedAttackMob theOwnerRanged; + @Shadow(remap = false) + private EntityLivingBase attackTarget; + @Shadow(remap = false) + private int rangedAttackTime; + @Shadow(remap = false) + private double moveSpeed; + @Shadow(remap = false) + private double moveSpeedFlee = 1.5D; + @Shadow(remap = false) + private int repathDelay; + @Shadow(remap = false) + private int attackTimeMin; + @Shadow(remap = false) + private int attackTimeMax; + @Shadow(remap = false) + private float attackRange; + @Shadow(remap = false) + private float attackRangeSq; + @Shadow(remap = false) + public static Vec3 findPositionAwayFrom(EntityLivingBase entity, EntityLivingBase target, int min, int max) {return null;} + + public UUID leader_id; + public Entity leader; + + @Overwrite + public void updateTask() { + if (warband_task()) return; + update_vanilla_task(); + } + + private boolean warband_task() { + EntityLiving entity = this.theOwner; + UUID leader_id = ((IEntityLivingBase)entity).get_warband_uuid(); + + if (leader_id != null) { + if (leader == null) + leader = Utilities.find_entity_by_uuid(entity.worldObj, leader_id); + if (leader != null && entity.getDistanceSqToEntity(leader) > 576.0D) { + entity.setAttackTarget(null); + entity.getNavigator().tryMoveToEntityLiving(leader, 1.3D); + return true; // Return here to not run default logic + } + } + return false; + } + + private void update_vanilla_task() { + double distanceSq = this.theOwner.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ); + boolean canSee = this.theOwner.getEntitySenses().canSee((Entity)this.attackTarget); + if (canSee) { + this.repathDelay++; + } else { + this.repathDelay = 0; + } + if (distanceSq <= this.attackRangeSq) { + if (this.theOwner.getDistanceSqToEntity((Entity)this.attackTarget) < 25.0D) { + Vec3 vec = findPositionAwayFrom((EntityLivingBase)this.theOwner, this.attackTarget, 8, 16); + if (vec != null) + this.theOwner.getNavigator().tryMoveToXYZ(vec.xCoord, vec.yCoord, vec.zCoord, this.moveSpeedFlee); + } else if (this.repathDelay >= 20) { + this.theOwner.getNavigator().clearPathEntity(); + this.repathDelay = 0; + } + } else { + this.theOwner.getNavigator().tryMoveToEntityLiving((Entity)this.attackTarget, this.moveSpeed); + } + this.theOwner.getLookHelper().setLookPositionWithEntity((Entity)this.attackTarget, 30.0F, 30.0F); + this.rangedAttackTime--; + if (this.rangedAttackTime == 0) { + if (distanceSq > this.attackRangeSq || !canSee) + return; + float distanceRatio = MathHelper.sqrt_double(distanceSq) / this.attackRange; + float power = distanceRatio; + power = MathHelper.clamp_float(power, 0.1F, 1.0F); + this.theOwnerRanged.attackEntityWithRangedAttack(this.attackTarget, power); + this.rangedAttackTime = MathHelper.floor_float(distanceRatio * (this.attackTimeMax - this.attackTimeMin) + this.attackTimeMin); + } else if (this.rangedAttackTime < 0) { + float distanceRatio = MathHelper.sqrt_double(distanceSq) / this.attackRange; + this.rangedAttackTime = MathHelper.floor_float(distanceRatio * (this.attackTimeMax - this.attackTimeMin) + this.attackTimeMin); + } + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTRGuiMap.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTRGuiMap.java new file mode 100644 index 0000000..3a89dea --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTRGuiMap.java @@ -0,0 +1,139 @@ +package com.zivilon.cinder_loe.mixins; + +import com.zivilon.cinder_loe.world.event.Warband; +import com.zivilon.cinder_loe.world.event.WarbandTracker; +import com.zivilon.cinder_loe.world.event.WarbandLocationInfo; + +import lotr.client.gui.LOTRGuiMap; +import lotr.client.gui.LOTRGuiMenuBase; +import lotr.client.LOTRClientProxy; +import lotr.common.LOTRLevelData; +import lotr.common.fac.LOTRFaction; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.lwjgl.opengl.GL11; + +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.*; + + +@Mixin(LOTRGuiMap.class) +public abstract class MixinLOTRGuiMap extends LOTRGuiMenuBase { + private static Map warband_locations = WarbandTracker.locations; + private static ResourceLocation WARBAND_ICON = new ResourceLocation("cinderloe", "textures/gui/alignment.png"); + + @Shadow(remap = false) + private boolean loadingConquestGrid; + @Shadow(remap = false) + private boolean hasOverlay; + @Shadow(remap = false) + private static int mapXMin; + @Shadow(remap = false) + private static int mapXMax; + @Shadow(remap = false) + private static int mapYMin; + @Shadow(remap = false) + private static int mapYMax; + @Shadow(remap = false) + private void drawFancyRect(int x1, int y1, int x2, int y2) {} + @Shadow(remap = false) + public float[] transformCoords(float x, float z) { return null;} + + @Inject(method = "func_73863_a", at = @At("HEAD"), remap = false) + public void inject_head(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { + System.out.println("[MixinLOTRGuiMap] Inject at HEAD"); + } + @Inject(method = "func_73863_a", at = @At( value = "INVOKE", target = "renderPlayers(II)V", shift = At.Shift.AFTER), remap = false) + public void inject_render_warbands(int mouseX, int mouseY, float partialTicks, CallbackInfo ci) { + System.out.println("[MixinLOTRGuiMap] Running wrapper"); + render_warbands(mouseX, mouseY); + } + + @Dynamic + private void render_warbands(int cursor_x, int cursor_y) { + System.out.println("[MixinLOTRGuiMap] Rendering warband icon"); + String mouse_over_warband_name = null; + double mouse_over_warband_x = 0.0D; + double mouse_over_warband_y = 0.0D; + double shortest_distance_to_cursor = Double.MAX_VALUE; + int icon_width_half = 4; + for (Map.Entry entry : warband_locations.entrySet()) { + System.out.println("[MixinLOTRGuiMap] Iterated"); + WarbandLocationInfo info = entry.getValue(); + Warband warband = info.warband; + String warband_name = warband.faction.warband_name; + float[] pos = transformCoords((float)info.x, (float)info.z); + int map_x = Math.round(pos[0]); + int map_y = Math.round(pos[1]); + + double distance_to_icon = render_warband_icon(warband, map_x, map_y, cursor_x, cursor_y); + if (distance_to_icon <= (icon_width_half + 3)) { + if (distance_to_icon <= shortest_distance_to_cursor) { + mouse_over_warband_name = StatCollector.translateToLocal(warband_name); + mouse_over_warband_x = map_x; + mouse_over_warband_y = map_y; + shortest_distance_to_cursor = distance_to_icon; + } + } + } + if (mouse_over_warband_name != null && !this.hasOverlay && !this.loadingConquestGrid) { + int name_width = this.mc.fontRenderer.getStringWidth(mouse_over_warband_name); + int name_height = this.mc.fontRenderer.FONT_HEIGHT; + int namebox_x = (int)Math.round(mouse_over_warband_x); + int namebox_y = (int)Math.round(mouse_over_warband_y); + namebox_y += icon_width_half + 3; + int border = 3; + int namebox_width = name_width + border * 2; + namebox_x -= namebox_width / 2; + int namebox_height = name_height + border * 2; + int map_border = 2; + namebox_x = Math.max(namebox_x, mapXMin + map_border); + namebox_x = Math.min(namebox_x, mapXMax - map_border - namebox_width); + namebox_y = Math.max(namebox_y, mapYMin + map_border); + namebox_y = Math.min(namebox_y, mapYMax - map_border - namebox_height); + GL11.glTranslatef(0.0F, 0.0F, 300.0F); + drawFancyRect(namebox_x, namebox_y, namebox_x + namebox_width, namebox_y + namebox_height); + this.mc.fontRenderer.drawString(mouse_over_warband_name, namebox_x + border, namebox_y + border, 16777215); + GL11.glTranslatef(0.0F, 0.0F, -300.0F); + } + } + + @Dynamic + private double render_warband_icon(Warband warband, double map_x, double map_y, int mouse_x, int mouse_y) { + int icon_half = 4; + int icon_border = icon_half + 1; + + map_x = Math.max(mapXMin + icon_border, Math.min(mapXMax - icon_border - 1, map_x)); + map_y = Math.max(mapYMin + icon_border, Math.min(mapYMax - icon_border - 1, map_y)); + + // Determine ally/enemy icon + LOTRFaction faction = warband.faction.faction; + float alignment = LOTRLevelData.getData(mc.thePlayer).getAlignment(faction); + boolean is_ally = alignment > 0.0F; + + load_warband_icon(is_ally, (int) map_x, (int) map_y); + + // Return mouse distance to icon + double dx = map_x - mouse_x; + double dy = map_y - mouse_y; + return Math.hypot(dx, dy); + } + + + @Dynamic + private void load_warband_icon(boolean ally, int x, int y) { + System.out.println("[MixinLOTRGuiMap] Loading warband icon: " + (ally ? "ally" : "enemy")); + mc.getTextureManager().bindTexture(LOTRClientProxy.alignmentTexture); + GL11.glColor4f(1F, 1F, 1F, 1F); + int variant = ally ? 16 : 0; + drawTexturedModalRect(x - 8, y - 8, variant, 228, 16, 16); + } + +} diff --git a/src/main/java/com/zivilon/cinder_loe/network/PacketRegistration.java b/src/main/java/com/zivilon/cinder_loe/network/PacketRegistration.java new file mode 100644 index 0000000..e2a9114 --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/network/PacketRegistration.java @@ -0,0 +1,12 @@ +package com.zivilon.cinder_loe.network; + +import com.zivilon.cinder_loe.network.PacketWarbandLocations.Handler; +import lotr.common.network.LOTRPacketHandler; +import cpw.mods.fml.relauncher.Side; + +public class PacketRegistration { + public static void register() { + int id = 200; + LOTRPacketHandler.networkWrapper.registerMessage(PacketWarbandLocations.Handler.class, PacketWarbandLocations.class, id++, Side.CLIENT); + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/network/PacketWarbandLocations.java b/src/main/java/com/zivilon/cinder_loe/network/PacketWarbandLocations.java new file mode 100644 index 0000000..d1e08e5 --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/network/PacketWarbandLocations.java @@ -0,0 +1,115 @@ +package com.zivilon.cinder_loe.network; + +import com.zivilon.cinder_loe.world.event.Warband; +import com.zivilon.cinder_loe.world.event.WarbandFaction; +import com.zivilon.cinder_loe.world.event.WarbandLocationInfo; +import com.zivilon.cinder_loe.world.event.WarbandTracker; + +import cpw.mods.fml.common.FMLLog; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import lotr.common.LOTRMod; +import lotr.common.network.LOTRPacketHandler; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.PacketBuffer; +import net.minecraft.world.World; + +public class PacketWarbandLocations implements IMessage { + public List locations = WarbandTracker.get_all(); + + @Override + public void toBytes(ByteBuf buf) { + buf.writeShort(locations.size()); + for (WarbandLocationInfo loc : locations) { + buf.writeLong(loc.warband.warband_uuid.getMostSignificantBits()); + buf.writeLong(loc.warband.warband_uuid.getLeastSignificantBits()); + buf.writeDouble(loc.x); + buf.writeDouble(loc.z); + PacketBuffer packet = new PacketBuffer(buf); + write_string_to_buffer(packet, loc.warband.faction.name()); + } + } + + @Override + + public void fromBytes(ByteBuf buf) { + locations.clear(); + int count = buf.readShort(); + for (int i = 0; i < count; i++) { + long msb = buf.readLong(); + long lsb = buf.readLong(); + UUID uuid = new UUID(msb, lsb); + double x = buf.readDouble(); + double z = buf.readDouble(); + + PacketBuffer packet = new PacketBuffer(buf); + String faction_name = read_string_from_buffer(packet, Short.MAX_VALUE); + + WarbandFaction faction = WarbandFaction.get_warband_by_name(faction_name); + + Warband dummy = new Warband(); + dummy.warband_uuid = uuid; + dummy.faction = faction; + dummy.x = (int) x; + dummy.z = (int) z; + locations.add(new WarbandLocationInfo(dummy, x, z)); + } + } + + public static class Handler implements IMessageHandler { + @Override + public IMessage onMessage(PacketWarbandLocations message, MessageContext ctx) { + if (ctx.side.isServer()) { + System.out.println("[PacketWarbandLocations] WARNING: Client tried to update locations on server!"); + return null; + } + + WarbandTracker.clear_locations(); + for (WarbandLocationInfo info : message.locations) { + WarbandTracker.add(info); + } + return null; + } + } + + public static void send_warband_locations(World world) { + for (int i = 0; i < world.playerEntities.size(); i++) { + EntityPlayer entityplayer = (EntityPlayer)world.playerEntities.get(i); + send_location(entityplayer, world); + } + } + + public static void send_location(EntityPlayer player, World world) { + PacketWarbandLocations locations = new PacketWarbandLocations(); + LOTRPacketHandler.networkWrapper.sendTo((IMessage)locations, (EntityPlayerMP)player); + } + public static void write_string_to_buffer(PacketBuffer buffer, String string) { + try { + buffer.writeStringToBuffer(string); + } catch (IOException e) { + throw new RuntimeException("[PacketWarbandLocations] WARNING: Failed to write warband faction", e); + } + } + + public static String read_string_from_buffer(PacketBuffer buffer, int max_length) { + try { + return buffer.readStringFromBuffer(max_length); + } catch (IOException e) { + throw new RuntimeException("[PacketWarbandLocations] WARNING: Failed to read warband faction", e); + } + } + +} diff --git a/src/main/java/com/zivilon/cinder_loe/util/Utilities.java b/src/main/java/com/zivilon/cinder_loe/util/Utilities.java index 5f9c676..d38ee6b 100644 --- a/src/main/java/com/zivilon/cinder_loe/util/Utilities.java +++ b/src/main/java/com/zivilon/cinder_loe/util/Utilities.java @@ -3,6 +3,7 @@ package com.zivilon.cinder_loe.util; import com.zivilon.cinder_loe.CinderLoE; import com.zivilon.cinder_loe.client.render.item.RenderHelper; import com.zivilon.cinder_loe.mixins.MixinEntity; +import com.zivilon.cinder_loe.droptables.*; import java.io.BufferedWriter; import java.io.FileOutputStream; @@ -46,6 +47,7 @@ import net.minecraft.nbt.NBTTagString; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; public class Utilities { @@ -328,4 +330,12 @@ public class Utilities { } return true; } + public static Entity find_entity_by_uuid(World world, UUID uuid) { + for (Object obj : world.loadedEntityList) { + if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { + return (Entity)obj; + } + } + return null; + } } diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java b/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java index 6de85ef..cddfa70 100644 --- a/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java +++ b/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java @@ -18,12 +18,17 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.*; import net.minecraft.world.World; +import cpw.mods.fml.common.FMLCommonHandler; + import lotr.common.LOTRDimension; import lotr.common.LOTRMod; import lotr.common.entity.npc.LOTRSpeech; import lotr.common.entity.npc.LOTREntityNPC; +import lotr.common.fac.LOTRFaction; import lotr.common.world.biome.LOTRBiome; import lotr.common.world.map.LOTRWaypoint; +import lotr.common.world.map.LOTRConquestGrid; +import lotr.common.world.map.LOTRConquestZone; import java.util.ArrayList; import java.util.List; @@ -32,13 +37,19 @@ import java.util.UUID; public class Warband { public static Random random = new Random(); - public static World world = MinecraftServer.getServer().worldServerForDimension(LOTRDimension.MIDDLE_EARTH.dimensionID); - public static long last_warband_timestamp = System.currentTimeMillis() / 1000L - (60*60*4); + public static World world;; + public static long last_warband_timestamp = System.currentTimeMillis() / 1000L - (60*60*2); // Initialize at 2 hour cooldown on server startup + + static { + if (FMLCommonHandler.instance().getSide().isServer()) { + world = MinecraftServer.getServer().worldServerForDimension(LOTRDimension.MIDDLE_EARTH.dimensionID); + } + } public int x = 0; public int z = 0; - public String direction = "null"; - public String waypoint_name = "null"; + public String direction = null; + public String waypoint_name = null; public WarbandFaction faction = null; public UUID warband_uuid = null; @@ -52,32 +63,50 @@ public class Warband { } public static void initialize_warband() { + LOTRWaypoint waypoint = get_random_waypoint(); + initialize_warband(null, waypoint, true, null, null); + } + public static void initialize_warband(WarbandFaction faction, LOTRWaypoint waypoint) { + initialize_warband(faction, waypoint, true, null, null); + } + public static void initialize_warband(WarbandFaction faction, Integer x, Integer z) { + initialize_warband(faction, null, false, x, z); + } + public static void initialize_warband(WarbandFaction faction, LOTRWaypoint waypoint, Integer x, Integer z) { + initialize_warband(faction, waypoint, false, x, z); + } + public static void initialize_warband(WarbandFaction faction, LOTRWaypoint waypoint, boolean randomize, Integer x, Integer z) { if (MinecraftServer.getServer().getConfigurationManager().playerEntityList.size() < 1) return; Warband warband = new Warband(); - LOTRWaypoint waypoint = get_random_waypoint(); - warband.waypoint_name = "lotr.waypoint." + waypoint.getCodeName(); - - warband.x = waypoint.getXCoord(); - warband.z = waypoint.getZCoord(); - - switch (random.nextInt(8)) { - case 0: warband.direction = "North"; warband.z += random.nextInt(701) - 1000; break; - case 1: warband.direction = "South"; warband.z += random.nextInt(701) + 300; break; - case 2: warband.direction = "East"; warband.x += random.nextInt(701) + 300; break; - case 3: warband.direction = "West"; warband.x += random.nextInt(701) - 1000; break; - case 4: warband.direction = "North-East"; warband.z += random.nextInt(701) - 1000; warband.x += random.nextInt(701) + 300; break; - case 5: warband.direction = "North-West"; warband.z += random.nextInt(701) - 1000; warband.x += random.nextInt(701) - 1000; break; - case 6: warband.direction = "South-East"; warband.z += random.nextInt(701) + 300; warband.x += random.nextInt(701) + 300; break; - case 7: warband.direction = "South-West"; warband.z += random.nextInt(701) + 300; warband.x += random.nextInt(701) - 1000; break; - default: warband.direction = "none"; break; + if (waypoint != null) warband.waypoint_name = "lotr.waypoint." + waypoint.getCodeName(); + + if ((x == null || z == null) && waypoint == null) waypoint = get_random_waypoint(); + if (x == null) x = waypoint.getXCoord(); + if (z == null) z = waypoint.getZCoord(); + warband.x = x; + warband.z = z; + + if (randomize) { + switch (random.nextInt(8)) { + case 0: warband.direction = "North"; warband.z += random.nextInt(701) - 1000; break; + case 1: warband.direction = "South"; warband.z += random.nextInt(701) + 300; break; + case 2: warband.direction = "East"; warband.x += random.nextInt(701) + 300; break; + case 3: warband.direction = "West"; warband.x += random.nextInt(701) - 1000; break; + case 4: warband.direction = "North-East"; warband.z += random.nextInt(701) - 1000; warband.x += random.nextInt(701) + 300; break; + case 5: warband.direction = "North-West"; warband.z += random.nextInt(701) - 1000; warband.x += random.nextInt(701) - 1000; break; + case 6: warband.direction = "South-East"; warband.z += random.nextInt(701) + 300; warband.x += random.nextInt(701) + 300; break; + case 7: warband.direction = "South-West"; warband.z += random.nextInt(701) + 300; warband.x += random.nextInt(701) - 1000; break; + default: warband.direction = "none"; break; + } } - System.out.println("Loading warband chunks at " + warband.x + "," + warband.z); load_chunks_at(warband.x, warband.z); - warband.faction = get_warband_faction_by_biome(warband); + if (faction == null) faction = get_warband_faction_by_biome(warband); + warband.faction = faction; spawn_warband(warband); + WarbandTracker.add(warband); } public static void load_chunks_at(int block_x, int block_z) { @@ -121,6 +150,7 @@ public class Warband { } }).start(); broadcast_warband(world, warband.faction.warband_name, warband.direction, warband.waypoint_name); + do_radial_conquest(world, warband.x, warband.z, warband.faction.faction, 50); last_warband_timestamp = System.currentTimeMillis() / 1000L; } public static void spawn_boss_entity(Warband warband, int x, int y, int z) { @@ -192,13 +222,56 @@ public class Warband { } public static void broadcast_warband(World world, String faction_key, String direction, String waypoint_key) { - IChatComponent message = new ChatComponentTranslation( - "warband.found", - new ChatComponentTranslation(faction_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD)), - new ChatComponentText(direction).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW)), - new ChatComponentTranslation(waypoint_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)) - ); + IChatComponent message; + if (waypoint_key != null && direction != null) { + message = new ChatComponentTranslation( + "warband.found", + new ChatComponentTranslation(faction_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD)), + new ChatComponentText(direction).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.YELLOW)), + new ChatComponentTranslation(waypoint_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)) + ); + } else if (waypoint_key == null){ + message = new ChatComponentTranslation( + "warband.found.no_waypoint", + new ChatComponentTranslation(faction_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD)) + ); + } else { + message = new ChatComponentTranslation( + "warband.found.no_direction", + new ChatComponentTranslation(faction_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD)), + new ChatComponentTranslation(waypoint_key).setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA)) + ); + } LOTRSpeech.messageAllPlayersInWorld(world, message); } + + public static void do_radial_conquest(World world, int posX, int posZ, LOTRFaction faction, float amount) { + if (!LOTRConquestGrid.conquestEnabled(world)) { + return; + } + + LOTRConquestZone zone = LOTRConquestGrid.getZoneByWorldCoords(posX, posZ); + if (zone == null || zone.isDummyZone) { + return; + } + + float current_strength = zone.getConquestStrength(faction, world); + float target_strength = current_strength + amount; + if (target_strength > 100000.0F) { + amount = 100000.0F - current_strength; + } else if (target_strength < 0.0F) { + amount = -current_strength; + } + + if (amount == 0.0F) { + return; + } + + if (amount < 0.0F) { + LOTRConquestGrid.doRadialConquest(world, zone, null, null, faction, -amount, -amount); + } else { + LOTRConquestGrid.doRadialConquest(world, zone, null, faction, null, amount, amount); + } + } } diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandFaction.java b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandFaction.java index ab410fd..2964835 100644 --- a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandFaction.java +++ b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandFaction.java @@ -885,6 +885,14 @@ public enum WarbandFaction { } } + public static WarbandFaction get_warband_by_name(String name) { + for (WarbandFaction faction : values()) { + if (faction.name().equals(name)) + return faction; + } + return null; + } + public static class Troop { public Class entity_class; public int amount; diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandLocationInfo.java b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandLocationInfo.java new file mode 100644 index 0000000..741af51 --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandLocationInfo.java @@ -0,0 +1,13 @@ +package com.zivilon.cinder_loe.world.event; + +public class WarbandLocationInfo { + public Warband warband; + public double x; + public double z; + + public WarbandLocationInfo(Warband warband, double x, double z) { + this.warband = warband; + this.x = x; + this.z = z; + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTickHandler.java b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTickHandler.java index 57d87ff..1378811 100644 --- a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTickHandler.java +++ b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTickHandler.java @@ -7,8 +7,7 @@ import cpw.mods.fml.common.gameevent.TickEvent.ServerTickEvent; public class WarbandTickHandler { public int tick_counter = 0; -// public static int INTERVAL_TICKS = 12000; // 10 minutes at 20 TPS - public static int INTERVAL_TICKS = 1200; // 1 minutes at 20 TPS + public static int INTERVAL_TICKS = 12000; // 10 minutes at 20 TPS @SubscribeEvent public void onServerTick(ServerTickEvent event) { @@ -22,10 +21,8 @@ public class WarbandTickHandler { } public void run_task() { - System.out.println("Warband ticked"); - if (Warband.last_warband_timestamp > (System.currentTimeMillis() / 1000L) - 7200) return; // Do not spawn warband if less than 2 hours since last one -// if (Warband.random.nextInt(10) != 0) return; - System.out.println("Warband starting"); + if (Warband.last_warband_timestamp > (System.currentTimeMillis() / 1000L) - (60*60*4)) return; // Do not spawn warband if less than 4 hours since last one + if (Warband.random.nextInt(10) != 0) return; Warband.initialize_warband(); } } diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTracker.java b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTracker.java new file mode 100644 index 0000000..19928be --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/world/event/WarbandTracker.java @@ -0,0 +1,30 @@ +package com.zivilon.cinder_loe.world.event; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class WarbandTracker { + public static Map locations = new HashMap<>(); + + public static void clear_locations() { + locations.clear(); + } + + public static void add(Warband warband) { + locations.put(warband.warband_uuid, new WarbandLocationInfo(warband, warband.x, warband.z)); + } + public static void add(WarbandLocationInfo info) { + locations.put(info.warband.warband_uuid, info); + } + + public static void remove(UUID uuid) { + locations.remove(uuid); + } + + public static List get_all() { + return new ArrayList<>(locations.values()); + } +} diff --git a/src/main/resources/assets/cinder_loe/lang/en_US.lang b/src/main/resources/assets/cinder_loe/lang/en_US.lang index ac0897b..d34e855 100644 --- a/src/main/resources/assets/cinder_loe/lang/en_US.lang +++ b/src/main/resources/assets/cinder_loe/lang/en_US.lang @@ -366,7 +366,11 @@ lotr.unitinfo.Rhudaur=To Hire this unit you must have the Rhudaur Objective comp lotr.unitinfo.Dale=To Hire this unit you must have the Dalish Objective complete. lotr.unitinfo.Lindon=To Hire this unit you must have the Lindon Objective complete. -warband.found=Warband of %s has been found %s of %s +warband.found=Warband of %s was spotted %s of %s! +warband.found.no_direction=Warband of %s was spotted by %s! +warband.found.no_waypoint=Warband of %s has been found! +warband.defeated.faction=Warband of %s has been defeated! +warband.defeated.no_faction=Warband has been defeated! warband.fac.MORGUL_VALE=Morgul Vale warband.fac.WOOD_ELF_SCOUT=Woodland Realm scouts warband.fac.RED_MOUNTAINS=Red Mountains diff --git a/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_0.png b/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_0.png index e427528..373ac6a 100644 Binary files a/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_0.png and b/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_0.png differ diff --git a/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_90.png b/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_90.png index b6c0bfe..4f4fddd 100644 Binary files a/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_90.png and b/src/main/resources/assets/lotr/textures/blocks/ivory_block_side_90.png differ diff --git a/src/main/resources/assets/lotr/textures/blocks/ivory_block_top.png b/src/main/resources/assets/lotr/textures/blocks/ivory_block_top.png index 74ac7de..72e33ce 100644 Binary files a/src/main/resources/assets/lotr/textures/blocks/ivory_block_top.png and b/src/main/resources/assets/lotr/textures/blocks/ivory_block_top.png differ diff --git a/src/main/resources/mixins.cinder_loe.json b/src/main/resources/mixins.cinder_loe.json index cb9b9ce..c378be0 100644 --- a/src/main/resources/mixins.cinder_loe.json +++ b/src/main/resources/mixins.cinder_loe.json @@ -52,8 +52,13 @@ "MixinLOTREntityNPC", "MixinFoodStats", "MixinLOTRItemMug", +<<<<<<< HEAD "MixinLOTRNPCTargetSelector", "MixinLOTREntityHorse" +======= + "MixinLOTRGuiMap", + "MixinLOTREntityAIOrcSkirmish" +>>>>>>> b62b012e70ebb6eea11d071eb443e10f77f855ce ], "client": [] }