Compare commits
10 commits
ddc78efa0e
...
ac41344a3c
Author | SHA1 | Date | |
---|---|---|---|
ac41344a3c | |||
5fee6404b0 | |||
f1c52e4371 | |||
|
a91692ded7 | ||
|
4cf81e171c | ||
|
83757cd9bc | ||
|
c82fcee8aa | ||
|
7db468db1e | ||
|
3102d3c033 | ||
|
5276e52f45 |
60 changed files with 2694 additions and 195 deletions
61
.github/workflows/deploy.yml
vendored
Normal file
61
.github/workflows/deploy.yml
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
# A deployment template that works out of the box
|
||||
# It supports these objectives:
|
||||
# - Deploy to Maven (Build Job) [Secrets: MAVEN_USER, MAVEN_PASS]
|
||||
# - Deploy to CurseForge (Upload Job) [Secrets: CURSEFORGE_TOKEN]
|
||||
# - Deploy to Modrinth (Upload Job) [Secrets: MODRINTH_TOKEN]
|
||||
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9]+.[0-9]+.[0-9]+'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Grant Execute Permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Read gradle.properties
|
||||
uses: BrycensRanch/read-properties-action@v1
|
||||
id: properties
|
||||
with:
|
||||
file: gradle.properties
|
||||
all: true
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
cache: gradle
|
||||
|
||||
- name: Publish to Maven
|
||||
if: steps.properties.outputs.publish_to_maven == 'true' && steps.properties.outputs.publish_to_local_maven == 'true'
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
arguments: |
|
||||
publish
|
||||
-P${{ steps.properties.outputs.maven_name }}Username=${{ secrets.MAVEN_USER }}
|
||||
-P${{ steps.properties.outputs.maven_name }}Password=${{ secrets.MAVEN_PASS }}
|
||||
|
||||
- name: Publish to CurseForge
|
||||
if: steps.properties.outputs.publish_to_curseforge == 'true'
|
||||
uses: gradle/gradle-build-action@v2
|
||||
env:
|
||||
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||
with:
|
||||
arguments: curseforge
|
||||
|
||||
- name: Publish to Modrinth
|
||||
if: steps.properties.outputs.publish_to_modrinth == 'true'
|
||||
uses: gradle/gradle-build-action@v2
|
||||
env:
|
||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||
with:
|
||||
arguments: modrinth
|
6
CHANGELOG.md
Normal file
6
CHANGELOG.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Changelog
|
||||
|
||||
## [1.0.0] - 2023-09-15
|
||||
|
||||
### Added
|
||||
- This is a default template changelog that follows the [KeepAChangelog Convention](https://keepachangelog.com/en/1.1.0/)
|
18
LICENSE
18
LICENSE
|
@ -1,21 +1,11 @@
|
|||
MIT License
|
||||
All Rights Reserved
|
||||
|
||||
Copyright (c) 2022 CleanroomMC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
Copyright (c) 2024 Octol1ttle
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Template workspace for modding Minecraft 1.12.2. Licensed under MIT, it is made for public use.
|
||||
|
||||
This template currently utilizies **Gradle 8.1.1** + **[RetroFuturaGradle](https://github.com/GTNewHorizons/RetroFuturaGradle) 1.3.6** + **Forge 14.23.5.2847**.
|
||||
This template currently utilizies **Gradle 8.7** + **[RetroFuturaGradle](https://github.com/GTNewHorizons/RetroFuturaGradle) 1.3.35** + **Forge 14.23.5.2847**.
|
||||
|
||||
With **coremod and mixin support** that is easy to configure.
|
||||
|
||||
|
@ -14,3 +14,7 @@ With **coremod and mixin support** that is easy to configure.
|
|||
4. Open the project folder in IDEA.
|
||||
5. Right-click in IDEA `build.gradle` of your project, and select `Link Gradle Project`, after completion, hit `Refresh All` in the gradle tab on the right.
|
||||
6. Run `gradlew runClient` and `gradlew runServer`, or use the auto-imported run configurations in IntelliJ like `1. Run Client`.
|
||||
|
||||
### Mixins:
|
||||
|
||||
- When writing Mixins on IntelliJ, it is advisable to use latest [MinecraftDev Fork for RetroFuturaGradle](https://github.com/eigenraven/MinecraftDev/releases).
|
||||
|
|
412
build.gradle
412
build.gradle
|
@ -1,34 +1,67 @@
|
|||
import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar
|
||||
/**
|
||||
* It is advised that you do not edit anything in the build.gradle; unless you are sure of what you are doing
|
||||
*/
|
||||
import com.gtnewhorizons.retrofuturagradle.mcp.InjectTagsTask
|
||||
import org.jetbrains.changelog.Changelog
|
||||
import org.jetbrains.gradle.ext.Gradle
|
||||
|
||||
plugins {
|
||||
id("java")
|
||||
id("java-library")
|
||||
id("maven-publish")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext") version "1.1.7"
|
||||
id("eclipse")
|
||||
id("com.gtnewhorizons.retrofuturagradle") version "1.3.9"
|
||||
id("com.matthewprenger.cursegradle") version "1.4.0"
|
||||
id 'java'
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.7'
|
||||
id 'com.gtnewhorizons.retrofuturagradle' version '1.3.35'
|
||||
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
|
||||
id 'com.modrinth.minotaur' version '2.+' apply false
|
||||
id 'org.jetbrains.changelog' version '2.2.0'
|
||||
}
|
||||
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
archivesBaseName = project.archives_base_name
|
||||
apply from: 'gradle/scripts/helpers.gradle'
|
||||
|
||||
// Early Assertions
|
||||
assertProperty 'mod_version'
|
||||
assertProperty 'root_package'
|
||||
assertProperty 'mod_id'
|
||||
assertProperty 'mod_name'
|
||||
|
||||
assertSubProperties 'use_tags', 'tag_class_name'
|
||||
assertSubProperties 'use_access_transformer', 'access_transformer_locations'
|
||||
assertSubProperties 'use_mixins', 'mixin_booter_version', 'mixin_refmap'
|
||||
assertSubProperties 'is_coremod', 'coremod_includes_mod', 'coremod_plugin_class_name'
|
||||
assertSubProperties 'use_asset_mover', 'asset_mover_version'
|
||||
|
||||
setDefaultProperty 'use_modern_java_syntax', false, false
|
||||
setDefaultProperty 'generate_sources_jar', true, false
|
||||
setDefaultProperty 'generate_javadocs_jar', true, false
|
||||
setDefaultProperty 'mapping_channel', true, 'stable'
|
||||
setDefaultProperty 'mapping_version', true, '39'
|
||||
setDefaultProperty 'use_dependency_at_files', true, true
|
||||
setDefaultProperty 'minecraft_username', true, 'Developer'
|
||||
setDefaultProperty 'extra_jvm_args', false, ''
|
||||
setDefaultProperty 'extra_tweak_classes', false, ''
|
||||
setDefaultProperty 'change_minecraft_sources', false, false
|
||||
|
||||
version = propertyString('mod_version')
|
||||
group = propertyString('root_package')
|
||||
|
||||
base {
|
||||
archivesName.set(propertyString('mod_id'))
|
||||
}
|
||||
|
||||
tasks.decompressDecompiledSources.enabled !propertyBool('change_minecraft_sources')
|
||||
|
||||
// Set the toolchain version to decouple the Java we run Gradle with from the Java used to compile and run the mod
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(8))
|
||||
languageVersion.set(JavaLanguageVersion.of(propertyBool('use_modern_java_syntax') ? 16 : 8))
|
||||
// Azul covers the most platforms for Java 8 toolchains, crucially including MacOS arm64
|
||||
vendor.set(org.gradle.jvm.toolchain.JvmVendorSpec.AZUL)
|
||||
vendor.set(JvmVendorSpec.AZUL)
|
||||
}
|
||||
if (propertyBool('generate_sources_jar')) {
|
||||
withSourcesJar()
|
||||
}
|
||||
if (propertyBool('generate_javadocs_jar')) {
|
||||
withJavadocJar()
|
||||
}
|
||||
// Generate sources and javadocs jars when building and publishing
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
@ -37,131 +70,139 @@ configurations {
|
|||
}
|
||||
|
||||
minecraft {
|
||||
mcVersion = '1.12.2'
|
||||
def args = ["-ea:${project.group}"]
|
||||
if (project.use_coremod.toBoolean()) {
|
||||
args << '-Dfml.coreMods.load=' + coremod_plugin_class_name
|
||||
}
|
||||
if (project.use_mixins.toBoolean()) {
|
||||
mcVersion.set('1.12.2')
|
||||
|
||||
mcpMappingChannel.set(propertyString('mapping_channel'))
|
||||
mcpMappingVersion.set(propertyString('mapping_version'))
|
||||
|
||||
useDependencyAccessTransformers.set(propertyBool('use_dependency_at_files'))
|
||||
|
||||
username.set(propertyString('minecraft_username'))
|
||||
|
||||
// Add any additional tweaker classes here
|
||||
extraTweakClasses.addAll(propertyStringList('extra_tweak_classes'))
|
||||
|
||||
// Add various JVM arguments here for runtime
|
||||
def args = ['-ea:' + group]
|
||||
if (propertyBool('use_mixins')) {
|
||||
args << '-Dmixin.hotSwap=true'
|
||||
args << '-Dmixin.checks.interfaces=true'
|
||||
args << '-Dmixin.debug.export=true'
|
||||
}
|
||||
extraRunJvmArguments.addAll(args)
|
||||
extraRunJvmArguments.addAll(propertyStringList('extra_jvm_args'))
|
||||
|
||||
useDependencyAccessTransformers = true
|
||||
|
||||
injectedTags.put("VERSION", project.version)
|
||||
}
|
||||
|
||||
// Generate a my.project.Tags class with the version number as a field
|
||||
tasks.injectTags.configure {
|
||||
outputClassName.set("${project.group}.Tags")
|
||||
if (propertyBool('use_tags')) {
|
||||
if (file('tags.properties').exists()) {
|
||||
Properties props = new Properties().tap { it.load(file('tags.properties').newInputStream()); it }
|
||||
if (!props.isEmpty()) {
|
||||
injectedTags.set(props.collectEntries { k, v -> [(k): interpolate(v)] })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = 'https://maven.cleanroommc.com'
|
||||
name 'CleanroomMC Maven'
|
||||
url 'https://maven.cleanroommc.com'
|
||||
}
|
||||
maven { url = "https://repo.spongepowered.org/maven" }
|
||||
//maven { url "https://maven.mcmoddev.com/" }
|
||||
maven {
|
||||
url "https://cursemaven.com"
|
||||
content {
|
||||
includeGroup "curse.maven"
|
||||
}
|
||||
}
|
||||
mavenLocal() // Must be last for caching to work
|
||||
}
|
||||
|
||||
dependencies {
|
||||
if (project.use_assetmover.toBoolean()) {
|
||||
implementation 'com.cleanroommc:assetmover:2.0'
|
||||
}
|
||||
if (project.use_mixins.toBoolean()) {
|
||||
implementation 'zone.rong:mixinbooter:7.0'
|
||||
}
|
||||
|
||||
// Example deobf dependency
|
||||
// compileOnly rfg.deobf("curse.maven:endercore-231868:2972849:")
|
||||
|
||||
if (project.use_mixins.toBoolean()) {
|
||||
api ("org.spongepowered:mixin:0.8.3") {transitive = false}
|
||||
annotationProcessor('org.ow2.asm:asm-debug-all:5.2')
|
||||
annotationProcessor('com.google.guava:guava:24.1.1-jre')
|
||||
annotationProcessor('com.google.code.gson:gson:2.8.6')
|
||||
annotationProcessor ("org.spongepowered:mixin:0.8.3") {transitive = false}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def mixinConfigRefMap = 'mixins.' + project.archives_base_name + '.refmap.json'
|
||||
def mixinTmpDir = buildDir.path + File.separator + 'tmp' + File.separator + 'mixins'
|
||||
def refMap = "${mixinTmpDir}" + File.separator + mixinConfigRefMap
|
||||
def mixinSrg = "${mixinTmpDir}" + File.separator + "mixins.srg"
|
||||
|
||||
if (project.use_mixins.toBoolean()) {
|
||||
tasks.named("reobfJar", ReobfuscatedJar).configure {
|
||||
extraSrgFiles.from(mixinSrg)
|
||||
}
|
||||
|
||||
tasks.named("compileJava", JavaCompile).configure {
|
||||
doFirst {
|
||||
new File(mixinTmpDir).mkdirs()
|
||||
if (propertyBool('use_modern_java_syntax')) {
|
||||
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
|
||||
}
|
||||
options.compilerArgs += [
|
||||
"-AreobfSrgFile=${tasks.reobfJar.srg.get().asFile}",
|
||||
"-AoutSrgFile=${mixinSrg}",
|
||||
"-AoutRefMapFile=${refMap}",
|
||||
]
|
||||
// Allow jdk.unsupported classes like sun.misc.Unsafe, workaround for JDK-8206937 and fixes crashes in tests
|
||||
patchedMinecraft 'me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0'
|
||||
// Include for tests
|
||||
testAnnotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:1.0.0'
|
||||
testCompileOnly('com.github.bsideup.jabel:jabel-javac-plugin:1.0.0') {
|
||||
transitive = false // We only care about the 1 annotation class
|
||||
}
|
||||
}
|
||||
if (propertyBool('use_asset_mover')) {
|
||||
implementation "com.cleanroommc:assetmover:${propertyString('asset_mover_version')}"
|
||||
}
|
||||
if (propertyBool('use_mixins')) {
|
||||
String mixin = modUtils.enableMixins("zone.rong:mixinbooter:${propertyString('mixin_booter_version')}", propertyString('mixin_refmap'))
|
||||
api (mixin) {
|
||||
transitive = false
|
||||
}
|
||||
annotationProcessor 'org.ow2.asm:asm-debug-all:5.2'
|
||||
annotationProcessor 'com.google.guava:guava:24.1.1-jre'
|
||||
annotationProcessor 'com.google.code.gson:gson:2.8.6'
|
||||
annotationProcessor (mixin) {
|
||||
transitive = false
|
||||
}
|
||||
}
|
||||
if (propertyBool('enable_junit_testing')) {
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
}
|
||||
|
||||
if (project.use_access_transformer.toBoolean()) {
|
||||
for (File at : sourceSets.getByName("main").resources.files) {
|
||||
if (at.name.toLowerCase().endsWith("_at.cfg")) {
|
||||
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(at)
|
||||
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(at)
|
||||
apply from: 'gradle/scripts/dependencies.gradle'
|
||||
|
||||
// Adds Access Transformer files to tasks
|
||||
if (propertyBool('use_access_transformer')) {
|
||||
for (def location : propertyStringList('access_transformer_locations')) {
|
||||
def fileLocation = file("${projectDir}/src/main/resources/${location}")
|
||||
if (fileLocation.exists()) {
|
||||
tasks.deobfuscateMergedJarToSrg.accessTransformerFiles.from(fileLocation)
|
||||
tasks.srgifyBinpatchedJar.accessTransformerFiles.from(fileLocation)
|
||||
} else {
|
||||
throw new GradleException("Access Transformer file [$fileLocation] does not exist!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
// this will ensure that this task is redone when the versions change.
|
||||
inputs.property 'version', project.version
|
||||
inputs.property 'mcversion', project.minecraft.version
|
||||
// replace stuff in mcmod.info, nothing else
|
||||
filesMatching(['mcmod.info', 'pack.mcmeta']) { fcd ->
|
||||
// replace version and mcversion
|
||||
fcd.expand (
|
||||
'version': project.version,
|
||||
'mcversion': project.minecraft.version
|
||||
|
||||
def filterList = ['mcmod.info', 'pack.mcmeta']
|
||||
filterList.addAll(propertyStringList('mixin_configs').collect(config -> "mixins.${config}.json" as String))
|
||||
|
||||
filesMatching(filterList) { fcd ->
|
||||
fcd.expand(
|
||||
'mod_id': propertyString('mod_id'),
|
||||
'mod_name': propertyString('mod_name'),
|
||||
'mod_version': propertyString('mod_version'),
|
||||
'mod_description': propertyString('mod_description'),
|
||||
'mod_authors': "[${propertyStringList('mod_authors', ',').join(', ')}]",
|
||||
'mod_credits': propertyString('mod_credits'),
|
||||
'mod_url': propertyString('mod_url'),
|
||||
'mod_update_json': propertyString('mod_update_json'),
|
||||
'mod_logo_path': propertyString('mod_logo_path'),
|
||||
'mixin_refmap': propertyString('mixin_refmap'),
|
||||
'mixin_package': propertyString('mixin_package')
|
||||
)
|
||||
}
|
||||
|
||||
if (project.use_access_transformer.toBoolean()) {
|
||||
rename '(.+_at.cfg)', 'META-INF/$1' // Access Transformers
|
||||
if (propertyBool('use_access_transformer')) {
|
||||
rename '(.+_at.cfg)', 'META-INF/$1'
|
||||
}
|
||||
|
||||
if (project.use_mixins.toBoolean()) {
|
||||
// Embed mixin refmap
|
||||
from refMap
|
||||
dependsOn("compileJava")
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
def attribute_map = [:]
|
||||
if (project.use_coremod.toBoolean()) {
|
||||
attribute_map['FMLCorePlugin'] = project.coremod_plugin_class_name
|
||||
if (project.include_mod.toBoolean()) {
|
||||
if (propertyBool('is_coremod')) {
|
||||
attribute_map['FMLCorePlugin'] = propertyString('coremod_plugin_class_name')
|
||||
if (propertyBool('coremod_includes_mod')) {
|
||||
attribute_map['FMLCorePluginContainsFMLMod'] = true
|
||||
attribute_map['ForceLoadAsMod'] = project.gradle.startParameter.taskNames[0] == "build"
|
||||
def currentTasks = gradle.startParameter.taskNames
|
||||
if (currentTasks[0] == 'build' || currentTasks[0] == 'prepareObfModsFolder' || currentTasks[0] == 'runObfClient') {
|
||||
attribute_map['ForceLoadAsMod'] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (project.use_access_transformer.toBoolean()) {
|
||||
attribute_map['FMLAT'] = project.archives_base_name + '_at.cfg'
|
||||
if (propertyBool('use_access_transformer')) {
|
||||
attribute_map['FMLAT'] = propertyString('access_transformer_locations')
|
||||
}
|
||||
attributes(attribute_map)
|
||||
}
|
||||
|
@ -170,33 +211,136 @@ jar {
|
|||
}
|
||||
|
||||
idea {
|
||||
module { inheritOutputDirs = true }
|
||||
project { settings {
|
||||
runConfigurations {
|
||||
"1. Run Client"(Gradle) {
|
||||
taskNames = ["runClient"]
|
||||
module {
|
||||
inheritOutputDirs = true
|
||||
}
|
||||
project {
|
||||
settings {
|
||||
runConfigurations {
|
||||
"1. Run Client"(Gradle) {
|
||||
taskNames = ["runClient"]
|
||||
}
|
||||
"2. Run Server"(Gradle) {
|
||||
taskNames = ["runServer"]
|
||||
}
|
||||
"3. Run Obfuscated Client"(Gradle) {
|
||||
taskNames = ["runObfClient"]
|
||||
}
|
||||
"4. Run Obfuscated Server"(Gradle) {
|
||||
taskNames = ["runObfServer"]
|
||||
}
|
||||
}
|
||||
"2. Run Server"(Gradle) {
|
||||
taskNames = ["runServer"]
|
||||
}
|
||||
"3. Run Obfuscated Client"(Gradle) {
|
||||
taskNames = ["runObfClient"]
|
||||
}
|
||||
"4. Run Obfuscated Server"(Gradle) {
|
||||
taskNames = ["runObfServer"]
|
||||
compiler.javac {
|
||||
afterEvaluate {
|
||||
javacAdditionalOptions = "-encoding utf8"
|
||||
moduleJavacAdditionalOptions = [
|
||||
(project.name + ".main"): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ')
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
compiler.javac {
|
||||
afterEvaluate {
|
||||
javacAdditionalOptions = "-encoding utf8"
|
||||
moduleJavacAdditionalOptions = [
|
||||
(project.name + ".main"): tasks.compileJava.options.compilerArgs.collect { '"' + it + '"' }.join(' ')
|
||||
]
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named("processIdeaSettings").configure {
|
||||
dependsOn("injectTags")
|
||||
compileTestJava {
|
||||
sourceCompatibility = targetCompatibility = 8
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
javaLauncher.set(javaToolchains.launcherFor {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
})
|
||||
if (propertyBool('show_testing_output')) {
|
||||
testLogging {
|
||||
showStandardStreams = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String parserChangelog() {
|
||||
if (!file('CHANGELOG.md').exists()) {
|
||||
throw new GradleException('publish_with_changelog is true, but CHANGELOG.md does not exist in the workspace!')
|
||||
}
|
||||
String parsedChangelog = changelog.renderItem(
|
||||
changelog.get(propertyString('mod_version')).withHeader(false).withEmptySections(false),
|
||||
Changelog.OutputType.MARKDOWN)
|
||||
if (parsedChangelog.isEmpty()) {
|
||||
throw new GradleException('publish_with_changelog is true, but the changelog for the latest version is empty!')
|
||||
}
|
||||
return parsedChangelog
|
||||
}
|
||||
|
||||
tasks.register('generateMixinJson') {
|
||||
group 'cleanroom helpers'
|
||||
def missingConfig = propertyStringList('mixin_configs').findAll(config -> !file("src/main/resources/mixins.${config}.json").exists())
|
||||
onlyIf {
|
||||
if (propertyBool('use_mixins') && propertyBool('generate_mixins_json')) {
|
||||
return !missingConfig.empty
|
||||
}
|
||||
return false
|
||||
}
|
||||
doLast {
|
||||
for (String mixinConfig : missingConfig) {
|
||||
def file = file("src/main/resources/mixins.${mixinConfig}.json")
|
||||
file << """{\n\t"package": "",\n\t"required": true,\n\t"refmap": "${mixin_refmap}",\n\t"target": "@env(DEFAULT)",\n\t"minVersion": "0.8.5",\n\t"compatibilityLevel": "JAVA_8",\n\t"mixins": [],\n\t"server": [],\n\t"client": []\n}"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8'
|
||||
if (propertyBool('use_modern_java_syntax')) {
|
||||
if (it.name in ['compileMcLauncherJava', 'compilePatchedMcJava']) {
|
||||
return
|
||||
}
|
||||
sourceCompatibility = 17
|
||||
options.release.set(8)
|
||||
javaCompiler.set(javaToolchains.compilerFor {
|
||||
languageVersion.set(JavaLanguageVersion.of(16))
|
||||
vendor.set(JvmVendorSpec.AZUL)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('cleanroomAfterSync') {
|
||||
group 'cleanroom helpers'
|
||||
dependsOn 'injectTags', 'generateMixinJson'
|
||||
}
|
||||
|
||||
if (propertyBool('use_modern_java_syntax')) {
|
||||
tasks.withType(Javadoc).configureEach {
|
||||
sourceCompatibility = 17
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named('injectTags', InjectTagsTask).configure {
|
||||
onlyIf {
|
||||
return propertyBool('use_tags') && !it.getTags().get().isEmpty()
|
||||
}
|
||||
it.outputClassName.set(propertyString('tag_class_name'))
|
||||
}
|
||||
|
||||
tasks.named('prepareObfModsFolder').configure {
|
||||
finalizedBy 'prioritizeCoremods'
|
||||
}
|
||||
|
||||
tasks.register('prioritizeCoremods') {
|
||||
dependsOn 'prepareObfModsFolder'
|
||||
doLast {
|
||||
fileTree('run/obfuscated').forEach {
|
||||
if (it.isFile() && it.name =~ '(mixinbooter|configanytime)(-)([0-9])+\\.+([0-9])+(.jar)') {
|
||||
it.renameTo(new File(it.parentFile, "!${it.name}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idea.project.settings {
|
||||
taskTriggers {
|
||||
afterSync 'cleanroomAfterSync'
|
||||
}
|
||||
}
|
||||
|
||||
apply from: 'gradle/scripts/publishing.gradle'
|
||||
apply from: 'gradle/scripts/extra.gradle'
|
||||
|
|
|
@ -1,22 +1,126 @@
|
|||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
# Gradle Properties
|
||||
org.gradle.jvmargs = -Xmx3G
|
||||
|
||||
# Source Options
|
||||
# Use Modern Java(9+) Syntax (Courtesy of Jabel)
|
||||
use_modern_java_syntax = false
|
||||
|
||||
# Compilation Options
|
||||
generate_sources_jar = true
|
||||
generate_javadocs_jar = false
|
||||
|
||||
# Testing
|
||||
enable_junit_testing = true
|
||||
show_testing_output = false
|
||||
|
||||
# Mod Information
|
||||
mod_version = 1.0
|
||||
maven_group = com.cleanroommc
|
||||
archives_base_name = modid
|
||||
# HIGHLY RECOMMEND complying with SemVer for mod_version: https://semver.org/
|
||||
mod_version = 1.0.0
|
||||
root_package = ru.octol1ttle
|
||||
mod_id = knockdowns
|
||||
mod_name = Knockdowns (Legacy)
|
||||
|
||||
# If any properties changes below this line, run `gradlew setupDecompWorkspace` and refresh gradle again to ensure everything is working correctly.
|
||||
# Mod Metadata (Optional)
|
||||
mod_description =
|
||||
mod_url =
|
||||
mod_update_json =
|
||||
# Delimit authors with commas
|
||||
mod_authors = Octol1ttle
|
||||
mod_credits =
|
||||
mod_logo_path =
|
||||
|
||||
# Boilerplate Options
|
||||
use_mixins = false
|
||||
use_coremod = false
|
||||
use_assetmover = false
|
||||
# Mapping Properties
|
||||
mapping_channel = stable
|
||||
mapping_version = 39
|
||||
use_dependency_at_files = true
|
||||
|
||||
# Access Transformer files should be in the root of `resources` folder and with the filename formatted as: `{archives_base_name}_at.cfg`
|
||||
# Run Configurations
|
||||
# If multiple arguments/tweak classes are stated, use spaces as the delimiter
|
||||
minecraft_username = Developer
|
||||
extra_jvm_args =
|
||||
extra_tweak_classes =
|
||||
|
||||
# Maven Publishing (Provide secret: MAVEN_USER, MAVEN_PASS)
|
||||
publish_to_maven = false
|
||||
# Good for debugging artifacts before uploading to remote maven
|
||||
# GitHub actions won't run if this is true, test this by running the task `publishToMavenLocal`
|
||||
publish_to_local_maven = false
|
||||
maven_name = ${mod_name}
|
||||
maven_url =
|
||||
|
||||
# Publishing
|
||||
# release_type can only be: release, beta or alpha (applies to CurseForge / Modrinth)
|
||||
release_type = release
|
||||
publish_with_changelog = ${{ it.file('CHANGELOG.md').exists() }}
|
||||
|
||||
# Publishing to CurseForge (Provide secret: CURSEFORGE_TOKEN)
|
||||
# To configure dependencies, head to publishing.gradle's curseforge block
|
||||
publish_to_curseforge = false
|
||||
# CurseForge project ID must be the numerical ID and not the slug
|
||||
curseforge_project_id =
|
||||
curseforge_debug = false
|
||||
|
||||
# Publishing to Modrinth (Provide secret: MODRINTH_TOKEN), the token must have the `CREATE_VERSION` and `PROJECT_WRITE` permissions
|
||||
# To configure dependencies, head to publishing.gradle's modrinth block
|
||||
publish_to_modrinth = false
|
||||
modrinth_project_id =
|
||||
# Allows gradle to publish updated READMEs to the project body (via the modrinthSyncBody task)
|
||||
modrinth_sync_readme = false
|
||||
modrinth_debug = false
|
||||
|
||||
# If any properties changes below this line, refresh gradle again to ensure everything is working correctly.
|
||||
|
||||
# Modify Minecraft Sources
|
||||
# RetroFuturaGradle allows Minecraft sources to be edited, and have the changes reflected upon running it
|
||||
# Good for previews when coremodding, or generally seeing how behaviours can change with certain code applied/unapplied
|
||||
# Turning this on allows Minecraft sources to persist and not regenerate
|
||||
change_minecraft_sources = false
|
||||
|
||||
# Tags
|
||||
# A RetroFuturaGradle concept akin to Ant ReplaceTokens
|
||||
# A class is generated at build-time for compilation, to describe properties that have values that could change at build time such as versioning
|
||||
# Class name is configurable with the `tag_class_name` property
|
||||
# Tag properties can be stated in the `tags.properties` file, references are allowed
|
||||
use_tags = true
|
||||
tag_class_name = ${root_package}.${mod_id}.Tags
|
||||
|
||||
# Access Transformers
|
||||
# A way to change visibility of Minecraft's classes, methods and fields
|
||||
# An example access transformer file is given in the path: `src/main/resources/example_at.cfg`
|
||||
# AT files should be in the root of src/main/resources with the filename formatted as: `mod_id_at.cfg`
|
||||
# Use the property `access_transformer_locations` to state custom AT files if you aren't using the default `mod_id_at.cfg` location
|
||||
# If multiple locations are stated, use spaces as the delimiter
|
||||
use_access_transformer = false
|
||||
access_transformer_locations = ${mod_id}_at.cfg
|
||||
|
||||
# Coremod Arguments
|
||||
include_mod = true
|
||||
coremod_plugin_class_name =
|
||||
# Mixins
|
||||
# Powerful tool to do runtime description changes of classes
|
||||
# Wiki: https://github.com/SpongePowered/Mixin/wiki + https://github.com/CleanroomMC/MixinBooter/ + https://cleanroommc.com/wiki/forge-mod-development/mixin/preface
|
||||
# Only use mixins once you understand the underlying structure
|
||||
use_mixins = true
|
||||
mixin_booter_version = 9.1
|
||||
# A configuration defines a mixin set, and you may have as many mixin sets as you require for your application.
|
||||
# Each config can only have one and only one package root.
|
||||
# Generate missing configs, obtain from mixin_configs and generate file base on name convention: "mixins.config_name.json"
|
||||
# You should change package root once they are generated
|
||||
generate_mixins_json = true
|
||||
# Delimit configs with spaces. Should only put configs name instead of full file name
|
||||
mixin_configs = ${mod_id}
|
||||
# A refmap is a json that denotes mapping conversions, this json is generated automatically, with the name `mixins.mod_id.refmap.json`
|
||||
# Use the property `mixin_refmap` if you want it to use a different name, only one name is accepted
|
||||
mixin_refmap = mixins.${mod_id}.refmap.json
|
||||
|
||||
# Coremods
|
||||
# The most powerful way to change java classes at runtime, it is however very primitive with little documentation.
|
||||
# Only make a coremod if you are absolutely sure of what you are doing
|
||||
# Change the property `coremod_includes_mod` to false if your coremod doesn't have a @Mod annotation
|
||||
# You MUST state a class name for `coremod_plugin_class_name` if you are making a coremod, the class should implement `IFMLLoadingPlugin`
|
||||
is_coremod = true
|
||||
coremod_includes_mod = true
|
||||
coremod_plugin_class_name = ru.octol1ttle.knockdowns.common.KnockdownsFMLLoadingPlugin
|
||||
|
||||
# AssetMover
|
||||
# Convenient way to allow downloading of assets from official vanilla Minecraft servers, CurseForge, or any direct links
|
||||
# Documentation: https://github.com/CleanroomMC/AssetMover
|
||||
use_asset_mover = false
|
||||
asset_mover_version = 2.5
|
||||
|
|
62
gradle/scripts/dependencies.gradle
Normal file
62
gradle/scripts/dependencies.gradle
Normal file
|
@ -0,0 +1,62 @@
|
|||
apply from: 'gradle/scripts/helpers.gradle'
|
||||
|
||||
repositories {
|
||||
// Other repositories described by default:
|
||||
// CleanroomMC: https://maven.cleanroommc.com
|
||||
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'
|
||||
}
|
||||
}
|
||||
mavenLocal() // Must be last for caching to work
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Example - Dependency descriptor:
|
||||
// 'com.google.code.gson:gson:2.8.6' << group: com.google.code.gson, name:gson, version:2.8.6
|
||||
// 'group:name:version:classifier' where classifier is optional
|
||||
|
||||
// Example - Deobfuscating dependencies:
|
||||
// rfg.deobf('curse.maven:had-enough-items-557549:4543375')
|
||||
// By wrapping a dependency descriptor in rfg.deobf() method call, the dependency is queued for deobfuscation
|
||||
// When deobfuscating, RFG respects the mapping_channel + mapping_version stated in gradle.properties
|
||||
|
||||
// Example - CurseMaven dependencies:
|
||||
// 'curse.maven:had-enough-items-557549:4543375' << had-enough-items = project slug, 557549 = project id, 4543375 = file id
|
||||
// Full documentation: https://cursemaven.com/
|
||||
|
||||
// Example - Modrinth dependencies:
|
||||
// 'maven.modrinth:jei:4.16.1.1000' << jei = project name, 4.16.1.1000 = file version
|
||||
// Full documentation: https://docs.modrinth.com/docs/tutorials/maven/
|
||||
|
||||
// Common dependency types (configuration):
|
||||
// implementation = dependency available at both compile time and runtime
|
||||
// runtimeOnly = runtime dependency
|
||||
// compileOnly = compile time dependency
|
||||
// annotationProcessor = annotation processing dependencies
|
||||
|
||||
// Transitive dependencies:
|
||||
// (Dependencies that your dependency depends on)
|
||||
// If you wish to exclude transitive dependencies in the described dependencies
|
||||
// Use a closure as such:
|
||||
// implementation ('com.google.code.gson:gson:2.8.6') {
|
||||
// transitive = false
|
||||
// }
|
||||
}
|
5
gradle/scripts/extra.gradle
Normal file
5
gradle/scripts/extra.gradle
Normal file
|
@ -0,0 +1,5 @@
|
|||
// You may write any gradle buildscript component in this file
|
||||
// This file is automatically applied after build.gradle + dependencies.gradle is ran
|
||||
|
||||
// If you wish to use the default helper methods, uncomment the line below
|
||||
// apply from: 'gradle/scripts/helpers.gradle'
|
96
gradle/scripts/helpers.gradle
Normal file
96
gradle/scripts/helpers.gradle
Normal file
|
@ -0,0 +1,96 @@
|
|||
import groovy.text.SimpleTemplateEngine
|
||||
import org.codehaus.groovy.runtime.MethodClosure
|
||||
|
||||
ext.propertyString = this.&propertyString as MethodClosure
|
||||
ext.propertyBool = this.&propertyBool as MethodClosure
|
||||
ext.propertyStringList = this.&propertyStringList as MethodClosure
|
||||
ext.interpolate = this.&interpolate as MethodClosure
|
||||
ext.assertProperty = this.&assertProperty as MethodClosure
|
||||
ext.assertSubProperties = this.&assertSubProperties as MethodClosure
|
||||
ext.setDefaultProperty = this.&setDefaultProperty as MethodClosure
|
||||
ext.assertEnvironmentVariable = this.&assertEnvironmentVariable as MethodClosure
|
||||
|
||||
String propertyString(String key) {
|
||||
return $property(key).toString()
|
||||
}
|
||||
|
||||
boolean propertyBool(String key) {
|
||||
return propertyString(key).toBoolean()
|
||||
}
|
||||
|
||||
Collection<String> propertyStringList(String key) {
|
||||
return propertyStringList(key, ' ')
|
||||
}
|
||||
|
||||
Collection<String> propertyStringList(String key, String delimit) {
|
||||
return propertyString(key).split(delimit).findAll { !it.isEmpty() }
|
||||
}
|
||||
|
||||
private Object $property(String key) {
|
||||
def value = project.findProperty(key)
|
||||
if (value instanceof String) {
|
||||
return interpolate(value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
String interpolate(String value) {
|
||||
if (value.startsWith('${{') && value.endsWith('}}')) {
|
||||
value = value.substring(3, value.length() - 2)
|
||||
Binding newBinding = new Binding(this.binding.getVariables())
|
||||
newBinding.setProperty('it', this)
|
||||
return new GroovyShell(this.getClass().getClassLoader(), newBinding).evaluate(value)
|
||||
}
|
||||
if (value.contains('${')) {
|
||||
return new SimpleTemplateEngine().createTemplate(value).make(project.properties).toString()
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
void assertProperty(String propertyName) {
|
||||
def property = property(propertyName)
|
||||
if (property == null) {
|
||||
throw new GradleException("Property ${propertyName} is not defined!")
|
||||
}
|
||||
if (property.isEmpty()) {
|
||||
throw new GradleException("Property ${propertyName} is empty!")
|
||||
}
|
||||
}
|
||||
|
||||
void assertSubProperties(String propertyName, String... subPropertyNames) {
|
||||
assertProperty(propertyName)
|
||||
if (propertyBool(propertyName)) {
|
||||
for (String subPropertyName : subPropertyNames) {
|
||||
assertProperty(subPropertyName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setDefaultProperty(String propertyName, boolean warn, defaultValue) {
|
||||
def property = property(propertyName)
|
||||
def exists = true
|
||||
if (property == null) {
|
||||
exists = false
|
||||
if (warn) {
|
||||
project.logger.log(LogLevel.WARN, "Property ${propertyName} is not defined!")
|
||||
}
|
||||
} else if (property.isEmpty()) {
|
||||
exists = false
|
||||
if (warn) {
|
||||
project.logger.log(LogLevel.WARN, "Property ${propertyName} is empty!")
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
project.setProperty(propertyName, defaultValue.toString())
|
||||
}
|
||||
}
|
||||
|
||||
void assertEnvironmentVariable(String propertyName) {
|
||||
def property = System.getenv(propertyName)
|
||||
if (property == null) {
|
||||
throw new GradleException("System Environment Variable $propertyName is not defined!")
|
||||
}
|
||||
if (property.isEmpty()) {
|
||||
throw new GradleException("Property $propertyName is empty!")
|
||||
}
|
||||
}
|
107
gradle/scripts/publishing.gradle
Normal file
107
gradle/scripts/publishing.gradle
Normal file
|
@ -0,0 +1,107 @@
|
|||
apply from: 'gradle/scripts/helpers.gradle'
|
||||
|
||||
setDefaultProperty('publish_to_maven', true, false)
|
||||
setDefaultProperty('publish_to_curseforge', true, false)
|
||||
setDefaultProperty('publish_to_modrinth', true, false)
|
||||
|
||||
if (propertyBool('publish_to_maven')) {
|
||||
assertProperty('maven_name')
|
||||
assertProperty('maven_url')
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name propertyString('maven_name').replaceAll("\\s", "")
|
||||
url propertyString('maven_url')
|
||||
credentials(PasswordCredentials)
|
||||
}
|
||||
}
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
from components.java // Publish with standard artifacts
|
||||
setGroupId(propertyString('root_package'))// Publish with root package as maven group
|
||||
setArtifactId(propertyString('mod_id')) // Publish artifacts with mod id as the artifact id
|
||||
|
||||
// Custom artifact:
|
||||
// If you want to publish a different artifact to the one outputted when building normally
|
||||
// Create a different gradle task (Jar task), in extra.gradle
|
||||
// Remove the 'from components.java' line above
|
||||
// Add this line (change the task name):
|
||||
// artifacts task_name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation here: https://github.com/matthewprenger/CurseGradle/wiki/
|
||||
if (propertyBool('publish_to_curseforge')) {
|
||||
apply plugin: 'com.matthewprenger.cursegradle'
|
||||
assertProperty('curseforge_project_id')
|
||||
assertProperty('release_type')
|
||||
setDefaultProperty('curseforge_debug', false, false)
|
||||
curseforge {
|
||||
apiKey = System.getenv('CURSEFORGE_TOKEN') == null ? "" : System.getenv('CURSEFORGE_TOKEN')
|
||||
// noinspection GroovyAssignabilityCheck
|
||||
project {
|
||||
id = propertyString('curseforge_project_id')
|
||||
addGameVersion 'Java 8'
|
||||
addGameVersion 'Forge'
|
||||
addGameVersion '1.12.2'
|
||||
releaseType = propertyString('release_type')
|
||||
if (!propertyBool('publish_with_changelog')) {
|
||||
changelog = parserChangelog()
|
||||
changelogType = 'markdown'
|
||||
}
|
||||
mainArtifact tasks.reobfJar, {
|
||||
displayName = "${propertyString('mod_name')} ${propertyString('mod_version')}"
|
||||
if (propertyBool('use_mixins')) {
|
||||
relations {
|
||||
requiredDependency 'mixin-booter'
|
||||
}
|
||||
}
|
||||
if (propertyBool('use_asset_mover')) {
|
||||
relations {
|
||||
requiredDependency 'assetmover'
|
||||
}
|
||||
}
|
||||
}
|
||||
options {
|
||||
debug = propertyBool('curseforge_debug')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation here: https://github.com/modrinth/minotaur
|
||||
if (propertyBool('publish_to_modrinth')) {
|
||||
apply plugin: 'com.modrinth.minotaur'
|
||||
assertProperty('modrinth_project_id')
|
||||
assertProperty('release_type')
|
||||
setDefaultProperty('modrinth_debug', false, false)
|
||||
modrinth {
|
||||
token = System.getenv('MODRINTH_TOKEN') ? "" : System.getenv('MODRINTH_TOKEN')
|
||||
projectId = propertyString('modrinth_project_id')
|
||||
versionNumber = propertyString('mod_version')
|
||||
versionType = propertyString('release_type')
|
||||
uploadFile = tasks.reobfJar
|
||||
gameVersions = ['1.12.2']
|
||||
loaders = ['forge']
|
||||
debugMode = propertyBool('modrinth_debug')
|
||||
if (propertyBool('use_mixins') || propertyBool('use_asset_mover')) {
|
||||
dependencies {
|
||||
if (propertyBool('use_mixins')) {
|
||||
required.project 'mixinbooter'
|
||||
}
|
||||
if (propertyBool('use_asset_mover')) {
|
||||
required.project 'assetmover'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!propertyBool('publish_with_changelog')) {
|
||||
changelog = parserChangelog()
|
||||
}
|
||||
if (propertyBool('modrinth_sync_readme')) {
|
||||
syncBodyFrom = file('README.md').text
|
||||
tasks.modrinth.dependsOn(tasks.modrinthSyncBody)
|
||||
}
|
||||
}
|
||||
}
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -2,12 +2,11 @@ pluginManagement {
|
|||
repositories {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name = "GTNH Maven"
|
||||
url = uri("http://jenkins.usrv.eu:8081/nexus/content/groups/public/")
|
||||
allowInsecureProtocol = true
|
||||
name 'GTNH Maven'
|
||||
url 'https://nexus.gtnewhorizons.com/repository/public/'
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons")
|
||||
includeGroup("com.gtnewhorizons.retrofuturagradle")
|
||||
includeGroup 'com.gtnewhorizons'
|
||||
includeGroup 'com.gtnewhorizons.retrofuturagradle'
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
|
@ -18,7 +17,9 @@ pluginManagement {
|
|||
|
||||
plugins {
|
||||
// Automatic toolchain provisioning
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.4.0"
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0'
|
||||
}
|
||||
|
||||
rootProject.name = archives_base_name
|
||||
// Due to an IntelliJ bug, this has to be done
|
||||
// rootProject.name = archives_base_name
|
||||
rootProject.name = rootProject.projectDir.getName()
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
- Here lies the root of the `io.github.cleanroommc` package, add another level with your mod id and use that as the root for your mod classes.
|
||||
|
113
src/main/java/ru/octol1ttle/knockdowns/client/ClientProxy.java
Normal file
113
src/main/java/ru/octol1ttle/knockdowns/client/ClientProxy.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
package ru.octol1ttle.knockdowns.client;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
|
||||
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
|
||||
import ru.octol1ttle.knockdowns.client.event.KnockdownsKeyListener;
|
||||
import ru.octol1ttle.knockdowns.client.util.DirectionalCallSound;
|
||||
import ru.octol1ttle.knockdowns.common.IClientProxy;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsMod;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
|
||||
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class ClientProxy implements IClientProxy {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
|
||||
@Override
|
||||
public void onFMLInit(FMLInitializationEvent event) {
|
||||
KnockdownsMod.LOGGER.info("Registering key bindings");
|
||||
KnockdownsKeyListener.registerKeyBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T handleMessage(IMessage message) {
|
||||
if (message instanceof PlayerCalloutS2CPacket) {
|
||||
PlayerCalloutS2CPacket packet = (PlayerCalloutS2CPacket) message;
|
||||
client.addScheduledTask(() -> {
|
||||
if (CalloutManager.addOrUpdateCallout(packet)) {
|
||||
CalloutManager.playCalloutSound(packet);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof PlayerKnockedDownS2CPacket) {
|
||||
PlayerKnockedDownS2CPacket packet = (PlayerKnockedDownS2CPacket) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(packet.playerId);
|
||||
if (entity != null) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
|
||||
data.setKnockedDown(true);
|
||||
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
|
||||
data.getRevivers().clear();
|
||||
}
|
||||
|
||||
if (client.player.dimension == packet.dimensionId) {
|
||||
client.getSoundHandler().playSound(new DirectionalCallSound(KnockdownsSoundEvents.KNOCKED_DOWN, entity, packet.position));
|
||||
KnockedNotificationManager.addKnockedNotification(packet.playerId, packet.position);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof SynchronizePlayerDataS2CPacket.KnockedDown) {
|
||||
SynchronizePlayerDataS2CPacket.KnockedDown packet = (SynchronizePlayerDataS2CPacket.KnockedDown) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(packet.playerId);
|
||||
if (entity != null) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
|
||||
data.setKnockedDown(packet.knockedDown);
|
||||
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
|
||||
data.getRevivers().clear();
|
||||
}
|
||||
});
|
||||
} else if (message instanceof SynchronizePlayerDataS2CPacket.ReviveTimeLeft) {
|
||||
SynchronizePlayerDataS2CPacket.ReviveTimeLeft packet = (SynchronizePlayerDataS2CPacket.ReviveTimeLeft) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(packet.playerId);
|
||||
if (entity != null) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
|
||||
data.setReviveTimeLeft(packet.reviveTimeLeft);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof SynchronizePlayerDataS2CPacket.Full) {
|
||||
SynchronizePlayerDataS2CPacket.Full packet = (SynchronizePlayerDataS2CPacket.Full) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer entity = (EntityPlayer) client.world.getEntityByID(packet.playerId);
|
||||
if (entity != null) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(entity);
|
||||
data.setKnockedDown(packet.knockedDown);
|
||||
data.setReviveTimeLeft(packet.reviveTimeLeft);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof SynchronizeReviversS2CPacket.Add) {
|
||||
SynchronizeReviversS2CPacket.Add packet = (SynchronizeReviversS2CPacket.Add) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer knocked = (EntityPlayer) client.world.getEntityByID(packet.knockedId);
|
||||
EntityPlayer reviver = (EntityPlayer) client.world.getEntityByID(packet.reviverId);
|
||||
if (knocked != null && reviver != null) {
|
||||
IKnockdownsPlayerData.get(knocked).getRevivers().add(reviver);
|
||||
}
|
||||
});
|
||||
} else if (message instanceof SynchronizeReviversS2CPacket.Remove) {
|
||||
SynchronizeReviversS2CPacket.Remove packet = (SynchronizeReviversS2CPacket.Remove) message;
|
||||
client.addScheduledTask(() -> {
|
||||
EntityPlayer knocked = (EntityPlayer) client.world.getEntityByID(packet.knockedId);
|
||||
EntityPlayer reviver = (EntityPlayer) client.world.getEntityByID(packet.reviverId);
|
||||
if (knocked != null && reviver != null) {
|
||||
IKnockdownsPlayerData.get(knocked).getRevivers().remove(reviver);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown packet received on the client: " + message.getClass().getName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package ru.octol1ttle.knockdowns.client.communication;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.client.util.Callout;
|
||||
import ru.octol1ttle.knockdowns.client.util.DirectionalCallSound;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class CalloutManager {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final Map<Integer, Callout> callouts = new HashMap<>();
|
||||
|
||||
public static Set<Map.Entry<Integer, Callout>> getCallouts() {
|
||||
return callouts.entrySet();
|
||||
}
|
||||
|
||||
public static boolean addOrUpdateCallout(PlayerCalloutS2CPacket message) {
|
||||
return callouts.put(message.playerId, new Callout(message.position, message.type, client.world.getTotalWorldTime())) == null;
|
||||
}
|
||||
|
||||
public static void playCalloutSound(PlayerCalloutS2CPacket message) {
|
||||
client.getSoundHandler().playSound(new DirectionalCallSound(KnockdownsSoundEvents.CALLOUT, client.world.getEntityByID(message.playerId), message.position));
|
||||
}
|
||||
|
||||
public static void clearCallouts() {
|
||||
callouts.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package ru.octol1ttle.knockdowns.client.communication;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.client.util.KnockedPlayerData;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class KnockedNotificationManager {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final List<KnockedPlayerData> knockedDatas = new ArrayList<>();
|
||||
|
||||
public static void addKnockedNotification(int playerId, Vec3d position) {
|
||||
knockedDatas.add(new KnockedPlayerData(playerId, position, client.world.getTotalWorldTime()));
|
||||
}
|
||||
|
||||
public static Collection<KnockedPlayerData> getKnockedPlayerDatas() {
|
||||
return knockedDatas;
|
||||
}
|
||||
|
||||
public static void clearDatas() {
|
||||
knockedDatas.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package ru.octol1ttle.knockdowns.client.event;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.InputEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
|
||||
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
|
||||
import ru.octol1ttle.knockdowns.client.gui.CommunicationGui;
|
||||
import ru.octol1ttle.knockdowns.client.gui.KnockedNotificationGui;
|
||||
import ru.octol1ttle.knockdowns.client.gui.ReviveGui;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(value = Side.CLIENT, modid = Tags.MOD_ID)
|
||||
public class KnockdownsClientEventListener {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final CommunicationGui communicationGui = new CommunicationGui();
|
||||
private static final KnockedNotificationGui notificationGui = new KnockedNotificationGui();
|
||||
private static final ReviveGui reviveGui = new ReviveGui();
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTick(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START) {
|
||||
return;
|
||||
}
|
||||
if (client.world == null) {
|
||||
CalloutManager.clearCallouts();
|
||||
KnockedNotificationManager.clearDatas();
|
||||
return;
|
||||
}
|
||||
CalloutManager.getCallouts().removeIf(callout -> client.world.getTotalWorldTime() - callout.getValue().getReceiveTime() > 60);
|
||||
KnockedNotificationManager.getKnockedPlayerDatas().removeIf(notification -> client.world.getTotalWorldTime() - notification.getReceiveTime() > 100);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
||||
List<EntityPlayer> revivers = IKnockdownsPlayerData.get(event.player).getRevivers();
|
||||
if (revivers.contains(client.player) && !event.player.equals(client.pointedEntity)) {
|
||||
KnockdownsNetwork.sendToServer(new CancelReviveC2SPacket());
|
||||
revivers.remove(client.player);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderWorldLast(RenderWorldLastEvent event) {
|
||||
notificationGui.renderNotifications(event.getPartialTicks());
|
||||
communicationGui.renderCallouts(event.getPartialTicks());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderGameOverlay(RenderGameOverlayEvent.Chat event) {
|
||||
communicationGui.render(event.getPartialTicks(), event.getResolution());
|
||||
reviveGui.render(event.getPartialTicks(), event.getResolution());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKeyInput(InputEvent.KeyInputEvent event) {
|
||||
KnockdownsKeyListener.tickKeys();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package ru.octol1ttle.knockdowns.client.event;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraftforge.fml.client.registry.ClientRegistry;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(value = Side.CLIENT, modid = Tags.MOD_ID)
|
||||
public class KnockdownsKeyListener {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
public static final Map<KeyBinding, Supplier<CalloutType>> calloutBindings = new HashMap<>();
|
||||
|
||||
public static void registerKeyBindings() {
|
||||
calloutBindings.put(
|
||||
new KeyBinding("knockdowns.key.callout.danger", Keyboard.KEY_LEFT, "knockdowns.key.category"),
|
||||
() -> CalloutType.DANGER
|
||||
);
|
||||
calloutBindings.put(
|
||||
new KeyBinding("knockdowns.key.callout.booyah", Keyboard.KEY_DOWN, "knockdowns.key.category"),
|
||||
() -> CalloutType.BOOYAH
|
||||
);
|
||||
calloutBindings.put(
|
||||
new KeyBinding("knockdowns.key.callout.this_way_help", Keyboard.KEY_UP, "knockdowns.key.category"),
|
||||
() -> IKnockdownsPlayerData.get(client.player).isKnockedDown() ? CalloutType.HELP : CalloutType.THIS_WAY
|
||||
);
|
||||
calloutBindings.put(
|
||||
new KeyBinding("knockdowns.key.callout.ouch", Keyboard.KEY_RIGHT, "knockdowns.key.category"),
|
||||
() -> CalloutType.OUCH
|
||||
);
|
||||
|
||||
for (KeyBinding binding : calloutBindings.keySet()) {
|
||||
ClientRegistry.registerKeyBinding(binding);
|
||||
}
|
||||
}
|
||||
|
||||
public static void tickKeys() {
|
||||
for (KeyBinding binding : calloutBindings.keySet()) {
|
||||
if (binding.isPressed()) {
|
||||
KnockdownsNetwork.sendToServer(new PlayerCalloutC2SPacket(calloutBindings.get(binding).get()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package ru.octol1ttle.knockdowns.client.gui;
|
||||
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.client.communication.CalloutManager;
|
||||
import ru.octol1ttle.knockdowns.client.event.KnockdownsKeyListener;
|
||||
import ru.octol1ttle.knockdowns.client.util.Callout;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class CommunicationGui extends KnockdownsBaseGui {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final ResourceLocation LEFT_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/left_arrow.png");
|
||||
private static final ResourceLocation DOWN_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/down_arrow.png");
|
||||
private static final ResourceLocation UP_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/up_arrow.png");
|
||||
private static final ResourceLocation RIGHT_ARROW = new ResourceLocation(Tags.MOD_ID, "textures/gui/right_arrow.png");
|
||||
private static final int SCREEN_EDGE_MARGIN = 5;
|
||||
private static final int SEPARATOR_MARGIN = 2;
|
||||
private static final int KEY_SIZE = 17;
|
||||
private float totalPartialTicks;
|
||||
|
||||
@Override
|
||||
public void render(float partialTicks, ScaledResolution resolution) {
|
||||
FontRenderer font = client.fontRenderer;
|
||||
|
||||
int x = SCREEN_EDGE_MARGIN;
|
||||
int y = resolution.getScaledHeight() - SCREEN_EDGE_MARGIN - font.FONT_HEIGHT;
|
||||
|
||||
KeyBinding[] sortedBindings = new KeyBinding[4];
|
||||
for (KeyBinding binding : KnockdownsKeyListener.calloutBindings.keySet())
|
||||
{
|
||||
switch (binding.getKeyCode()) {
|
||||
case Keyboard.KEY_LEFT:
|
||||
sortedBindings[0] = binding;
|
||||
break;
|
||||
case Keyboard.KEY_DOWN:
|
||||
sortedBindings[1] = binding;
|
||||
break;
|
||||
case Keyboard.KEY_UP:
|
||||
sortedBindings[2] = binding;
|
||||
break;
|
||||
case Keyboard.KEY_RIGHT:
|
||||
sortedBindings[3] = binding;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
KeyBinding leftCallout = sortedBindings[0];
|
||||
if (leftCallout != null) {
|
||||
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(leftCallout).get().getTextKey());
|
||||
font.drawStringWithShadow(
|
||||
text,
|
||||
x,
|
||||
y - 12,
|
||||
0xFFFFFF
|
||||
);
|
||||
|
||||
x += font.getStringWidth(text) + SEPARATOR_MARGIN;
|
||||
client.getTextureManager().bindTexture(LEFT_ARROW);
|
||||
this.drawTexture(
|
||||
x,
|
||||
y - KEY_SIZE,
|
||||
KEY_SIZE,
|
||||
KEY_SIZE
|
||||
);
|
||||
x += KEY_SIZE + SEPARATOR_MARGIN;
|
||||
}
|
||||
|
||||
KeyBinding downCallout = sortedBindings[1];
|
||||
if (downCallout != null) {
|
||||
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(downCallout).get().getTextKey());
|
||||
font.drawStringWithShadow(
|
||||
text,
|
||||
x + KEY_SIZE * 0.5f - font.getStringWidth(text) * 0.5f,
|
||||
y + SEPARATOR_MARGIN,
|
||||
0xFFFFFF
|
||||
);
|
||||
client.getTextureManager().bindTexture(DOWN_ARROW);
|
||||
this.drawTexture(
|
||||
x,
|
||||
y - KEY_SIZE,
|
||||
KEY_SIZE,
|
||||
KEY_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
KeyBinding upCallout = sortedBindings[2];
|
||||
if (upCallout != null) {
|
||||
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(upCallout).get().getTextKey());
|
||||
font.drawStringWithShadow(
|
||||
text,
|
||||
x + KEY_SIZE * 0.5f - font.getStringWidth(text) * 0.5f,
|
||||
y - KEY_SIZE * 2 - 12,
|
||||
0xFFFFFF
|
||||
);
|
||||
|
||||
client.getTextureManager().bindTexture(UP_ARROW);
|
||||
this.drawTexture(
|
||||
x,
|
||||
y - KEY_SIZE * 2 - 2,
|
||||
KEY_SIZE,
|
||||
KEY_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
KeyBinding rightCallout = sortedBindings[3];
|
||||
if (rightCallout != null) {
|
||||
x += KEY_SIZE + SEPARATOR_MARGIN;
|
||||
String text = I18n.format(KnockdownsKeyListener.calloutBindings.get(rightCallout).get().getTextKey());
|
||||
font.drawStringWithShadow(
|
||||
text,
|
||||
x + KEY_SIZE + SEPARATOR_MARGIN,
|
||||
y - 12,
|
||||
0xFFFFFF
|
||||
);
|
||||
|
||||
client.getTextureManager().bindTexture(RIGHT_ARROW);
|
||||
this.drawTexture(
|
||||
x,
|
||||
y - KEY_SIZE,
|
||||
KEY_SIZE,
|
||||
KEY_SIZE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderCallouts(float partialTicks) {
|
||||
totalPartialTicks += partialTicks;
|
||||
for (Map.Entry<Integer, Callout> calloutEntry : CalloutManager.getCallouts()) {
|
||||
Entity entity = client.world.getEntityByID(calloutEntry.getKey());
|
||||
renderCallout(
|
||||
I18n.format(calloutEntry.getValue().getType().getTextKey()),
|
||||
entity != null ? entity.getPositionEyes(partialTicks).add(0, 1, 0) : calloutEntry.getValue().getPosition(),
|
||||
client.getRenderManager().playerViewX,
|
||||
client.getRenderManager().playerViewY,
|
||||
client.getRenderManager().options.thirdPersonView == 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCallout(String text, Vec3d position, float pitch, float yaw, boolean isThirdPersonFrontal) {
|
||||
FontRenderer font = client.fontRenderer;
|
||||
|
||||
Vec3d deltaPos = position.subtract(client.getRenderManager().viewerPosX, client.getRenderManager().viewerPosY, client.getRenderManager().viewerPosZ);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(deltaPos.x, deltaPos.y, deltaPos.z);
|
||||
GlStateManager.rotate(-yaw, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate((float)(isThirdPersonFrontal ? -1 : 1) * pitch, 1.0F, 0.0F, 0.0F);
|
||||
float scale = (float) Math.max(deltaPos.length() / 8.0f, 1.0f) * (0.75f + MathHelper.abs((float) (MathHelper.sin(totalPartialTicks / 10F) / Math.PI)));
|
||||
GlStateManager.scale(-0.025F * scale, -0.025F * scale, 0.025F * scale);
|
||||
GlStateManager.color(1f, 1f, 1f, 1f);
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.depthFunc(GL11.GL_ALWAYS);
|
||||
|
||||
font.drawStringWithShadow(text, -font.getStringWidth(text) * 0.5f, -font.FONT_HEIGHT * 0.5f, 0xFFFFFF);
|
||||
|
||||
GlStateManager.depthFunc(GL11.GL_LEQUAL);
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package ru.octol1ttle.knockdowns.client.gui;
|
||||
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract class KnockdownsBaseGui extends Gui {
|
||||
public abstract void render(float partialTicks, ScaledResolution resolution);
|
||||
|
||||
protected void drawTexture(int x, int y, int width, int height) {
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder bufferbuilder = tessellator.getBuffer();
|
||||
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX);
|
||||
bufferbuilder.pos(x, y, this.zLevel).tex(0, 0).endVertex();
|
||||
bufferbuilder.pos(x, y + height, this.zLevel).tex(0, 1).endVertex();
|
||||
bufferbuilder.pos(x + width, y + height, this.zLevel).tex(1, 1).endVertex();
|
||||
bufferbuilder.pos(x + width, y, this.zLevel).tex(1, 0).endVertex();
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package ru.octol1ttle.knockdowns.client.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.client.communication.KnockedNotificationManager;
|
||||
import ru.octol1ttle.knockdowns.client.util.KnockedPlayerData;
|
||||
|
||||
public class KnockedNotificationGui extends KnockdownsBaseGui {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
private static final int KNOCKED_ICON_SIZE = 18;
|
||||
private static final ResourceLocation KNOCKED_ICON = new ResourceLocation(Tags.MOD_ID, "textures/gui/knocked_icon.png");
|
||||
private float totalPartialTicks;
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void render(float partialTicks, ScaledResolution resolution) {
|
||||
}
|
||||
|
||||
public void renderNotifications(float partialTicks) {
|
||||
totalPartialTicks += partialTicks;
|
||||
for (KnockedPlayerData data : KnockedNotificationManager.getKnockedPlayerDatas()) {
|
||||
Entity entity = client.world.getEntityByID(data.getPlayerId());
|
||||
renderKnockedNotification(
|
||||
entity != null ? entity.getPositionEyes(partialTicks).add(0, 1, 0) : data.getPosition(),
|
||||
client.getRenderManager().playerViewX,
|
||||
client.getRenderManager().playerViewY,
|
||||
client.getRenderManager().options.thirdPersonView == 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderKnockedNotification(Vec3d position, float pitch, float yaw, boolean isThirdPersonFrontal) {
|
||||
Vec3d deltaPos = position.subtract(client.getRenderManager().viewerPosX, client.getRenderManager().viewerPosY, client.getRenderManager().viewerPosZ);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate(deltaPos.x, deltaPos.y, deltaPos.z);
|
||||
GlStateManager.rotate(-yaw, 0.0F, 1.0F, 0.0F);
|
||||
GlStateManager.rotate((float)(isThirdPersonFrontal ? -1 : 1) * pitch, 1.0F, 0.0F, 0.0F);
|
||||
float scale = (float) Math.max(deltaPos.length() / 8.0f, 1.0f) * (0.75f + MathHelper.abs((float) (MathHelper.sin(totalPartialTicks / 10F) / Math.PI)));
|
||||
GlStateManager.scale(0.05F * scale, 0.05F * scale, 0.05F * scale);
|
||||
GlStateManager.color(1f, 1f, 1f, 1f);
|
||||
GlStateManager.disableCull();
|
||||
GlStateManager.depthFunc(GL11.GL_ALWAYS);
|
||||
|
||||
client.getTextureManager().bindTexture(KNOCKED_ICON);
|
||||
this.drawTexture(
|
||||
-KNOCKED_ICON_SIZE / 2,
|
||||
-KNOCKED_ICON_SIZE / 2,
|
||||
KNOCKED_ICON_SIZE,
|
||||
KNOCKED_ICON_SIZE
|
||||
);
|
||||
|
||||
GlStateManager.depthFunc(GL11.GL_LEQUAL);
|
||||
GlStateManager.enableCull();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package ru.octol1ttle.knockdowns.client.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
|
||||
public class ReviveGui extends KnockdownsBaseGui {
|
||||
private static final Minecraft client = Minecraft.getMinecraft();
|
||||
|
||||
@Override
|
||||
public void render(float partialTicks, ScaledResolution resolution) {
|
||||
EntityPlayer reviving =
|
||||
client.pointedEntity instanceof EntityPlayer && IKnockdownsPlayerData.get((EntityPlayer) client.pointedEntity).getRevivers().contains(client.player)
|
||||
? (EntityPlayer) client.pointedEntity
|
||||
: client.player;
|
||||
if (IKnockdownsPlayerData.get(reviving).getReviveTimeLeft() == KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT) {
|
||||
return;
|
||||
}
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(reviving);
|
||||
|
||||
FontRenderer font = client.fontRenderer;
|
||||
|
||||
String timerText = String.format("%.1f", data.getReviveTimeLeft() / 20.0f);
|
||||
float timerX = (resolution.getScaledWidth() - font.getStringWidth(timerText)) * 0.5f;
|
||||
|
||||
data.getRevivers().removeIf(reviver -> reviver.isDead || !reviver.isEntityAlive() || IKnockdownsPlayerData.get(reviver).isKnockedDown());
|
||||
int reviverCount = data.getRevivers().size();
|
||||
TextFormatting color;
|
||||
if (reviverCount == 0) {
|
||||
color = TextFormatting.RED;
|
||||
} else if (reviverCount == 1) {
|
||||
color = TextFormatting.WHITE;
|
||||
} else {
|
||||
color = TextFormatting.GREEN;
|
||||
}
|
||||
|
||||
String reviverCountText = "x" + reviverCount;
|
||||
float reviveCountX = (resolution.getScaledWidth() - font.getStringWidth(reviverCountText)) * 0.5f;
|
||||
|
||||
font.drawStringWithShadow(color + timerText, timerX, resolution.getScaledHeight() * 0.5f + 5, 0xFFFFFF);
|
||||
font.drawStringWithShadow(color + reviverCountText, reviveCountX, resolution.getScaledHeight() * 0.5f + 14, 0xFFFFFF);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ru.octol1ttle.knockdowns.client.util;
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class Callout {
|
||||
private final Vec3d position;
|
||||
private final CalloutType type;
|
||||
private final long receiveTime;
|
||||
|
||||
public Callout(Vec3d position, CalloutType type, long receiveTime) {
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
this.receiveTime = receiveTime;
|
||||
}
|
||||
|
||||
public Vec3d getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public CalloutType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public long getReceiveTime() {
|
||||
return receiveTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package ru.octol1ttle.knockdowns.client.util;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.MovingSound;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class DirectionalCallSound extends MovingSound {
|
||||
private final @Nullable Entity entity;
|
||||
private final Vec3d position;
|
||||
private int time;
|
||||
|
||||
public DirectionalCallSound(SoundEvent event, @Nullable Entity entity, Vec3d position) {
|
||||
super(event, SoundCategory.PLAYERS);
|
||||
this.entity = entity;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
this.time++;
|
||||
if (this.time > 40 || this.entity != null && this.entity.isDead) {
|
||||
this.donePlaying = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Minecraft client = Minecraft.getMinecraft();
|
||||
Vec3d calloutPos = this.entity != null ? this.entity.getPositionVector() : this.position;
|
||||
Vec3d directionVec = calloutPos.subtract(client.player.getPositionVector()).normalize();
|
||||
Vec3d finalPos = client.player.getPositionVector().add(directionVec);
|
||||
|
||||
this.xPosF = (float) finalPos.x;
|
||||
this.yPosF = (float) finalPos.y;
|
||||
this.zPosF = (float) finalPos.z;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ru.octol1ttle.knockdowns.client.util;
|
||||
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class KnockedPlayerData {
|
||||
private final int playerId;
|
||||
private final Vec3d position;
|
||||
private final long receiveTime;
|
||||
|
||||
public KnockedPlayerData(int playerId, Vec3d position, long receiveTime) {
|
||||
this.playerId = playerId;
|
||||
this.position = position;
|
||||
this.receiveTime = receiveTime;
|
||||
}
|
||||
|
||||
public int getPlayerId() {
|
||||
return playerId;
|
||||
}
|
||||
|
||||
public Vec3d getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public long getReceiveTime() {
|
||||
return receiveTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public interface IClientProxy {
|
||||
void onFMLInit(FMLInitializationEvent event);
|
||||
|
||||
<T> T handleMessage(IMessage message);
|
||||
|
||||
class Dummy implements IClientProxy {
|
||||
@Override
|
||||
public void onFMLInit(FMLInitializationEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T handleMessage(IMessage message) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingDeathEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
|
||||
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.data.KnockdownsCapability;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.registry.KnockdownsSoundEvents;
|
||||
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_HURT_PERIOD;
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_INVULNERABILITY_TICKS;
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.KNOCKED_TENACITY;
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.allPlayersKnocked;
|
||||
import static ru.octol1ttle.knockdowns.common.KnockdownsUtils.resetKnockedState;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = Tags.MOD_ID)
|
||||
public class KnockdownsCommonEventListener {
|
||||
public static void onFMLInit(FMLInitializationEvent event) {
|
||||
KnockdownsMod.LOGGER.info("Registering network packets");
|
||||
KnockdownsNetwork.registerPackets();
|
||||
KnockdownsMod.LOGGER.info("Registering capability");
|
||||
KnockdownsCapability.register();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onSoundsRegister(RegistryEvent.Register<SoundEvent> event) {
|
||||
event.getRegistry().register(KnockdownsSoundEvents.CALLOUT);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCapabilitiesAttach(AttachCapabilitiesEvent<Entity> event) {
|
||||
if (event.getObject() instanceof EntityPlayer) {
|
||||
event.addCapability(KnockdownsCapability.ID, new KnockdownsCapability());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
||||
MinecraftServer server = event.player.getServer();
|
||||
if (event.phase == TickEvent.Phase.START || server == null) {
|
||||
return;
|
||||
}
|
||||
EntityPlayerMP knocked = (EntityPlayerMP) event.player;
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(knocked);
|
||||
if (!data.isKnockedDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (allPlayersKnocked(server, knocked)) {
|
||||
knocked.attackEntityFrom(DamageSource.GENERIC, knocked.getMaxHealth());
|
||||
return;
|
||||
}
|
||||
|
||||
List<EntityPlayer> revivers = data.getRevivers();
|
||||
revivers.removeIf(reviver -> reviver.isDead || !reviver.isEntityAlive() || IKnockdownsPlayerData.get(reviver).isKnockedDown());
|
||||
if (!revivers.isEmpty()) {
|
||||
data.setReviveTimeLeft(data.getReviveTimeLeft() - revivers.size());
|
||||
KnockdownsNetwork.sendToMultiple(
|
||||
new SynchronizePlayerDataS2CPacket.ReviveTimeLeft(knocked.getEntityId(), data.getReviveTimeLeft()),
|
||||
revivers,
|
||||
knocked
|
||||
);
|
||||
|
||||
if (data.getReviveTimeLeft() <= 0) {
|
||||
resetKnockedState(knocked, data);
|
||||
|
||||
knocked.setEntityInvulnerable(false);
|
||||
knocked.setHealth(knocked.getMaxHealth() * 0.3f);
|
||||
knocked.setAbsorptionAmount(0.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int oldReviveTimeLeft = data.getReviveTimeLeft();
|
||||
data.setReviveTimeLeft(Math.min(INITIAL_REVIVE_TIME_LEFT, oldReviveTimeLeft + 1));
|
||||
if (data.getReviveTimeLeft() != oldReviveTimeLeft) {
|
||||
KnockdownsNetwork.sendToPlayer(
|
||||
new SynchronizePlayerDataS2CPacket.ReviveTimeLeft(knocked.getEntityId(), data.getReviveTimeLeft()),
|
||||
knocked
|
||||
);
|
||||
}
|
||||
|
||||
data.setTicksKnocked(data.getTicksKnocked() + 1);
|
||||
|
||||
int period = MathHelper.floor(KNOCKED_HURT_PERIOD * 20);
|
||||
if (data.getTicksKnocked() >= KNOCKED_INVULNERABILITY_TICKS && data.getTicksKnocked() % period == 0) {
|
||||
knocked.setEntityInvulnerable(false);
|
||||
knocked.attackEntityFrom(DamageSource.GENERIC, knocked.getMaxHealth() / (KNOCKED_TENACITY / KNOCKED_HURT_PERIOD));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerDeath(LivingDeathEvent event) {
|
||||
if (!(event.getEntityLiving() instanceof EntityPlayerMP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityPlayerMP player = (EntityPlayerMP) event.getEntityLiving();
|
||||
IKnockdownsPlayerData data = player.getCapability(KnockdownsCapability.CAPABILITY, null);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isKnockedDown() || allPlayersKnocked(player.getServer(), player)) {
|
||||
data.getRevivers().clear();
|
||||
return;
|
||||
}
|
||||
|
||||
player.clearActivePotions();
|
||||
player.setEntityInvulnerable(true);
|
||||
player.setHealth(1.0f);
|
||||
player.setAbsorptionAmount(player.getMaxHealth() - 1.0f);
|
||||
player.extinguish();
|
||||
player.setAir(300);
|
||||
player.clearElytraFlying();
|
||||
|
||||
player.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, 6000, 3));
|
||||
|
||||
Entity trueSource = event.getSource().getTrueSource();
|
||||
if (trueSource instanceof EntityLiving) {
|
||||
((EntityLiving) trueSource).setAttackTarget(null);
|
||||
}
|
||||
|
||||
data.setKnockedDown(true);
|
||||
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
|
||||
data.setTicksKnocked(0);
|
||||
|
||||
KnockdownsNetwork.sendToAll(new PlayerKnockedDownS2CPacket(player.getEntityId(), player.dimension, player.getPositionEyes(1).add(0, 1, 0)));
|
||||
|
||||
TextComponentTranslation deathMessage = (TextComponentTranslation) player.getCombatTracker().getDeathMessage();
|
||||
|
||||
String knockdownKey = deathMessage.getKey().replace("death.", "knockdown.");
|
||||
TextComponentTranslation knockdownTranslation = new TextComponentTranslation(knockdownKey, deathMessage.getFormatArgs());
|
||||
player.getServer().getPlayerList().sendMessage(
|
||||
!knockdownTranslation.getUnformattedComponentText().equals(knockdownKey) ? knockdownTranslation : deathMessage,
|
||||
true
|
||||
);
|
||||
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onMobTarget(LivingSetAttackTargetEvent event) {
|
||||
if (event.getTarget() instanceof EntityPlayer && IKnockdownsPlayerData.get((EntityPlayer) event.getTarget()).isKnockedDown()) {
|
||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerStartTracking(PlayerEvent.StartTracking event) {
|
||||
if (event.getTarget() instanceof EntityPlayerMP) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get((EntityPlayer) event.getTarget());
|
||||
if (data.isKnockedDown()) {
|
||||
KnockdownsNetwork.sendToPlayer(
|
||||
new SynchronizePlayerDataS2CPacket.KnockedDown(
|
||||
event.getTarget().getEntityId(),
|
||||
data.isKnockedDown()
|
||||
),
|
||||
(EntityPlayerMP) event.getEntityPlayer()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKnockedAttack(AttackEntityEvent event) {
|
||||
if (IKnockdownsPlayerData.get(event.getEntityPlayer()).isKnockedDown()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onKnockedInteraction(PlayerInteractEvent event) {
|
||||
if (IKnockdownsPlayerData.get(event.getEntityPlayer()).isKnockedDown()) {
|
||||
if (!(event instanceof PlayerInteractEvent.RightClickBlock) && event.isCancelable()) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(EnumActionResult.FAIL);
|
||||
}
|
||||
} else if (event instanceof PlayerInteractEvent.EntityInteract) {
|
||||
onPlayerInteraction((PlayerInteractEvent.EntityInteract) event);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPlayerInteraction(PlayerInteractEvent.EntityInteract event) {
|
||||
if (event.getTarget() instanceof EntityPlayerMP) {
|
||||
EntityPlayerMP knocked = (EntityPlayerMP) event.getTarget();
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(knocked);
|
||||
if (data.isKnockedDown() && !data.getRevivers().contains(event.getEntityPlayer())) {
|
||||
for (EntityPlayer reviver : data.getRevivers()) {
|
||||
KnockdownsNetwork.sendToPlayer(
|
||||
new SynchronizeReviversS2CPacket.Add(event.getTarget().getEntityId(), reviver.getEntityId()),
|
||||
(EntityPlayerMP) event.getEntityPlayer()
|
||||
);
|
||||
}
|
||||
|
||||
data.getRevivers().add(event.getEntityPlayer());
|
||||
KnockdownsNetwork.sendToMultiple(
|
||||
new SynchronizeReviversS2CPacket.Add(event.getTarget().getEntityId(), event.getEntityPlayer().getEntityId()),
|
||||
data.getRevivers(),
|
||||
knocked
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerJoin(PlayerLoggedInEvent event) {
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(event.player);
|
||||
KnockdownsNetwork.sendToPlayer(
|
||||
new SynchronizePlayerDataS2CPacket.Full(event.player.getEntityId(), data.isKnockedDown(), data.getReviveTimeLeft()),
|
||||
(EntityPlayerMP) event.player
|
||||
);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerLeave(PlayerLoggedOutEvent event) {
|
||||
for (EntityPlayer knocked : event.player.world.playerEntities) {
|
||||
List<EntityPlayer> revivers = IKnockdownsPlayerData.get(knocked).getRevivers();
|
||||
if (revivers.contains(event.player)) {
|
||||
revivers.remove(event.player);
|
||||
KnockdownsNetwork.sendToMultiple(
|
||||
new SynchronizeReviversS2CPacket.Remove(knocked.getEntityId(), event.player.getEntityId()),
|
||||
revivers,
|
||||
(EntityPlayerMP) knocked
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
||||
import zone.rong.mixinbooter.IEarlyMixinLoader;
|
||||
|
||||
@IFMLLoadingPlugin.MCVersion("1.12.2")
|
||||
public class KnockdownsFMLLoadingPlugin implements IFMLLoadingPlugin, IEarlyMixinLoader {
|
||||
@Override
|
||||
public String[] getASMTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModContainerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSetupClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectData(Map<String, Object> data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessTransformerClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixinConfigs() {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
list.add("mixins.knockdowns.json");
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.SidedProxy;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
|
||||
@Mod(modid = Tags.MOD_ID, name = Tags.MOD_NAME, version = Tags.VERSION)
|
||||
public class KnockdownsMod {
|
||||
public static final Logger LOGGER = LogManager.getLogger(Tags.MOD_NAME);
|
||||
@SidedProxy(clientSide = "ru.octol1ttle.knockdowns.client.ClientProxy", serverSide = "ru.octol1ttle.knockdowns.common.IClientProxy$Dummy")
|
||||
public static IClientProxy clientProxy;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void onFMLInit(FMLInitializationEvent event) {
|
||||
LOGGER.info("Initializing");
|
||||
clientProxy.onFMLInit(event);
|
||||
KnockdownsCommonEventListener.onFMLInit(event);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package ru.octol1ttle.knockdowns.common;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.network.KnockdownsNetwork;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
|
||||
|
||||
public class KnockdownsUtils {
|
||||
public static final int INITIAL_REVIVE_TIME_LEFT = 200;
|
||||
public static final float KNOCKED_INVULNERABILITY_TICKS = 3.0f * 20.0f;
|
||||
public static final float KNOCKED_HURT_PERIOD = 1.2f;
|
||||
public static final float KNOCKED_TENACITY = 60.0f;
|
||||
|
||||
public static boolean allPlayersKnocked(MinecraftServer server, EntityPlayer except) {
|
||||
for (EntityPlayer player : server.getPlayerList().getPlayers()) {
|
||||
if (player.equals(except)) {
|
||||
continue;
|
||||
}
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(player);
|
||||
if (player.isEntityAlive() && !data.isKnockedDown()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void resetKnockedState(EntityPlayerMP player, IKnockdownsPlayerData data) {
|
||||
player.removePotionEffect(MobEffects.SLOWNESS);
|
||||
data.setKnockedDown(false);
|
||||
data.setReviveTimeLeft(INITIAL_REVIVE_TIME_LEFT);
|
||||
data.setTicksKnocked(0);
|
||||
|
||||
KnockdownsNetwork.sendToTrackingAndSelf(
|
||||
new SynchronizePlayerDataS2CPacket.KnockedDown(player.getEntityId(), data.isKnockedDown()),
|
||||
player
|
||||
);
|
||||
|
||||
data.getRevivers().clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package ru.octol1ttle.knockdowns.common.communication;
|
||||
|
||||
public enum CalloutType {
|
||||
DANGER((byte) 0, "knockdowns.callout.danger"),
|
||||
BOOYAH((byte) 1, "knockdowns.callout.booyah"),
|
||||
THIS_WAY((byte) 2, "knockdowns.callout.this_way"),
|
||||
OUCH((byte) 3, "knockdowns.callout.ouch"),
|
||||
HELP((byte) 4, "knockdowns.callout.help");
|
||||
|
||||
private final byte id;
|
||||
private final String textKey;
|
||||
|
||||
CalloutType(byte id, String textKey) {
|
||||
this.id = id;
|
||||
this.textKey = textKey;
|
||||
}
|
||||
|
||||
public byte getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getTextKey() {
|
||||
return textKey;
|
||||
}
|
||||
|
||||
public static CalloutType byId(byte id) {
|
||||
for (CalloutType type : CalloutType.values()) {
|
||||
if (id == type.getId()) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package ru.octol1ttle.knockdowns.common.data;
|
||||
|
||||
import java.util.Objects;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.INBTSerializable;
|
||||
import ru.octol1ttle.knockdowns.common.util.UniqueOnlyList;
|
||||
|
||||
public interface IKnockdownsPlayerData extends INBTSerializable<NBTTagCompound> {
|
||||
boolean isKnockedDown();
|
||||
void setKnockedDown(boolean knockedDown);
|
||||
|
||||
int getReviveTimeLeft();
|
||||
void setReviveTimeLeft(int reviveTimeLeft);
|
||||
|
||||
int getTicksKnocked();
|
||||
void setTicksKnocked(int ticksKnocked);
|
||||
|
||||
UniqueOnlyList<EntityPlayer> getRevivers();
|
||||
|
||||
static IKnockdownsPlayerData get(EntityPlayer player) {
|
||||
return Objects.requireNonNull(player.getCapability(KnockdownsCapability.CAPABILITY, null));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package ru.octol1ttle.knockdowns.common.data;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.LazyLoadBase;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.CapabilityInject;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
|
||||
public class KnockdownsCapability implements ICapabilitySerializable<NBTTagCompound> {
|
||||
@CapabilityInject(IKnockdownsPlayerData.class)
|
||||
public static Capability<IKnockdownsPlayerData> CAPABILITY;
|
||||
public static final ResourceLocation ID = new ResourceLocation(Tags.MOD_ID, "data");
|
||||
|
||||
private KnockdownsPlayerData playerData = null;
|
||||
private final LazyLoadBase<KnockdownsPlayerData> lazy = new LazyLoadBase<KnockdownsPlayerData>() {
|
||||
@Override
|
||||
protected KnockdownsPlayerData load() {
|
||||
return playerData == null ? (playerData = new KnockdownsPlayerData()) : playerData;
|
||||
}
|
||||
};
|
||||
|
||||
public static void register() {
|
||||
CapabilityManager.INSTANCE.register(IKnockdownsPlayerData.class, new Capability.IStorage<IKnockdownsPlayerData>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public NBTBase writeNBT(Capability<IKnockdownsPlayerData> capability, IKnockdownsPlayerData instance, EnumFacing side) {
|
||||
return instance.serializeNBT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(Capability<IKnockdownsPlayerData> capability, IKnockdownsPlayerData instance, EnumFacing side, NBTBase nbt) {
|
||||
instance.deserializeNBT((NBTTagCompound) nbt);
|
||||
}
|
||||
}, KnockdownsPlayerData::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
|
||||
return capability == CAPABILITY;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
|
||||
return capability == CAPABILITY ? (T) lazy.getValue() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound serializeNBT() {
|
||||
return lazy.getValue().serializeNBT();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(NBTTagCompound nbt) {
|
||||
lazy.getValue().deserializeNBT(nbt);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package ru.octol1ttle.knockdowns.common.data;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
|
||||
import ru.octol1ttle.knockdowns.common.util.UniqueOnlyList;
|
||||
|
||||
public class KnockdownsPlayerData implements IKnockdownsPlayerData {
|
||||
private static final String KEY_KNOCKED_DOWN = "KnockedDown";
|
||||
private static final String KEY_REVIVE_TIME_LEFT = "ReviveTimeLeft";
|
||||
private static final String KEY_TICKS_KNOCKED = "TicksKnocked";
|
||||
private boolean knockedDown = false;
|
||||
private int reviveTimeLeft = KnockdownsUtils.INITIAL_REVIVE_TIME_LEFT;
|
||||
private int ticksKnocked = 0;
|
||||
private final UniqueOnlyList<EntityPlayer> revivers = new UniqueOnlyList<>();
|
||||
|
||||
@Override
|
||||
public boolean isKnockedDown() {
|
||||
return this.knockedDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKnockedDown(boolean knockedDown) {
|
||||
this.knockedDown = knockedDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReviveTimeLeft() {
|
||||
return this.reviveTimeLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReviveTimeLeft(int reviveTimeLeft) {
|
||||
this.reviveTimeLeft = reviveTimeLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTicksKnocked() {
|
||||
return this.ticksKnocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTicksKnocked(int ticksKnocked) {
|
||||
this.ticksKnocked = ticksKnocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UniqueOnlyList<EntityPlayer> getRevivers() {
|
||||
return revivers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound serializeNBT() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setBoolean(KEY_KNOCKED_DOWN, this.knockedDown);
|
||||
nbt.setInteger(KEY_REVIVE_TIME_LEFT, this.reviveTimeLeft);
|
||||
nbt.setInteger(KEY_TICKS_KNOCKED, this.ticksKnocked);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeNBT(NBTTagCompound nbt) {
|
||||
this.knockedDown = nbt.getBoolean(KEY_KNOCKED_DOWN);
|
||||
this.reviveTimeLeft = nbt.getInteger(KEY_REVIVE_TIME_LEFT);
|
||||
this.ticksKnocked = nbt.getInteger(KEY_TICKS_KNOCKED);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ru.octol1ttle.knockdowns.common.mixins;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsUtils;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Mixin(EntityLivingBase.class)
|
||||
public abstract class EntityLivingBaseMixin extends Entity {
|
||||
public EntityLivingBaseMixin(World worldIn) {
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
@Inject(method = "checkTotemDeathProtection", at = @At("RETURN"))
|
||||
public void onTotemActivation(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (cir.getReturnValue() && ((Object) this) instanceof EntityPlayerMP) {
|
||||
EntityPlayerMP player = (EntityPlayerMP) (Object) this;
|
||||
IKnockdownsPlayerData data = IKnockdownsPlayerData.get(player);
|
||||
if (data.isKnockedDown()) {
|
||||
KnockdownsUtils.resetKnockedState(player, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ru.octol1ttle.knockdowns.common.mixins;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
@Mixin(EntityPlayer.class)
|
||||
public class EntityPlayerMixin {
|
||||
@ModifyReturnValue(method = "shouldHeal", at = @At("RETURN"))
|
||||
private boolean dontHealIfKnockedDown(boolean original) {
|
||||
if (((Object) this) instanceof EntityPlayer) {
|
||||
EntityPlayer player = (EntityPlayer) (Object) this;
|
||||
if (IKnockdownsPlayerData.get(player).isKnockedDown()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return original;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package ru.octol1ttle.knockdowns.common.network;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
import ru.octol1ttle.knockdowns.common.KnockdownsMod;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerKnockedDownS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizePlayerDataS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
|
||||
|
||||
public class KnockdownsNetwork {
|
||||
private static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(Tags.MOD_ID);
|
||||
private static int packetId = 0;
|
||||
|
||||
public static void registerPackets() {
|
||||
INSTANCE.registerMessage(KnockdownsServerPacketHandler.Callout.class, PlayerCalloutC2SPacket.class, packetId++, Side.SERVER);
|
||||
INSTANCE.registerMessage(KnockdownsServerPacketHandler.CancelRevive.class, CancelReviveC2SPacket.class, packetId++, Side.SERVER);
|
||||
|
||||
IMessageHandler<IMessage, IMessage> clientProxyHandler = (message, ctx) -> KnockdownsMod.clientProxy.handleMessage(message);
|
||||
INSTANCE.registerMessage(clientProxyHandler, PlayerCalloutS2CPacket.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, PlayerKnockedDownS2CPacket.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, SynchronizePlayerDataS2CPacket.KnockedDown.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, SynchronizePlayerDataS2CPacket.ReviveTimeLeft.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, SynchronizePlayerDataS2CPacket.Full.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, SynchronizeReviversS2CPacket.Add.class, packetId++, Side.CLIENT);
|
||||
INSTANCE.registerMessage(clientProxyHandler, SynchronizeReviversS2CPacket.Remove.class, packetId++, Side.CLIENT);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void sendToServer(IMessage message) {
|
||||
INSTANCE.sendToServer(message);
|
||||
}
|
||||
|
||||
public static void sendToAll(IMessage message) {
|
||||
INSTANCE.sendToAll(message);
|
||||
}
|
||||
|
||||
public static void sendToDimension(IMessage message, MessageContext context) {
|
||||
INSTANCE.sendToDimension(message, context.getServerHandler().player.dimension);
|
||||
}
|
||||
|
||||
public static void sendToTrackingAndSelf(IMessage message, EntityPlayerMP player) {
|
||||
sendToPlayer(message, player);
|
||||
sendToTracking(message, player);
|
||||
}
|
||||
|
||||
public static void sendToMultiple(IMessage message, List<EntityPlayer> players, EntityPlayerMP player) {
|
||||
sendToPlayer(message, player);
|
||||
for (EntityPlayer listed : players) {
|
||||
sendToPlayer(message, (EntityPlayerMP) listed);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendToTracking(IMessage message, Entity entity) {
|
||||
INSTANCE.sendToAllTracking(message, entity);
|
||||
}
|
||||
|
||||
public static void sendToPlayer(IMessage message, EntityPlayerMP player) {
|
||||
INSTANCE.sendTo(message, player);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package ru.octol1ttle.knockdowns.common.network;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||
import ru.octol1ttle.knockdowns.common.data.IKnockdownsPlayerData;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.CancelReviveC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.c2s.PlayerCalloutC2SPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.PlayerCalloutS2CPacket;
|
||||
import ru.octol1ttle.knockdowns.common.network.packets.s2c.SynchronizeReviversS2CPacket;
|
||||
|
||||
public class KnockdownsServerPacketHandler {
|
||||
public static class Callout implements IMessageHandler<PlayerCalloutC2SPacket, IMessage> {
|
||||
@Override
|
||||
public IMessage onMessage(PlayerCalloutC2SPacket message, MessageContext ctx) {
|
||||
KnockdownsNetwork.sendToDimension(
|
||||
new PlayerCalloutS2CPacket(
|
||||
ctx.getServerHandler().player.getEntityId(),
|
||||
ctx.getServerHandler().player.getPositionEyes(1).add(0, 1, 0),
|
||||
message.type
|
||||
),
|
||||
ctx
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CancelRevive implements IMessageHandler<CancelReviveC2SPacket, IMessage> {
|
||||
@Override
|
||||
public IMessage onMessage(CancelReviveC2SPacket message, MessageContext ctx) {
|
||||
EntityPlayerMP player = ctx.getServerHandler().player;
|
||||
for (EntityPlayer knocked : player.world.playerEntities) {
|
||||
List<EntityPlayer> revivers = IKnockdownsPlayerData.get(knocked).getRevivers();
|
||||
if (revivers.contains(player)) {
|
||||
revivers.remove(player);
|
||||
KnockdownsNetwork.sendToMultiple(
|
||||
new SynchronizeReviversS2CPacket.Remove(knocked.getEntityId(), player.getEntityId()),
|
||||
revivers,
|
||||
(EntityPlayerMP) knocked
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.c2s;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public class CancelReviveC2SPacket implements IMessage {
|
||||
public CancelReviveC2SPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.c2s;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
|
||||
|
||||
public class PlayerCalloutC2SPacket implements IMessage {
|
||||
public PlayerCalloutC2SPacket() {
|
||||
}
|
||||
|
||||
public CalloutType type;
|
||||
public PlayerCalloutC2SPacket(CalloutType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeByte(this.type.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.type = CalloutType.byId(buf.readByte());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import ru.octol1ttle.knockdowns.common.communication.CalloutType;
|
||||
|
||||
public class PlayerCalloutS2CPacket implements IMessage {
|
||||
public PlayerCalloutS2CPacket() {
|
||||
}
|
||||
|
||||
public int playerId;
|
||||
public Vec3d position;
|
||||
public CalloutType type;
|
||||
|
||||
public PlayerCalloutS2CPacket(int playerId, Vec3d position, CalloutType type) {
|
||||
this.playerId = playerId;
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.playerId);
|
||||
buf.writeDouble(this.position.x);
|
||||
buf.writeDouble(this.position.y);
|
||||
buf.writeDouble(this.position.z);
|
||||
buf.writeByte(this.type.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.playerId = buf.readInt();
|
||||
this.position = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
||||
this.type = CalloutType.byId(buf.readByte());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public class PlayerKnockedDownS2CPacket implements IMessage {
|
||||
public PlayerKnockedDownS2CPacket() {
|
||||
}
|
||||
|
||||
public int playerId;
|
||||
public int dimensionId;
|
||||
public Vec3d position;
|
||||
|
||||
public PlayerKnockedDownS2CPacket(int playerId, int dimensionId, Vec3d position) {
|
||||
this.playerId = playerId;
|
||||
this.dimensionId = dimensionId;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.playerId);
|
||||
buf.writeInt(this.dimensionId);
|
||||
buf.writeDouble(this.position.x);
|
||||
buf.writeDouble(this.position.y);
|
||||
buf.writeDouble(this.position.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.playerId = buf.readInt();
|
||||
this.dimensionId = buf.readInt();
|
||||
this.position = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public class SynchronizePlayerDataS2CPacket {
|
||||
public static class KnockedDown implements IMessage {
|
||||
public KnockedDown() {
|
||||
}
|
||||
|
||||
public int playerId;
|
||||
public boolean knockedDown;
|
||||
|
||||
public KnockedDown(int playerId, boolean knockedDown) {
|
||||
this.playerId = playerId;
|
||||
this.knockedDown = knockedDown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.playerId);
|
||||
buf.writeBoolean(this.knockedDown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.playerId = buf.readInt();
|
||||
this.knockedDown = buf.readBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReviveTimeLeft implements IMessage {
|
||||
public ReviveTimeLeft() {
|
||||
}
|
||||
|
||||
public int playerId;
|
||||
public int reviveTimeLeft;
|
||||
|
||||
public ReviveTimeLeft(int playerId, int reviveTimeLeft) {
|
||||
this.playerId = playerId;
|
||||
this.reviveTimeLeft = reviveTimeLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.playerId);
|
||||
buf.writeInt(this.reviveTimeLeft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.playerId = buf.readInt();
|
||||
this.reviveTimeLeft = buf.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Full implements IMessage {
|
||||
public Full() {
|
||||
}
|
||||
|
||||
public int playerId;
|
||||
public boolean knockedDown;
|
||||
public int reviveTimeLeft;
|
||||
|
||||
public Full(int playerId, boolean knockedDown, int reviveTimeLeft) {
|
||||
this.playerId = playerId;
|
||||
this.knockedDown = knockedDown;
|
||||
this.reviveTimeLeft = reviveTimeLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.playerId);
|
||||
buf.writeBoolean(this.knockedDown);
|
||||
buf.writeInt(this.reviveTimeLeft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.playerId = buf.readInt();
|
||||
this.knockedDown = buf.readBoolean();
|
||||
this.reviveTimeLeft = buf.readInt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package ru.octol1ttle.knockdowns.common.network.packets.s2c;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
|
||||
public class SynchronizeReviversS2CPacket {
|
||||
public static class Add implements IMessage {
|
||||
public Add() {
|
||||
}
|
||||
|
||||
public int knockedId;
|
||||
public int reviverId;
|
||||
|
||||
public Add(int knockedId, int reviverId) {
|
||||
this.knockedId = knockedId;
|
||||
this.reviverId = reviverId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.knockedId);
|
||||
buf.writeInt(this.reviverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.knockedId = buf.readInt();
|
||||
this.reviverId = buf.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Remove implements IMessage {
|
||||
public Remove() {
|
||||
}
|
||||
|
||||
public int knockedId;
|
||||
public int reviverId;
|
||||
|
||||
public Remove(int knockedId, int reviverId) {
|
||||
this.knockedId = knockedId;
|
||||
this.reviverId = reviverId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf) {
|
||||
buf.writeInt(this.knockedId);
|
||||
buf.writeInt(this.reviverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf) {
|
||||
this.knockedId = buf.readInt();
|
||||
this.reviverId = buf.readInt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package ru.octol1ttle.knockdowns.common.registry;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundEvent;
|
||||
import ru.octol1ttle.knockdowns.Tags;
|
||||
|
||||
public class KnockdownsSoundEvents {
|
||||
public static final SoundEvent CALLOUT;
|
||||
public static final SoundEvent KNOCKED_DOWN;
|
||||
static {
|
||||
ResourceLocation callout = new ResourceLocation(Tags.MOD_ID, "callout");
|
||||
CALLOUT = new SoundEvent(callout).setRegistryName(callout);
|
||||
|
||||
ResourceLocation knockedDown = new ResourceLocation(Tags.MOD_ID, "knocked_down");
|
||||
KNOCKED_DOWN = new SoundEvent(knockedDown).setRegistryName(knockedDown);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ru.octol1ttle.knockdowns.common.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UniqueOnlyList<T> extends ArrayList<T> {
|
||||
@Override
|
||||
public void add(int index, T element) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(T t) {
|
||||
if (this.contains(t)) {
|
||||
return false;
|
||||
}
|
||||
return super.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T set(int index, T element) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
65
src/main/resources/assets/knockdowns/lang/en_us.lang
Normal file
65
src/main/resources/assets/knockdowns/lang/en_us.lang
Normal file
|
@ -0,0 +1,65 @@
|
|||
knockdowns.key.category=Knockdowns
|
||||
knockdowns.key.callout.danger=Call out "Danger!"
|
||||
knockdowns.key.callout.booyah=Call out "Booyah!"
|
||||
knockdowns.key.callout.this_way_help=Call out "This way!" ("Help!" when knocked down)
|
||||
knockdowns.key.callout.ouch=Call out "Ouch..."
|
||||
|
||||
knockdowns.callout.danger=Danger!
|
||||
knockdowns.callout.booyah=Booyah!
|
||||
knockdowns.callout.this_way=This way!
|
||||
knockdowns.callout.ouch=Ouch...
|
||||
knockdowns.callout.help=Help!
|
||||
|
||||
knockdowns.subtitles.callout=Player calls out
|
||||
knockdowns.subtitles.knocked_down=Player knocked down
|
||||
|
||||
knockdown.fell.accident.ladder=%1$s was knocked down by falling off a ladder
|
||||
knockdown.fell.accident.vines=%1$s was knocked down by falling off some vines
|
||||
knockdown.fell.accident.water=%1$s was knocked down by falling out of the water
|
||||
knockdown.fell.accident.generic=%1$s was knocked down by a fall
|
||||
knockdown.fell.killer=%1$s was doomed to get knocked down
|
||||
knockdown.fell.assist=%1$s was doomed to get knocked down by %2$s
|
||||
knockdown.fell.assist.item=%1$s was doomed to get knocked down by %2$s using %3$s
|
||||
knockdown.fell.finish=%1$s fell too far and was knocked down by %2$s
|
||||
knockdown.fell.finish.item=%1$s fell too far and was knocked down by %2$s using %3$s
|
||||
|
||||
knockdown.attack.lightningBolt=%1$s was knocked down by lightning
|
||||
knockdown.attack.inFire=%1$s was knocked down by the fire below
|
||||
knockdown.attack.inFire.player=%1$s was knocked down by the fire below whilst fighting %2$s
|
||||
knockdown.attack.onFire=%1$s was knocked down by fire
|
||||
knockdown.attack.onFire.player=%1$s was knocked down by fire whilst fighting %2$s
|
||||
knockdown.attack.lava=%1$s was knocked down by lava
|
||||
knockdown.attack.lava.player=%1$s was knocked down by lava to escape %2$s
|
||||
knockdown.attack.hotFloor=%1$s was knocked down by the floor
|
||||
knockdown.attack.hotFloor.player=%1$s was knocked down by the floor due to %2$s
|
||||
knockdown.attack.inWall=%1$s was knocked down by a wall
|
||||
knockdown.attack.cramming=%1$s was knocked down by social anxiety
|
||||
knockdown.attack.drown=%1$s was knocked down by lack of air
|
||||
knockdown.attack.drown.player=%1$s was knocked down by lack of air whilst trying to escape %2$s
|
||||
knockdown.attack.starve=%1$s was knocked down by hunger
|
||||
knockdown.attack.cactus=%1$s was knocked down by a cactus
|
||||
knockdown.attack.cactus.player=%1$s was knocked down by a cactus whilst trying to escape %2$s
|
||||
knockdown.attack.generic=%1$s was knocked down
|
||||
knockdown.attack.explosion=%1$s was knocked down by an explosion
|
||||
knockdown.attack.explosion.player=%1$s was knocked down by an explosion due to %2$s
|
||||
knockdown.attack.magic=%1$s was knocked down by magic
|
||||
knockdown.attack.wither=%1$s was knocked down by withering
|
||||
knockdown.attack.anvil=%1$s was knocked down by a falling anvil
|
||||
knockdown.attack.fallingBlock=%1$s was knocked down by a falling block
|
||||
knockdown.attack.mob=%1$s was knocked down by %2$s
|
||||
knockdown.attack.player=%1$s was knocked down by %2$s
|
||||
knockdown.attack.player.item=%1$s was knocked down by %2$s using %3$s
|
||||
knockdown.attack.arrow=%1$s was knocked down by an arrow shot by %2$s
|
||||
knockdown.attack.arrow.item=%1$s was knocked down by an arrow shot by %2$s using %3$s
|
||||
knockdown.attack.fireball=%1$s was knocked down by a fireball shot by %2$s
|
||||
knockdown.attack.fireball.item=%1$s was knocked down by a fireball shot by %2$s using %3$s
|
||||
knockdown.attack.thrown=%1$s was knocked down after being pummeled by %2$s
|
||||
knockdown.attack.thrown.item=%1$s was knocked down after being pummeled by %2$s using %3$s
|
||||
knockdown.attack.indirectMagic=%1$s was knocked down by %2$s using magic
|
||||
knockdown.attack.indirectMagic.item=%1$s was knocked down by %2$s using %3$s
|
||||
knockdown.attack.thorns=%1$s was knocked down trying to hurt %2$s
|
||||
knockdown.attack.fall=%1$s was knocked down by the ground below
|
||||
knockdown.attack.outOfWorld=%1$s was knocked down by the void
|
||||
knockdown.attack.dragonBreath=%1$s was knocked down by dragon breath
|
||||
knockdown.attack.flyIntoWall=%1$s was knocked down by physics
|
||||
knockdown.attack.fireworks=%1$s was knocked down by a firework
|
64
src/main/resources/assets/knockdowns/lang/ru_ru.lang
Normal file
64
src/main/resources/assets/knockdowns/lang/ru_ru.lang
Normal file
|
@ -0,0 +1,64 @@
|
|||
knockdowns.key.category=Knockdowns
|
||||
knockdowns.key.callout.danger="Опасность!"
|
||||
knockdowns.key.callout.booyah="Йо-хо!"
|
||||
knockdowns.key.callout.this_way_help="Сюда!" ("SOS!" когда тяжело ранен)
|
||||
knockdowns.key.callout.ouch="Непруха!"
|
||||
|
||||
knockdowns.callout.danger=Опасность!
|
||||
knockdowns.callout.booyah=Йо-хо!
|
||||
knockdowns.callout.this_way=Сюда!
|
||||
knockdowns.callout.ouch=Непруха!
|
||||
knockdowns.callout.help=SOS!
|
||||
|
||||
knockdowns.subtitles.callout=Игрок зовёт союзников
|
||||
knockdowns.subtitles.knocked_down=Игрок тяжело ранен
|
||||
|
||||
knockdown.attack.anvil=%1$s тяжело ранен упавшей наковальней
|
||||
knockdown.attack.arrow=%1$s тяжело ранен стрелой %2$s
|
||||
knockdown.attack.arrow.item=%1$s тяжело ранен стрелой %2$s с помощью %3$s
|
||||
knockdown.attack.cactus=%1$s исколот до тяжелого ранения
|
||||
knockdown.attack.cactus.player=%1$s тяжело ранен кактусом, спасаясь от %2$s
|
||||
knockdown.attack.cramming=%1$s расплющен до тяжелого ранения
|
||||
knockdown.attack.dragonBreath=%1$s тяжело ранен в драконьем дыхании
|
||||
knockdown.attack.drown=%1$s тяжело ранен от нехватки воздуха
|
||||
knockdown.attack.drown.player=%1$s тяжело ранен от нехватки воздуха, спасаясь от %2$s
|
||||
knockdown.attack.explosion=%1$s тяжело ранен взрывом
|
||||
knockdown.attack.explosion.player=%1$s был тяжело ранен взрывом %2$s
|
||||
knockdown.attack.fall=%1$s разбился до тяжелого ранения
|
||||
knockdown.attack.fallingBlock=%1$s тяжело ранен упавшим блоком
|
||||
knockdown.attack.fireball=%1$s тяжело ранен файерболом %2$s
|
||||
knockdown.attack.fireball.item=%1$s тяжело ранен файерболом %2$s с помощью %3$s
|
||||
knockdown.attack.fireworks=%1$s с треском тяжело ранен
|
||||
knockdown.attack.flyIntoWall=%1$s преобразовал кинетическую энергию в тяжелое ранение
|
||||
knockdown.attack.generic=%1$s тяжело ранен
|
||||
knockdown.attack.hotFloor=%1$s тяжело ранен, обнаружив под ногами лаву
|
||||
knockdown.attack.hotFloor.player=%1$s зашёл в опасную зону тяжелого ранения из-за %2$s
|
||||
knockdown.attack.inFire=%1$s сгорел до тяжелого ранения
|
||||
knockdown.attack.inFire.player=%1$s тяжело ранен в огне, борясь с %2$s
|
||||
knockdown.attack.inWall=%1$s погребён до тяжелого ранения
|
||||
knockdown.attack.indirectMagic=%1$s был тяжело ранен %2$s с помощью магии
|
||||
knockdown.attack.indirectMagic.item=%1$s был тяжело ранен %2$s с помощью %3$s
|
||||
knockdown.attack.lava=%1$s решил получить тяжелое ранение в лаве
|
||||
knockdown.attack.lava.player=%1$s получил тяжелое ранение от лавы, убегая от %2$s
|
||||
knockdown.attack.lightningBolt=%1$s был тяжело ранен поражением молнией
|
||||
knockdown.attack.magic=%1$s был тяжело ранен магией
|
||||
knockdown.attack.mob=%1$s был тяжело ранен %2$s
|
||||
knockdown.attack.onFire=%1$s сгорел до тяжелого ранения
|
||||
knockdown.attack.onFire.player=%1$s был сожжён до тяжелого ранения, пока боролся с %2$s
|
||||
knockdown.attack.outOfWorld=%1$s тяжело ранен отсутствием земли под собой
|
||||
knockdown.attack.player=%1$s был тяжело ранен %2$s
|
||||
knockdown.attack.player.item=%1$s был тяжело ранен %2$s с помощью %3$s
|
||||
knockdown.attack.starve=%1$s тяжело ранен от голода
|
||||
knockdown.attack.thorns=%1$s был тяжело ранен, пытаясь навредить %2$s
|
||||
knockdown.attack.thrown=%1$s был избит до тяжелого ранения %2$s
|
||||
knockdown.attack.thrown.item=%1$s был избит до тяжелого ранения %2$s с помощью %3$s
|
||||
knockdown.attack.wither=%1$s тяжело ранен иссушением
|
||||
knockdown.fell.accident.generic=%1$s разбился до тяжелого ранения
|
||||
knockdown.fell.accident.ladder=%1$s свалился с лестницы и был тяжело ранен
|
||||
knockdown.fell.accident.vines=%1$s сорвался с лианы и был тяжело ранен
|
||||
knockdown.fell.accident.water=%1$s выпал из воды и был тяжело ранен
|
||||
knockdown.fell.assist=%1$s свалился и был тяжело ранен благодаря %2$s
|
||||
knockdown.fell.assist.item=%1$s был обречён на тяжелое ранение %2$s с помощью %3$s
|
||||
knockdown.fell.finish=%1$s упал с высоты и был тяжело ранен %2$s
|
||||
knockdown.fell.finish.item=%1$s упал с высоты и был тяжело ранен %2$s с помощью %3$s
|
||||
knockdown.fell.killer=%1$s был обречён на тяжелое ранение
|
18
src/main/resources/assets/knockdowns/sounds.json
Executable file
18
src/main/resources/assets/knockdowns/sounds.json
Executable file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"callout": {
|
||||
"subtitle": "knockdowns.subtitles.callout",
|
||||
"sounds": [
|
||||
{
|
||||
"name": "knockdowns:callout"
|
||||
}
|
||||
]
|
||||
},
|
||||
"knocked_down": {
|
||||
"subtitle": "knockdowns.subtitles.knocked_down",
|
||||
"sounds": [
|
||||
{
|
||||
"name": "knockdowns:knocked_down"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
BIN
src/main/resources/assets/knockdowns/sounds/callout.ogg
Normal file
BIN
src/main/resources/assets/knockdowns/sounds/callout.ogg
Normal file
Binary file not shown.
BIN
src/main/resources/assets/knockdowns/sounds/knocked_down.ogg
Executable file
BIN
src/main/resources/assets/knockdowns/sounds/knocked_down.ogg
Executable file
Binary file not shown.
BIN
src/main/resources/assets/knockdowns/textures/gui/down_arrow.png
Normal file
BIN
src/main/resources/assets/knockdowns/textures/gui/down_arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
BIN
src/main/resources/assets/knockdowns/textures/gui/knocked_icon.png
Executable file
BIN
src/main/resources/assets/knockdowns/textures/gui/knocked_icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 172 B |
BIN
src/main/resources/assets/knockdowns/textures/gui/left_arrow.png
Normal file
BIN
src/main/resources/assets/knockdowns/textures/gui/left_arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
BIN
src/main/resources/assets/knockdowns/textures/gui/up_arrow.png
Normal file
BIN
src/main/resources/assets/knockdowns/textures/gui/up_arrow.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -1,16 +1,12 @@
|
|||
[
|
||||
{
|
||||
"modid": "examplemod",
|
||||
"name": "Example Mod",
|
||||
"description": "Example placeholder mod.",
|
||||
"version": "${version}",
|
||||
"mcversion": "${mcversion}",
|
||||
"url": "",
|
||||
"updateUrl": "",
|
||||
"authorList": ["CleanroomMC"],
|
||||
"credits": "Authors of this project",
|
||||
"logoFile": "",
|
||||
"screenshots": [],
|
||||
"dependencies": []
|
||||
}
|
||||
]
|
||||
[{
|
||||
"modid": "${mod_id}",
|
||||
"name": "${mod_name}",
|
||||
"version": "${mod_version}",
|
||||
"mcversion": "1.12.2",
|
||||
"description": "${mod_description}",
|
||||
"authorList": ${mod_authors},
|
||||
"credits": "${mod_credits}",
|
||||
"url": "${mod_url}",
|
||||
"updateJSON": "${mod_update_json}",
|
||||
"logoFile": "${mod_logo_path}"
|
||||
}]
|
11
src/main/resources/mixins.knockdowns.json
Normal file
11
src/main/resources/mixins.knockdowns.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"package": "ru.octol1ttle.knockdowns.common.mixins",
|
||||
"required": true,
|
||||
"refmap": "${mixin_refmap}",
|
||||
"target": "@env(DEFAULT)",
|
||||
"minVersion": "0.8.5",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [ "EntityLivingBaseMixin", "EntityPlayerMixin" ],
|
||||
"server": [],
|
||||
"client": []
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"pack": {
|
||||
"description": "examplemod resources",
|
||||
"pack_format": 3,
|
||||
"_comment": "A pack_format of 3 should be used starting with Minecraft 1.11. All resources, including language files, should be lowercase (eg: en_us.lang). A pack_format of 2 will load your mod resources with LegacyV2Adapter, which requires language files to have uppercase letters (eg: en_US.lang)."
|
||||
}
|
||||
}
|
||||
"pack": {
|
||||
"description": "${mod_name} Resources",
|
||||
"pack_format": 3
|
||||
}
|
||||
}
|
3
tags.properties
Normal file
3
tags.properties
Normal file
|
@ -0,0 +1,3 @@
|
|||
VERSION = ${mod_version}
|
||||
MOD_ID = ${mod_id}
|
||||
MOD_NAME = ${mod_name}
|
Loading…
Add table
Reference in a new issue