From 9eb5dc61cbe48a2fca1bbe859955e21966f5ea99 Mon Sep 17 00:00:00 2001 From: Leaf Date: Sun, 30 Jan 2022 11:52:21 +1300 Subject: [PATCH] First real commit --- .gitattributes | 5 + .gitignore | 25 + LICENSE | 17 + build.gradle | 264 +++++++++ gradle.properties | 11 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 +++++++ gradlew.bat | 89 +++ src/main/generated/.cache/cache | 19 + .../generated/assets/soulhome/lang/en_us.json | 31 ++ .../assets/soulhome/models/item/guide.json | 6 + .../assets/soulhome/models/item/soulkey.json | 6 + .../soulhome/advancements/main/blank.json | 31 ++ .../main/entered_soul_dimension.json | 36 ++ .../advancements/main/obtained_guide.json | 38 ++ .../advancements/main/obtained_soul_key.json | 41 ++ .../data/soulhome/advancements/main/root.json | 29 + .../recipes/soulhome.items/guide.json | 32 ++ .../recipes/soulhome.items/soulkey.json | 32 ++ .../en_us/categories/category.basics.json | 7 + .../categories/category.multiblocks.json | 7 + .../entries/category.basics/entry.guide.json | 19 + .../entries/category.basics/entry.soul.json | 17 + .../category.basics/entry.soul_key.json | 28 + .../category.basics/entry.welcome.json | 30 ++ .../category.multiblocks/entry.blank.json | 17 + .../data/soulhome/recipes/guide.json | 14 + .../data/soulhome/recipes/soulkey.json | 19 + src/main/java/leaf/soulhome/SoulHome.java | 91 ++++ .../java/leaf/soulhome/blocks/BaseBlock.java | 23 + .../java/leaf/soulhome/blocks/TileBlock.java | 15 + .../renderers/EmptyWeatherRenderer.java | 23 + .../leaf/soulhome/commands/SoulCommand.java | 29 + .../commands/permissions/PermissionEnum.java | 42 ++ .../permissions/PermissionManager.java | 18 + .../commands/subcommands/ModCommand.java | 28 + .../commands/subcommands/SoulHomeCommand.java | 58 ++ .../commands/subcommands/TestCommand.java | 45 ++ .../soulhome/compat/curios/CuriosCompat.java | 73 +++ .../leaf/soulhome/compat/curios/KeyCurio.java | 28 + .../compat/curios/SoulHomeCurios.java | 41 ++ .../soulhome/compat/hwyla/HwylaCompat.java | 19 + .../leaf/soulhome/compat/jei/JEICompat.java | 72 +++ .../compat/patchouli/PatchouliCompat.java | 25 + .../leaf/soulhome/constants/Constants.java | 31 ++ .../java/leaf/soulhome/datagen/DataGen.java | 56 ++ .../datagen/advancements/AdvancementGen.java | 86 +++ .../advancements/MainAdvancements.java | 127 +++++ .../datagen/blocks/BlockModelsGen.java | 53 ++ .../soulhome/datagen/items/ItemModelsGen.java | 61 +++ .../soulhome/datagen/language/EngLangGen.java | 133 +++++ .../datagen/loottables/BlockLootTableGen.java | 28 + .../datagen/loottables/LootTableGen.java | 43 ++ .../soulhome/datagen/patchouli/BookStuff.java | 508 ++++++++++++++++++ .../datagen/patchouli/PatchouliGen.java | 172 ++++++ .../patchouli/categories/PatchouliBasics.java | 71 +++ .../categories/PatchouliMultiblocks.java | 43 ++ .../soulhome/datagen/recipe/RecipeGen.java | 119 ++++ .../dimensions/SoulChunkGenerator.java | 132 +++++ .../dimensions/SoulDimensionRenderInfo.java | 42 ++ .../leaf/soulhome/handlers/CommonEvents.java | 54 ++ .../java/leaf/soulhome/items/BaseItem.java | 25 + .../java/leaf/soulhome/items/GuideItem.java | 95 ++++ .../soulhome/items/SoulHomeItemGroups.java | 22 + .../java/leaf/soulhome/items/SoulKeyItem.java | 158 ++++++ .../soulhome/mixin/EffectInstanceMixin.java | 14 + .../java/leaf/soulhome/mixin/EntityMixin.java | 16 + .../soulhome/network/ClientPacketHandler.java | 34 ++ .../java/leaf/soulhome/network/Network.java | 104 ++++ .../network/SyncDimensionListMessage.java | 54 ++ .../leaf/soulhome/properties/PropTypes.java | 31 ++ .../leaf/soulhome/registry/BiomeRegistry.java | 28 + .../soulhome/registry/BlocksRegistry.java | 37 ++ .../soulhome/registry/ClientRegistry.java | 27 + .../registry/DataSerializersRegistry.java | 40 ++ .../soulhome/registry/DimensionRegistry.java | 166 ++++++ .../leaf/soulhome/registry/ItemsRegistry.java | 34 ++ .../soulhome/utils/CompoundNBTHelper.java | 259 +++++++++ .../leaf/soulhome/utils/DimensionHelper.java | 163 ++++++ .../leaf/soulhome/utils/EntityHelper.java | 48 ++ .../java/leaf/soulhome/utils/ListHelper.java | 19 + .../java/leaf/soulhome/utils/LogHelper.java | 60 +++ .../java/leaf/soulhome/utils/MathUtils.java | 50 ++ .../leaf/soulhome/utils/PlayerHelper.java | 29 + .../utils/ResourceLocationHelper.java | 18 + .../leaf/soulhome/utils/StringHelper.java | 19 + .../leaf/soulhome/utils/TeleportHelper.java | 131 +++++ .../java/leaf/soulhome/utils/TextHelper.java | 63 +++ .../resources/META-INF/accesstransformer.cfg | 4 + src/main/resources/META-INF/mods.toml | 61 +++ .../soulhome/textures/block/test_block.png | Bin 0 -> 3087 bytes .../assets/soulhome/textures/item/guide.png | Bin 0 -> 4205 bytes .../assets/soulhome/textures/item/soulkey.png | Bin 0 -> 3071 bytes .../soulhome/dimension_type/soulhome.json | 19 + .../soulhome/patchouli_books/guide/book.json | 25 + .../soulhome/worldgen/biome/soulhome.json | 27 + .../worldgen/noise_settings/soulhome.json | 49 ++ src/main/resources/pack.mcmeta | 7 + src/main/resources/soulhome.mixins.json | 16 + 100 files changed, 5401 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/generated/.cache/cache create mode 100644 src/main/generated/assets/soulhome/lang/en_us.json create mode 100644 src/main/generated/assets/soulhome/models/item/guide.json create mode 100644 src/main/generated/assets/soulhome/models/item/soulkey.json create mode 100644 src/main/generated/data/soulhome/advancements/main/blank.json create mode 100644 src/main/generated/data/soulhome/advancements/main/entered_soul_dimension.json create mode 100644 src/main/generated/data/soulhome/advancements/main/obtained_guide.json create mode 100644 src/main/generated/data/soulhome/advancements/main/obtained_soul_key.json create mode 100644 src/main/generated/data/soulhome/advancements/main/root.json create mode 100644 src/main/generated/data/soulhome/advancements/recipes/soulhome.items/guide.json create mode 100644 src/main/generated/data/soulhome/advancements/recipes/soulhome.items/soulkey.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.basics.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.multiblocks.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.guide.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul_key.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.welcome.json create mode 100644 src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.multiblocks/entry.blank.json create mode 100644 src/main/generated/data/soulhome/recipes/guide.json create mode 100644 src/main/generated/data/soulhome/recipes/soulkey.json create mode 100644 src/main/java/leaf/soulhome/SoulHome.java create mode 100644 src/main/java/leaf/soulhome/blocks/BaseBlock.java create mode 100644 src/main/java/leaf/soulhome/blocks/TileBlock.java create mode 100644 src/main/java/leaf/soulhome/client/renderers/EmptyWeatherRenderer.java create mode 100644 src/main/java/leaf/soulhome/commands/SoulCommand.java create mode 100644 src/main/java/leaf/soulhome/commands/permissions/PermissionEnum.java create mode 100644 src/main/java/leaf/soulhome/commands/permissions/PermissionManager.java create mode 100644 src/main/java/leaf/soulhome/commands/subcommands/ModCommand.java create mode 100644 src/main/java/leaf/soulhome/commands/subcommands/SoulHomeCommand.java create mode 100644 src/main/java/leaf/soulhome/commands/subcommands/TestCommand.java create mode 100644 src/main/java/leaf/soulhome/compat/curios/CuriosCompat.java create mode 100644 src/main/java/leaf/soulhome/compat/curios/KeyCurio.java create mode 100644 src/main/java/leaf/soulhome/compat/curios/SoulHomeCurios.java create mode 100644 src/main/java/leaf/soulhome/compat/hwyla/HwylaCompat.java create mode 100644 src/main/java/leaf/soulhome/compat/jei/JEICompat.java create mode 100644 src/main/java/leaf/soulhome/compat/patchouli/PatchouliCompat.java create mode 100644 src/main/java/leaf/soulhome/constants/Constants.java create mode 100644 src/main/java/leaf/soulhome/datagen/DataGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/advancements/AdvancementGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/advancements/MainAdvancements.java create mode 100644 src/main/java/leaf/soulhome/datagen/blocks/BlockModelsGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/items/ItemModelsGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/language/EngLangGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/loottables/BlockLootTableGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/loottables/LootTableGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/patchouli/BookStuff.java create mode 100644 src/main/java/leaf/soulhome/datagen/patchouli/PatchouliGen.java create mode 100644 src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliBasics.java create mode 100644 src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliMultiblocks.java create mode 100644 src/main/java/leaf/soulhome/datagen/recipe/RecipeGen.java create mode 100644 src/main/java/leaf/soulhome/dimensions/SoulChunkGenerator.java create mode 100644 src/main/java/leaf/soulhome/dimensions/SoulDimensionRenderInfo.java create mode 100644 src/main/java/leaf/soulhome/handlers/CommonEvents.java create mode 100644 src/main/java/leaf/soulhome/items/BaseItem.java create mode 100644 src/main/java/leaf/soulhome/items/GuideItem.java create mode 100644 src/main/java/leaf/soulhome/items/SoulHomeItemGroups.java create mode 100644 src/main/java/leaf/soulhome/items/SoulKeyItem.java create mode 100644 src/main/java/leaf/soulhome/mixin/EffectInstanceMixin.java create mode 100644 src/main/java/leaf/soulhome/mixin/EntityMixin.java create mode 100644 src/main/java/leaf/soulhome/network/ClientPacketHandler.java create mode 100644 src/main/java/leaf/soulhome/network/Network.java create mode 100644 src/main/java/leaf/soulhome/network/SyncDimensionListMessage.java create mode 100644 src/main/java/leaf/soulhome/properties/PropTypes.java create mode 100644 src/main/java/leaf/soulhome/registry/BiomeRegistry.java create mode 100644 src/main/java/leaf/soulhome/registry/BlocksRegistry.java create mode 100644 src/main/java/leaf/soulhome/registry/ClientRegistry.java create mode 100644 src/main/java/leaf/soulhome/registry/DataSerializersRegistry.java create mode 100644 src/main/java/leaf/soulhome/registry/DimensionRegistry.java create mode 100644 src/main/java/leaf/soulhome/registry/ItemsRegistry.java create mode 100644 src/main/java/leaf/soulhome/utils/CompoundNBTHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/DimensionHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/EntityHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/ListHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/LogHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/MathUtils.java create mode 100644 src/main/java/leaf/soulhome/utils/PlayerHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/ResourceLocationHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/StringHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/TeleportHelper.java create mode 100644 src/main/java/leaf/soulhome/utils/TextHelper.java create mode 100644 src/main/resources/META-INF/accesstransformer.cfg create mode 100644 src/main/resources/META-INF/mods.toml create mode 100644 src/main/resources/assets/soulhome/textures/block/test_block.png create mode 100644 src/main/resources/assets/soulhome/textures/item/guide.png create mode 100644 src/main/resources/assets/soulhome/textures/item/soulkey.png create mode 100644 src/main/resources/data/soulhome/dimension_type/soulhome.json create mode 100644 src/main/resources/data/soulhome/patchouli_books/guide/book.json create mode 100644 src/main/resources/data/soulhome/worldgen/biome/soulhome.json create mode 100644 src/main/resources/data/soulhome/worldgen/noise_settings/soulhome.json create mode 100644 src/main/resources/pack.mcmeta create mode 100644 src/main/resources/soulhome.mixins.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f811f6a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Disable autocrlf on generated files, they always generate with LF +# Add any extra files or paths here to make git stop saying they +# are changed when only line endings change. +src/generated/**/.cache/cache text eol=lf +src/generated/**/*.json text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12f8644 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# eclipse +bin +*.launch +.settings +.metadata +.classpath +.project + +# idea +out +*.ipr +*.iws +*.iml +.idea + +# gradle +build +.gradle + +# other +eclipse +run + +# Files from Forge MDK +forge*changelog.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f944437 --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ +All Rights Reserved + +Copyright (c) 2022 LeafReynolds + +Permission is hereby granted, free of charge, to any person: + +- to use the mod +- to distribute the mod as part of a modpack +- to publish images or videos depicting the mod +- to copy and modify the code (e.g. submitting pull requests) +- to learn from portions of the code and adapt for use in other projects +- to derive from or depend on this code as a dependency (e.g. for mod compatibility) + +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. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..dab03a3 --- /dev/null +++ b/build.gradle @@ -0,0 +1,264 @@ +buildscript { + repositories { + maven { url = 'https://maven.minecraftforge.net' } + maven { url = 'https://repo.spongepowered.org/repository/maven-public' } + mavenCentral() + } + dependencies { + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true + classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT' + } +} +apply plugin: 'net.minecraftforge.gradle' +// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. +apply plugin: 'org.spongepowered.mixin' +apply plugin: 'eclipse' +apply plugin: 'maven-publish' + + +ext.configFile = file('gradle.properties') +ext.config = parseConfig(configFile) + +version = "${forge_version}-b${build_number}" +group = 'leaf.soulhome' // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = "${project.jar_name}" + +java.toolchain.languageVersion = JavaLanguageVersion.of(8) // Mojang ships Java 8 to end users, so your mod should target Java 8. +println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) + +// Include resources generated by data generators. +sourceSets { + main.resources.srcDirs += 'src/main/generated' +} + +minecraft { + // The mappings can be changed at any time, and must be in the following format. + // Channel: Version: + // snapshot YYYYMMDD Snapshot are built nightly. + // stable # Stables are built at the discretion of the MCP team. + // official MCVersion Official field/method names from Mojang mapping files + // + // You must be aware of the Mojang license when using the 'official' mappings. + // See more information here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md + // + // Use non-default mappings at your own risk. they may not always work. + // Simply re-run your setup task after changing the mappings to update your workspace. + mappings channel: 'official', version: '1.16.5' + // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. + + // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + + workingDirectory project.file('run') + arg "-mixin.config=soulhome.mixins.json" + + // Recommended logging data for a userdev environment + // The markers can be changed as needed. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + property 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + property 'forge.logging.console.level', 'debug' + + mods { + soulhome { + source sourceSets.main + } + } + } + + server { + properties 'mixin.env.disableRefMap': 'true' + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + // The markers can be changed as needed. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + property 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + property 'forge.logging.console.level', 'debug' + + mods { + soulhome { + source sourceSets.main + } + } + } + + data { + properties 'mixin.env.disableRefMap': 'true' + workingDirectory project.file('run') + + // Recommended logging data for a userdev environment + // The markers can be changed as needed. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + property 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + property 'forge.logging.console.level', 'debug' + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + args '--mod', 'soulhome', '--all', '--output', file('src/main/generated/'), '--existing', file('src/main/resources/') + + mods { + soulhome { + source sourceSets.main + } + } + } + + } + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') +} + +mixin { + add sourceSets.main, "soulhome.refmap.json" +} + +repositories { + maven { + // location of the maven that hosts JEI files + url "https://dvs1.progwml6.com/files/maven/" + } + maven { + //used for patchouli + url "https://maven.blamejared.com/" + } + maven { + //curio + url = "https://maven.theillusivec4.top/" + } + maven { + //HWYLA + url "https://maven.tehnut.info" + } + maven { + url "https://www.cursemaven.com" + content { + includeGroup "curse.maven" + } + } + mavenCentral() +} + +dependencies { + // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed + // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. + // The userdev artifact is a special name and will get all sorts of transformations applied to it. + minecraft "net.minecraftforge:forge:${forge_version}" + + annotationProcessor 'org.spongepowered:mixin:0.8.2:processor' + + compileOnly fg.deobf("mezz.jei:jei-${jei_version}:api") + runtimeOnly fg.deobf("mezz.jei:jei-${jei_version}") + + compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}:api") + runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:${curios_version}") + + compileOnly fg.deobf("vazkii.patchouli:Patchouli:${patchouli_version}:api") + runtimeOnly fg.deobf("vazkii.patchouli:Patchouli:${patchouli_version}") + + compileOnly fg.deobf("mcp.mobius.waila:Hwyla:${hwyla_version}:api") + runtimeOnly fg.deobf("mcp.mobius.waila:Hwyla:${hwyla_version}") + + //modname-modid:fileid? + implementation fg.deobf("curse.maven:appleskin-248787:3035787") + implementation fg.deobf("curse.maven:journeymap-32274:3397059") + //implementation fg.deobf("curse.maven:ctm-267602:2642375") +} + +// Example for how to get properties into the manifest for reading by the runtime.. +jar { + manifest { + attributes([ + "Specification-Title" : "soulhome", + "Specification-Vendor" : "soulhome", + "Specification-Version" : "1", // We are version 1 of ourselves + "Implementation-Title" : project.name, + "Implementation-Version" : "${version}", + "Implementation-Vendor" : "soulhome", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + "MixinConfigs" : "soulhome.mixins.json" + + ]) + } +} + +processResources { + // Exclude datagenerator .cache directory + exclude '.cache' + + filesMatching('data/soulhome/patchouli_books/guide/book.json') { + filter { + it.replaceAll("buildNumber", config.build_number) + } + } +} + +task incrementBuildNumber { + doFirst { + config.build_number = (config.build_number.toString().toInteger()) + 1 + configFile.withWriter { + config.toProperties().store(it, "") + } + } +} + +def parseConfig(File config) { + if(config.exists()){ + config.withReader { + def prop = new Properties() + prop.load(it) + return (new ConfigSlurper().parse(prop)) + } + } else { + return null + } +} + +// Example configuration to allow publishing using the maven-publish task +// This is the preferred method to reobfuscate your jar file +jar.finalizedBy('reobfJar') +// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing +//publish.dependsOn('reobfJar') + +publishing { + publications { + mavenJava(MavenPublication) { + artifact jar + } + } + repositories { + maven { + url "file:///${project.projectDir}/mcmodsrepo" + } + } +} + +// Prevent Mixin annotation processor from getting into IDEA's annotation processor settings +if (System.getProperty("idea.sync.active") == "true") { + afterEvaluate { + tasks.withType(JavaCompile).all { + it.options.annotationProcessorPath = files() + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..2d5b293 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,11 @@ +# +#Sat Jan 29 12:10:33 NZDT 2022 +forge_version=1.16.5-36.2.20 +org.gradle.daemon=false +jar_name=SoulHome-Mod +jei_version=1.16.4\:7.6.0.62 +hwyla_version=1.10.11-B78_1.16.2 +org.gradle.jvmargs=-Xmx8G +curios_version=1.16.5-4.0.6.8 +build_number=1 +patchouli_version=1.16.4-51 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..05679dc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/generated/.cache/cache b/src/main/generated/.cache/cache new file mode 100644 index 0000000..967363c --- /dev/null +++ b/src/main/generated/.cache/cache @@ -0,0 +1,19 @@ +6c2c626b8c81aaec7fd91bb62401b2fe79088789 assets/soulhome/lang/en_us.json +d9bb2941a407fb2be1631319b0360c1d501b682d assets/soulhome/models/item/guide.json +24ca7242da31f8e5d3a3511153a130555be28b00 assets/soulhome/models/item/soulkey.json +b5cf06caa15b475d51c28dbc82329ed25d7421ec data/soulhome/advancements/main/blank.json +67ddaa3bdc951351455ef0a0be80f8c61505fc0a data/soulhome/advancements/main/entered_soul_dimension.json +6a1deda33f5645561e3f4864d634c77394151d64 data/soulhome/advancements/main/obtained_guide.json +dd2d7bfa397b9aabee365c10a1c160ef51fc6b73 data/soulhome/advancements/main/obtained_soul_key.json +02102a978b4fb09e65bdabe13a882a20869802fe data/soulhome/advancements/main/root.json +8306ffa3cd445cafd67f9faea3f77a7f50dfeadc data/soulhome/advancements/recipes/soulhome.items/guide.json +fa7f558e5ad53bc4db0fae792d6e54e7a2615749 data/soulhome/advancements/recipes/soulhome.items/soulkey.json +c46f503b62dde6e0527a28bdad78cb6fbbe82d6c data/soulhome/patchouli_books/guide/en_us/categories/category.basics.json +90d07ba3c5302020fe2dacd816296633967a39b6 data/soulhome/patchouli_books/guide/en_us/categories/category.multiblocks.json +15a38c7962199e70d532bd825f3896884eb3b55a data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.guide.json +de0340acfd039aacc0202965dabfc67670d0fbe7 data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul.json +2f8075b36db22fcd3d92a7417feec39b0cf42cb5 data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul_key.json +c5228a2e128b4b8aa48d5ff6a7f8da99da2fd142 data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.welcome.json +33aa2b35124ae3110f7edb4e75a48880d60dec31 data/soulhome/patchouli_books/guide/en_us/entries/category.multiblocks/entry.blank.json +952e53b33bdad64cbfbad1710234cd8c5f5f2f41 data/soulhome/recipes/guide.json +17fcafa9fe68413745aa1237895f5918f6cb0412 data/soulhome/recipes/soulkey.json diff --git a/src/main/generated/assets/soulhome/lang/en_us.json b/src/main/generated/assets/soulhome/lang/en_us.json new file mode 100644 index 0000000..bacff5f --- /dev/null +++ b/src/main/generated/assets/soulhome/lang/en_us.json @@ -0,0 +1,31 @@ +{ + "advancements.soulhome.blank.description": "blank", + "advancements.soulhome.blank.title": "blank", + "advancements.soulhome.entered_soul_dimension.description": "Hey wait, why is it so empty in here?", + "advancements.soulhome.entered_soul_dimension.title": "Enlightened", + "advancements.soulhome.main.description": "Welcome to SoulHome. The way to your inner soul.", + "advancements.soulhome.main.title": "SoulHome", + "advancements.soulhome.obtained_guide.description": "", + "advancements.soulhome.obtained_guide.title": "Well Read", + "advancements.soulhome.obtained_soul_key.description": "By using this key, you can transport yourself and nearby entities to your soul.", + "advancements.soulhome.obtained_soul_key.title": "Obtained SoulKey", + "biome.soulhome.soulhome": "SoulHome", + "category.basics": "Basics", + "category.multiblock": "Multiblocks", + "entry.guide": "Guide", + "entry.soul": "Soul", + "entry.soul_key": "SoulKey", + "entry.welcome": "Welcome", + "item.soulhome.guide": "Guide", + "item.soulhome.soulkey": "Soulkey", + "itemGroup.soulhome.items": "SoulHome Items", + "key.soulhome.soul.charge": "Charge Key To Transport", + "keys.soulhome.main": "SoulHome", + "soulhome.landing": "They say the soul is infinite. They didn't say how empty it was. Fortunately, we can fill it.", + "soulhome:soulhome": "SoulHome", + "tooltip.item.info.control": "\u00A77Hold \u00A78[\u00A7eControl\u00A78]", + "tooltip.item.info.shift": "\u00A77Hold \u00A78[\u00A7eShift\u00A78]", + "tooltip.item.info.shift_control": "\u00A77Hold \u00A78[\u00A7eShift\u00A78] \u00A77and \u00A78[\u00A7eControl\u00A78]", + "tooltip.item.soulhome.guide": "If patchouli is installed, this is your guide to the mod", + "tooltip.item.soulhome.soulkey": "The key to accessing your own soul. Use for the full duration and it will take you there. As well as anything else nearby." +} \ No newline at end of file diff --git a/src/main/generated/assets/soulhome/models/item/guide.json b/src/main/generated/assets/soulhome/models/item/guide.json new file mode 100644 index 0000000..a2bb352 --- /dev/null +++ b/src/main/generated/assets/soulhome/models/item/guide.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "soulhome:item/guide" + } +} \ No newline at end of file diff --git a/src/main/generated/assets/soulhome/models/item/soulkey.json b/src/main/generated/assets/soulhome/models/item/soulkey.json new file mode 100644 index 0000000..62f305b --- /dev/null +++ b/src/main/generated/assets/soulhome/models/item/soulkey.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "soulhome:item/soulkey" + } +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/main/blank.json b/src/main/generated/data/soulhome/advancements/main/blank.json new file mode 100644 index 0000000..53d06b6 --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/main/blank.json @@ -0,0 +1,31 @@ +{ + "parent": "soulhome:main/obtained_guide", + "display": { + "icon": { + "item": "soulhome:guide" + }, + "title": { + "translate": "advancements.soulhome.blank.title" + }, + "description": { + "translate": "advancements.soulhome.blank.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": true + }, + "rewards": { + "experience": 5 + }, + "criteria": { + "impossible": { + "trigger": "minecraft:impossible" + } + }, + "requirements": [ + [ + "impossible" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/main/entered_soul_dimension.json b/src/main/generated/data/soulhome/advancements/main/entered_soul_dimension.json new file mode 100644 index 0000000..925c98a --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/main/entered_soul_dimension.json @@ -0,0 +1,36 @@ +{ + "parent": "soulhome:main/obtained_soul_key", + "display": { + "icon": { + "item": "soulhome:guide" + }, + "title": { + "translate": "advancements.soulhome.entered_soul_dimension.title" + }, + "description": { + "translate": "advancements.soulhome.entered_soul_dimension.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "rewards": { + "experience": 5 + }, + "criteria": { + "entered_soul": { + "trigger": "minecraft:location", + "conditions": { + "location": { + "biome": "soulhome:soulhome" + } + } + } + }, + "requirements": [ + [ + "entered_soul" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/main/obtained_guide.json b/src/main/generated/data/soulhome/advancements/main/obtained_guide.json new file mode 100644 index 0000000..983724c --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/main/obtained_guide.json @@ -0,0 +1,38 @@ +{ + "parent": "soulhome:main/obtained_soul_key", + "display": { + "icon": { + "item": "soulhome:guide" + }, + "title": { + "translate": "advancements.soulhome.obtained_guide.title" + }, + "description": { + "translate": "advancements.soulhome.obtained_guide.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "rewards": { + "experience": 5 + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "soulhome:guide" + } + ] + } + } + }, + "requirements": [ + [ + "has_item" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/main/obtained_soul_key.json b/src/main/generated/data/soulhome/advancements/main/obtained_soul_key.json new file mode 100644 index 0000000..59930ca --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/main/obtained_soul_key.json @@ -0,0 +1,41 @@ +{ + "parent": "soulhome:main/root", + "display": { + "icon": { + "item": "soulhome:guide" + }, + "title": { + "translate": "advancements.soulhome.obtained_soul_key.title" + }, + "description": { + "translate": "advancements.soulhome.obtained_soul_key.description" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "rewards": { + "experience": 50, + "loot": [ + "soulhome:guide" + ] + }, + "criteria": { + "has_item": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "soulhome:soulkey" + } + ] + } + } + }, + "requirements": [ + [ + "has_item" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/main/root.json b/src/main/generated/data/soulhome/advancements/main/root.json new file mode 100644 index 0000000..36903cd --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/main/root.json @@ -0,0 +1,29 @@ +{ + "display": { + "icon": { + "item": "soulhome:soulkey" + }, + "title": { + "translate": "advancements.soulhome.main.title" + }, + "description": { + "translate": "advancements.soulhome.main.description" + }, + "frame": "task", + "show_toast": false, + "announce_to_chat": false, + "hidden": false, + "background": "minecraft:textures/gui/advancements/backgrounds/stone.png" + }, + "criteria": { + "tick": { + "trigger": "minecraft:tick", + "conditions": {} + } + }, + "requirements": [ + [ + "tick" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/guide.json b/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/guide.json new file mode 100644 index 0000000..bbfd5e0 --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/guide.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "soulhome:guide" + ] + }, + "criteria": { + "has_soul_key": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "soulhome:soulkey" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "soulhome:guide" + } + } + }, + "requirements": [ + [ + "has_soul_key", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/soulkey.json b/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/soulkey.json new file mode 100644 index 0000000..de4c1ac --- /dev/null +++ b/src/main/generated/data/soulhome/advancements/recipes/soulhome.items/soulkey.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "soulhome:soulkey" + ] + }, + "criteria": { + "has_material": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:ender_pearl" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "soulhome:soulkey" + } + } + }, + "requirements": [ + [ + "has_material", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.basics.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.basics.json new file mode 100644 index 0000000..c8965b0 --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.basics.json @@ -0,0 +1,7 @@ +{ + "name": "category.basics", + "description": "An introduction to the mod, serving as a tutorial.", + "icon": "soulhome:guide", + "sortnum": 0, + "secret": false +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.multiblocks.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.multiblocks.json new file mode 100644 index 0000000..0f15e05 --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/categories/category.multiblocks.json @@ -0,0 +1,7 @@ +{ + "name": "category.multiblocks", + "description": "Structures you can build within your soul that will grant you power.", + "icon": "soulhome:guide", + "sortnum": 0, + "secret": false +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.guide.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.guide.json new file mode 100644 index 0000000..9aed594 --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.guide.json @@ -0,0 +1,19 @@ +{ + "name": "entry.guide", + "category": "category.basics", + "icon": "soulhome:guide", + "pages": [ + { + "type": "text", + "text": "Your guide to everything in the mod! There isn\u0027t much at the moment, but future versions will allow you to build structures within your soul in order to gain benefits when you\u0027re outside of it. " + }, + { + "type": "text", + "text": "For example, building a farm in a specific multiblock structure might mean that you get more saturation out of each thing that you eat. Or maybe you\u0027d build an armoury in order to gain a buff to toughness. At this point in time though, there\u0027s only the $(l:soulhome:category.basics/entry.soul_key)$(item)SoulKey$(0) $(/l)" + } + ], + "priority": false, + "secret": false, + "read_by_default": false, + "sortnum": 2 +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul.json new file mode 100644 index 0000000..e31970b --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul.json @@ -0,0 +1,17 @@ +{ + "name": "entry.soul", + "category": "category.basics", + "icon": "soulhome:guide", + "pages": [ + { + "type": "text", + "text": "Woo! Welcome to your soul. $(p)Kinda empty, isn\u0027t it? I wonder what that says about you, huh. $(p)For now, that\u0027s all there is to the mod. Look out for future updates that will let you build multiblock structures to give yourself buffs." + } + ], + "advancement": "soulhome:main/obtained_soul_key", + "priority": false, + "secret": false, + "read_by_default": false, + "sortnum": 4, + "turnin": "soulhome:main/entered_soul_dimension" +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul_key.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul_key.json new file mode 100644 index 0000000..9bedde4 --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.soul_key.json @@ -0,0 +1,28 @@ +{ + "name": "entry.soul_key", + "category": "category.basics", + "icon": "soulhome:guide", + "pages": [ + { + "type": "text", + "text": "Hey, well done! You\u0027ve managed to obtain the centerpiece to this mod. Now you just need to enter your soul by holding [$(k:use)]. You\u0027ll see some particles start appearing at your feet, an every widening circle showing the area of effect." + }, + { + "type": "text", + "text": "If you hold [$(k:use)] for the full duration, you and all other entities within the circle will be transported to your soul. This is how you\u0027d bring friends and livestock into your soul." + }, + { + "type": "crafting", + "text": "All you need is a little bit of iron and an ender pearl", + "title": "SoulKey", + "recipe": "soulhome:soulkey", + "recipe2": "" + } + ], + "advancement": "soulhome:main/obtained_soul_key", + "priority": false, + "secret": false, + "read_by_default": false, + "sortnum": 3, + "turnin": "soulhome:main/obtained_soul_key" +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.welcome.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.welcome.json new file mode 100644 index 0000000..7b6110f --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.basics/entry.welcome.json @@ -0,0 +1,30 @@ +{ + "name": "entry.welcome", + "category": "category.basics", + "icon": "soulhome:guide", + "pages": [ + { + "type": "text", + "text": "Hey, thanks for checking out this mod! It came about from my love of the $(item)Spectre Key$(0) from $(thing)RandomThings$(0). $(p)The idea of having a safe area in a different dimension that you could go to and come back from was very appealing. " + }, + { + "type": "text", + "text": "This current iteration of SoulHome is very basic, with a low barrier of entry on purpose. $(p)There\u0027s some exciting stuff coming in future versions though, so I hope you\u0027ll stick around!" + }, + { + "type": "text", + "text": "If you still aren\u0027t sure where to start, this book (as well as advancements) should help you find what the next step is. The book is set up to unlock new entries with every advancement completed.$(p) $(p)For now though, here\u0027s a tip:" + }, + { + "type": "crafting", + "text": "All you need is a little bit of iron and an ender pearl", + "title": "SoulKey", + "recipe": "soulhome:soulkey", + "recipe2": "" + } + ], + "priority": true, + "secret": false, + "read_by_default": false, + "sortnum": -10 +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.multiblocks/entry.blank.json b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.multiblocks/entry.blank.json new file mode 100644 index 0000000..bfd9ea2 --- /dev/null +++ b/src/main/generated/data/soulhome/patchouli_books/guide/en_us/entries/category.multiblocks/entry.blank.json @@ -0,0 +1,17 @@ +{ + "name": "entry.blank", + "category": "category.multiblocks", + "icon": "soulhome:guide", + "pages": [ + { + "type": "text", + "text": "Blank Blank Blank! ", + "title": "soulhome:guide" + } + ], + "advancement": "soulhome:main/blank", + "priority": true, + "secret": false, + "read_by_default": false, + "sortnum": -10 +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/recipes/guide.json b/src/main/generated/data/soulhome/recipes/guide.json new file mode 100644 index 0000000..067ca8c --- /dev/null +++ b/src/main/generated/data/soulhome/recipes/guide.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "minecraft:book" + }, + { + "item": "soulhome:soulkey" + } + ], + "result": { + "item": "soulhome:guide" + } +} \ No newline at end of file diff --git a/src/main/generated/data/soulhome/recipes/soulkey.json b/src/main/generated/data/soulhome/recipes/soulkey.json new file mode 100644 index 0000000..b68aa15 --- /dev/null +++ b/src/main/generated/data/soulhome/recipes/soulkey.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "I ", + "II ", + " E" + ], + "key": { + "I": { + "item": "minecraft:iron_ingot" + }, + "E": { + "item": "minecraft:ender_pearl" + } + }, + "result": { + "item": "soulhome:soulkey" + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/SoulHome.java b/src/main/java/leaf/soulhome/SoulHome.java new file mode 100644 index 0000000..96afde2 --- /dev/null +++ b/src/main/java/leaf/soulhome/SoulHome.java @@ -0,0 +1,91 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome; + +import leaf.soulhome.compat.curios.CuriosCompat; +import leaf.soulhome.compat.patchouli.PatchouliCompat; +import leaf.soulhome.network.Network; +import leaf.soulhome.registry.*; +import leaf.soulhome.utils.LogHelper; +import leaf.soulhome.utils.ResourceLocationHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +// The value here should match an entry in the META-INF/mods.toml file +@Mod(SoulHome.MODID) +public class SoulHome +{ + public static final String MODID = "soulhome"; + public static final ResourceLocation SOULHOME_LOC = ResourceLocationHelper.prefix(SoulHome.MODID); + + public SoulHome() + { + LogHelper.info("Registering Soulhome related mcgubbins!"); + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + + modBus.addListener(this::commonSetup); + modBus.addListener(this::loadComplete); + + //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(ClientSetup::init)); + //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(ClientSetup::registerIconTextures)); + //DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> FMLJavaModLoadingContext.get().getModEventBus().addListener(ClientSetup::retrieveRegisteredIconSprites)); + + + MinecraftForge.EVENT_BUS.register(this); + + //Register our deferred registries + BlocksRegistry.BLOCKS.register(modBus); + ItemsRegistry.ITEMS.register(modBus); + //EffectsRegistry.EFFECTS.register(modBus); + //LootModifierRegistry.LOOT_MODIFIERS.register(modBus); + //AttributesRegistry.ATTRIBUTES.register(modBus); + //EntityRegistry.ENTITIES.register(modBus); + + //FeatureRegistry.FEATURES.register(modBus); + //RecipeRegistry.SPECIAL_RECIPES.register(modBus); + + //AdvancementTriggerRegistry.init(); + + Network.init(); + + // init cross mod compatibility stuff, if relevant + CuriosCompat.init(); + PatchouliCompat.init(); + } + + private void commonSetup(FMLCommonSetupEvent event) + { + event.enqueueWork(() -> + { + //FeatureRegistry.registerConfiguredFeatures(); + //EntityRegistry.PrepareEntityAttributes(); + + BiomeRegistry.registerBiomeKeys(); + DimensionRegistry.registerNoiseSettings(); + DimensionRegistry.registerChunkGenerators(); + }); + + //Entity Caps + + DataSerializersRegistry.register(); + + LogHelper.info("Common setup complete!"); + } + + private void loadComplete(FMLLoadCompleteEvent event) + { + event.enqueueWork(() -> + { + //ColorHandler.init(); + }); + } + +} diff --git a/src/main/java/leaf/soulhome/blocks/BaseBlock.java b/src/main/java/leaf/soulhome/blocks/BaseBlock.java new file mode 100644 index 0000000..85f5ae0 --- /dev/null +++ b/src/main/java/leaf/soulhome/blocks/BaseBlock.java @@ -0,0 +1,23 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.blocks; + +import net.minecraft.block.Block; +import net.minecraft.block.SoundType; + +public class BaseBlock extends Block +{ + + public BaseBlock(Properties properties, SoundType sound, float hardness, float resistance) + { + super(properties.sound(sound).strength(hardness, resistance)); + } + + public BaseBlock(Properties properties) + { + super(properties); + + } +} diff --git a/src/main/java/leaf/soulhome/blocks/TileBlock.java b/src/main/java/leaf/soulhome/blocks/TileBlock.java new file mode 100644 index 0000000..e33e39a --- /dev/null +++ b/src/main/java/leaf/soulhome/blocks/TileBlock.java @@ -0,0 +1,15 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.blocks; + +import net.minecraft.block.Block; + +public class TileBlock extends Block +{ + public TileBlock(Properties properties) + { + super(properties); + } +} diff --git a/src/main/java/leaf/soulhome/client/renderers/EmptyWeatherRenderer.java b/src/main/java/leaf/soulhome/client/renderers/EmptyWeatherRenderer.java new file mode 100644 index 0000000..fa39592 --- /dev/null +++ b/src/main/java/leaf/soulhome/client/renderers/EmptyWeatherRenderer.java @@ -0,0 +1,23 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.client.renderers; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.world.ClientWorld; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.IWeatherRenderHandler; + +@OnlyIn(Dist.CLIENT) +public class EmptyWeatherRenderer implements IWeatherRenderHandler +{ + @Override + public void render(int ticks, float partialTicks, ClientWorld world, Minecraft mc, LightTexture lightmapIn, double xIn, double yIn, double zIn) + { + //no weather in the soul at this stage. + //todo random soul based events that cause weather? could be interesting. + } +} diff --git a/src/main/java/leaf/soulhome/commands/SoulCommand.java b/src/main/java/leaf/soulhome/commands/SoulCommand.java new file mode 100644 index 0000000..5f74f70 --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/SoulCommand.java @@ -0,0 +1,29 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + * + * Special thank you to the New Tardis Mod team. + * That mod taught me how to correctly add new commands, among other things! + * https://tardis-mod.com/books/home/page/links#bkmrk-source + */ + +package leaf.soulhome.commands; + +import com.mojang.brigadier.CommandDispatcher; +import leaf.soulhome.SoulHome; +import leaf.soulhome.commands.subcommands.SoulHomeCommand; +import leaf.soulhome.commands.subcommands.TestCommand; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; + + +public class SoulCommand +{ + + public static void register(CommandDispatcher dispatcher) + { + dispatcher.register(Commands.literal(SoulHome.MODID) + .then(TestCommand.register(dispatcher)) + .then(SoulHomeCommand.register(dispatcher)) + ); + } +} diff --git a/src/main/java/leaf/soulhome/commands/permissions/PermissionEnum.java b/src/main/java/leaf/soulhome/commands/permissions/PermissionEnum.java new file mode 100644 index 0000000..0a4e777 --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/permissions/PermissionEnum.java @@ -0,0 +1,42 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.commands.permissions; + +import leaf.soulhome.SoulHome; +import net.minecraftforge.server.permission.DefaultPermissionLevel; + +import java.text.MessageFormat; + +public enum PermissionEnum +{ + TEST("test", DefaultPermissionLevel.OP, ""), + HOME("home", DefaultPermissionLevel.OP, ""); + + private final String path; + private final DefaultPermissionLevel level; + private final String description; + + PermissionEnum(String path, DefaultPermissionLevel level, String description) + { + this.path = path; + this.level = level; + this.description = description; + } + + public String getNode() + { + return MessageFormat.format("{0}.command.{1}", SoulHome.MODID, this.path); + } + + public DefaultPermissionLevel getLevel() + { + return level; + } + + public String getDescription() + { + return description; + } +} diff --git a/src/main/java/leaf/soulhome/commands/permissions/PermissionManager.java b/src/main/java/leaf/soulhome/commands/permissions/PermissionManager.java new file mode 100644 index 0000000..450b4c9 --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/permissions/PermissionManager.java @@ -0,0 +1,18 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.commands.permissions; + +import net.minecraftforge.server.permission.PermissionAPI; + +import java.util.Arrays; + +public class PermissionManager +{ + + public static void init() + { + Arrays.stream(PermissionEnum.values()).forEach(perm -> PermissionAPI.registerNode(perm.getNode(), perm.getLevel(), perm.getDescription())); + } +} diff --git a/src/main/java/leaf/soulhome/commands/subcommands/ModCommand.java b/src/main/java/leaf/soulhome/commands/subcommands/ModCommand.java new file mode 100644 index 0000000..8f7d8b1 --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/subcommands/ModCommand.java @@ -0,0 +1,28 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.commands.subcommands; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.CommandSource; + +public abstract class ModCommand implements Command +{ + private int permLevel = 2; + + public ModCommand() + { + } + + public ModCommand(int level) + { + this.permLevel = level; + } + + public boolean canExecute(CommandSource source) throws CommandSyntaxException + { + return source.hasPermission(permLevel); + } +} diff --git a/src/main/java/leaf/soulhome/commands/subcommands/SoulHomeCommand.java b/src/main/java/leaf/soulhome/commands/subcommands/SoulHomeCommand.java new file mode 100644 index 0000000..f1a5a0b --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/subcommands/SoulHomeCommand.java @@ -0,0 +1,58 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.commands.subcommands; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import leaf.soulhome.utils.DimensionHelper; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.server.ServerWorld; + +public class SoulHomeCommand extends ModCommand +{ + + @Override + public int run(CommandContext context) throws CommandSyntaxException + { + return SINGLE_SUCCESS; + } + + private static int testSub(CommandContext context, ServerPlayerEntity player) + { + return testSub(context, player.getLevel()); + } + + private static int testSub(CommandContext context, ServerWorld world) + { + CommandSource source = context.getSource(); + source.sendSuccess(new TranslationTextComponent("command.soulhome.test.sub"), true); + + return SINGLE_SUCCESS; + } + + public static ArgumentBuilder register(CommandDispatcher dispatcher) + { + return Commands.literal("home") + .requires(context -> context.hasPermission(2)) + .then(Commands.literal("sub") + .executes(context -> testSub(context, context.getSource().getPlayerOrException()))) + .executes(context -> teleportToSoul(context, context.getSource().getPlayerOrException())) + ; // end add + } + + private static int teleportToSoul(CommandContext context, ServerPlayerEntity player) + { + DimensionHelper.FlipDimension(player, context.getSource().getServer(), null); + + return Command.SINGLE_SUCCESS; + } + +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/commands/subcommands/TestCommand.java b/src/main/java/leaf/soulhome/commands/subcommands/TestCommand.java new file mode 100644 index 0000000..99ea5e8 --- /dev/null +++ b/src/main/java/leaf/soulhome/commands/subcommands/TestCommand.java @@ -0,0 +1,45 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.commands.subcommands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.server.ServerWorld; + +public class TestCommand extends ModCommand +{ + + private static int testSub(CommandContext context, ServerPlayerEntity player) + { + return testSub(context, player.getLevel()); + } + + private static int testSub(CommandContext context, ServerWorld world) + { + CommandSource source = context.getSource(); + source.sendSuccess(new TranslationTextComponent("command.soulhome.test.sub"), true); + + return SINGLE_SUCCESS; + } + + public static ArgumentBuilder register(CommandDispatcher dispatcher) + { + return Commands.literal("test") + .requires(context -> context.hasPermission(2)).then(Commands.literal("sub").executes(context -> testSub(context, context.getSource().getPlayerOrException()))); // end add + } + + @Override + public int run(CommandContext context) throws CommandSyntaxException + { + return SINGLE_SUCCESS; + } + +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/compat/curios/CuriosCompat.java b/src/main/java/leaf/soulhome/compat/curios/CuriosCompat.java new file mode 100644 index 0000000..4f89aca --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/curios/CuriosCompat.java @@ -0,0 +1,73 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.curios; + +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.InterModComms; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.SlotTypeMessage; +import top.theillusivec4.curios.api.SlotTypePreset; + +public class CuriosCompat +{ + private static boolean curiosModDetected; + + + public static boolean CuriosIsPresent() + { + return curiosModDetected; + } + + public static void init() + { + curiosModDetected = ModList.get().isLoaded("curios"); + + if (!curiosModDetected) + { + return; + } + + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + modBus.addListener(CuriosCompat::onEnqueueIMC); + } + + + private static void onEnqueueIMC(InterModEnqueueEvent event) + { + if (!curiosModDetected) + { + return; + } + + SlotTypePreset[] oneSlot = { + SlotTypePreset.BACK, + SlotTypePreset.BODY, + }; + + for (SlotTypePreset type : oneSlot) + { + InterModComms.sendTo(CuriosApi.MODID, SlotTypeMessage.REGISTER_TYPE, () -> type.getMessageBuilder().build()); + } + + SlotTypePreset[] twoSlot = { + SlotTypePreset.HANDS, + SlotTypePreset.RING, + SlotTypePreset.CHARM, + SlotTypePreset.BRACELET, + SlotTypePreset.NECKLACE, + SlotTypePreset.HEAD, + SlotTypePreset.BELT, + }; + + for (SlotTypePreset type : twoSlot) + { + InterModComms.sendTo(CuriosApi.MODID, SlotTypeMessage.REGISTER_TYPE, () -> type.getMessageBuilder().size(2).build()); + } + + } +} diff --git a/src/main/java/leaf/soulhome/compat/curios/KeyCurio.java b/src/main/java/leaf/soulhome/compat/curios/KeyCurio.java new file mode 100644 index 0000000..06dd01d --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/curios/KeyCurio.java @@ -0,0 +1,28 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.curios; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; +import top.theillusivec4.curios.api.SlotContext; +import top.theillusivec4.curios.api.type.capability.ICurio; + +//Adding extra curio functionality, BUT ONLY if curio mod is installed. +//'ideally' you would extend ICurioItem on the key item itself, but that makes the Curio mod required to be installed, which isn't guaranteed. +public class KeyCurio implements ICurio +{ + + @Override + public void curioTick(String identifier, int index, LivingEntity livingEntity) + { + + } + + @Override + public void onUnequip(SlotContext slotContext, ItemStack newStack) + { + + } +} diff --git a/src/main/java/leaf/soulhome/compat/curios/SoulHomeCurios.java b/src/main/java/leaf/soulhome/compat/curios/SoulHomeCurios.java new file mode 100644 index 0000000..a803024 --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/curios/SoulHomeCurios.java @@ -0,0 +1,41 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.curios; + +import leaf.soulhome.items.SoulKeyItem; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.type.capability.ICurio; + +import java.util.Optional; +import java.util.function.Predicate; + +public class SoulHomeCurios +{ + + public static ICurio createKeyCurioProvider() + { + return new KeyCurio(); + } + + public static Optional> getCurioSoulKey(LivingEntity livingEntity) + { + Predicate keyCurio = stack -> stack.getItem() instanceof SoulKeyItem; + return CuriosApi.getCuriosHelper().findEquippedCurio(keyCurio, livingEntity); + } + + //get the itemstack of the key the player currently has equipped, if any + public static ItemStack getCurioEquippedKeyStack(PlayerEntity player) + { + if (getCurioSoulKey(player).isPresent()) + { + return getCurioSoulKey(player).get().getRight(); + } + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/leaf/soulhome/compat/hwyla/HwylaCompat.java b/src/main/java/leaf/soulhome/compat/hwyla/HwylaCompat.java new file mode 100644 index 0000000..0428267 --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/hwyla/HwylaCompat.java @@ -0,0 +1,19 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.hwyla; + +import mcp.mobius.waila.api.IRegistrar; +import mcp.mobius.waila.api.IWailaPlugin; +import mcp.mobius.waila.api.WailaPlugin; + +@WailaPlugin +public class HwylaCompat implements IWailaPlugin +{ + @Override + public void register(IRegistrar iRegistrar) + { + //iRegistrar.registerComponentProvider(SpiritWebTooltip.INSTANCE, TooltipPosition.BODY, LivingEntity.class); + } +} diff --git a/src/main/java/leaf/soulhome/compat/jei/JEICompat.java b/src/main/java/leaf/soulhome/compat/jei/JEICompat.java new file mode 100644 index 0000000..792bcf2 --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/jei/JEICompat.java @@ -0,0 +1,72 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.jei; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.constants.Constants; +import leaf.soulhome.registry.ItemsRegistry; +import leaf.soulhome.utils.ResourceLocationHelper; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.registration.IGuiHandlerRegistration; +import mezz.jei.api.registration.IRecipeCatalystRegistration; +import mezz.jei.api.registration.IRecipeCategoryRegistration; +import mezz.jei.api.registration.IRecipeRegistration; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +@JeiPlugin +public class JEICompat implements IModPlugin +{ + + public static final ResourceLocation JEI = ResourceLocationHelper.prefix("jei"); + + @Override + public ResourceLocation getPluginUid() + { + return JEI; + } + + @Override + public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) + { + //the ability to right click on your tile entity to see what other items interact with it. + //eg furnace burns fuel, so shows fuel, that kinda thing. + } + + @Override + public void registerCategories(IRecipeCategoryRegistration registration) + { + + } + + @Override + public void registerGuiHandlers(IGuiHandlerRegistration registration) + { + //for tile entities eg furnace furnace + } + + @Override + public void registerRecipes(IRecipeRegistration registration) + { + //for (RegistryObject itemRO : ItemsRegistry.ITEMS.get()) + //reg.addRecipes(TestRecipe.getAllRecipes(world), TestRecipeCategory.NAME); + + addItemInfoPage(registration, ItemsRegistry.SOUL_KEY.get()); + addItemInfoPage(registration, ItemsRegistry.GUIDE.get()); + + } + + private void addItemInfoPage(IRecipeRegistration reg, Item item) + { + reg.addIngredientInfo( + new ItemStack(item), + VanillaTypes.ITEM, + String.format(Constants.StringKeys.SOULHOME_ITEM_TOOLTIP, item.getRegistryName().getPath())); + } + +} diff --git a/src/main/java/leaf/soulhome/compat/patchouli/PatchouliCompat.java b/src/main/java/leaf/soulhome/compat/patchouli/PatchouliCompat.java new file mode 100644 index 0000000..88cc525 --- /dev/null +++ b/src/main/java/leaf/soulhome/compat/patchouli/PatchouliCompat.java @@ -0,0 +1,25 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.compat.patchouli; + +import leaf.soulhome.utils.LogHelper; +import net.minecraftforge.fml.ModList; + +public class PatchouliCompat +{ + private static boolean patchouliModDetected; + + public static boolean PatchouliIsPresent() + { + return patchouliModDetected; + } + + public static void init() + { + patchouliModDetected = ModList.get().isLoaded("patchouli"); + LogHelper.info("Patchouli detected, soulhome can use it's guide item."); + } + +} diff --git a/src/main/java/leaf/soulhome/constants/Constants.java b/src/main/java/leaf/soulhome/constants/Constants.java new file mode 100644 index 0000000..2e08fc1 --- /dev/null +++ b/src/main/java/leaf/soulhome/constants/Constants.java @@ -0,0 +1,31 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.constants; + +public class Constants +{ + public static class StringKeys + { + public static final String KEYS_CATEGORY = "keys.soulhome.main"; + public static final String KEY_SOUL_CHARGE = "key.soulhome.soul.charge"; + + public static final String PATCHOULI_NOT_INSTALLED = "tooltip.soulhome.patchouli.not_installed"; + + public static final String SOULHOME_ITEM_TOOLTIP = "tooltip.item.soulhome.%s"; + + public static final String SHIFT_ITEM_TOOLTIP = "tooltip.item.info.shift"; + public static final String SHIFT_CONTROL_ITEM_TOOLTIP = "tooltip.item.info.shift_control"; + public static final String CONTROL_ITEM_TOOLTIP = "tooltip.item.info.control"; + } + + public static class NBTKeys + { + public static final String LAST_DIMENSION_X = "LAST_DIMENSION_X"; + public static final String LAST_DIMENSION_Y = "LAST_DIMENSION_Y"; + public static final String LAST_DIMENSION_Z = "LAST_DIMENSION_Z"; + public static final String LAST_DIMENSION_MOD_ID = "LAST_DIMENSION_MOD_ID"; + public static final String LAST_DIMENSION_MOD_DIMENSION = "LAST_DIMENSION_MOD_DIMENSION"; + } +} diff --git a/src/main/java/leaf/soulhome/datagen/DataGen.java b/src/main/java/leaf/soulhome/datagen/DataGen.java new file mode 100644 index 0000000..32fc602 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/DataGen.java @@ -0,0 +1,56 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + * Special Thank you to ChampionAsh5357 from the forge project discord! + * They provided a series of tutorials with examples of how to add new sections of data generation + * Generating 20+ different metal related blocks, items, curios etc would have been a nightmare without it. + */ + +package leaf.soulhome.datagen; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import leaf.soulhome.SoulHome; +import leaf.soulhome.datagen.advancements.AdvancementGen; +import leaf.soulhome.datagen.blocks.BlockModelsGen; +import leaf.soulhome.datagen.items.ItemModelsGen; +import leaf.soulhome.datagen.language.EngLangGen; +import leaf.soulhome.datagen.loottables.LootTableGen; +import leaf.soulhome.datagen.patchouli.PatchouliGen; +import leaf.soulhome.datagen.recipe.RecipeGen; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; + +@Mod.EventBusSubscriber(modid = SoulHome.MODID, bus = Bus.MOD) +public class DataGen +{ + + public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + @SubscribeEvent + public static void onDataGen(GatherDataEvent event) + { + DataGenerator generator = event.getGenerator(); + ExistingFileHelper existingFileHelper = event.getExistingFileHelper(); + + generator.addProvider(new EngLangGen(generator)); + + if (!event.includeClient()) + { + return; + } + + generator.addProvider(new AdvancementGen(generator)); + generator.addProvider(new ItemModelsGen(generator, existingFileHelper)); + generator.addProvider(new BlockModelsGen(generator, existingFileHelper)); + generator.addProvider(new LootTableGen(generator)); + generator.addProvider(new RecipeGen(generator)); + + generator.addProvider(new PatchouliGen(generator)); + + } + +} diff --git a/src/main/java/leaf/soulhome/datagen/advancements/AdvancementGen.java b/src/main/java/leaf/soulhome/datagen/advancements/AdvancementGen.java new file mode 100644 index 0000000..35f6736 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/advancements/AdvancementGen.java @@ -0,0 +1,86 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.advancements; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.minecraft.advancements.Advancement; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DirectoryCache; +import net.minecraft.data.IDataProvider; +import net.minecraft.util.ResourceLocation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +public class AdvancementGen implements IDataProvider +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create(); + private final DataGenerator generator; + private final List>> advancements = ImmutableList.of( + new MainAdvancements() + ); + + public AdvancementGen(DataGenerator generatorIn) + { + this.generator = generatorIn; + } + + /** + * Performs this provider's action. + */ + public void run(DirectoryCache cache) throws IOException + { + Path path = this.generator.getOutputFolder(); + Set set = Sets.newHashSet(); + Consumer consumer = (advancement) -> + { + if (!set.add(advancement.getId())) + { + throw new IllegalStateException("Duplicate advancement " + advancement.getId()); + } + else + { + Path path1 = getPath(path, advancement); + + try + { + IDataProvider.save(GSON, cache, advancement.deconstruct().serializeToJson(), path1); + } catch (IOException ioexception) + { + LOGGER.error("Couldn't save advancement {}", path1, ioexception); + } + + } + }; + + for (Consumer> consumer1 : this.advancements) + { + consumer1.accept(consumer); + } + + } + + private static Path getPath(Path pathIn, Advancement advancementIn) + { + return pathIn.resolve("data/soulhome/advancements/" + advancementIn.getId().getPath() + ".json"); + } + + /** + * Gets a name for this provider, to use in logging. + */ + public String getName() + { + return "SoulHome Advancements"; + } +} diff --git a/src/main/java/leaf/soulhome/datagen/advancements/MainAdvancements.java b/src/main/java/leaf/soulhome/datagen/advancements/MainAdvancements.java new file mode 100644 index 0000000..1dfeee3 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/advancements/MainAdvancements.java @@ -0,0 +1,127 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.advancements; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.BiomeRegistry; +import leaf.soulhome.registry.ItemsRegistry; +import leaf.soulhome.utils.ResourceLocationHelper; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.advancements.FrameType; +import net.minecraft.advancements.criterion.*; +import net.minecraft.command.FunctionObject; +import net.minecraft.item.Items; +import net.minecraft.tags.ItemTags; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; + +import java.util.function.Consumer; + +public class MainAdvancements implements Consumer> +{ + public MainAdvancements() + { + } + + public void accept(Consumer advancementConsumer) + { + final String tabName = "main"; + + final String titleFormat = "advancements.soulhome.%s.title"; + final String descriptionFormat = "advancements.soulhome.%s.description"; + final String achievementPathFormat = "soulhome:%s/%s"; + + Advancement root = Advancement.Builder.advancement() + .display(ItemsRegistry.SOUL_KEY.get(), + new TranslationTextComponent(String.format(titleFormat, tabName)), + new TranslationTextComponent(String.format(descriptionFormat, tabName)), + new ResourceLocation("textures/gui/advancements/backgrounds/stone.png"), + FrameType.TASK, + false,//showToast + false,//announceChat + false)//hidden + .addCriterion("tick", new TickTrigger.Instance(EntityPredicate.AndPredicate.ANY)) + .save(advancementConsumer, String.format(achievementPathFormat, tabName, "root")); + + + final String obtainedSoulKey = "obtained_soul_key"; + Advancement advancement1 = Advancement.Builder.advancement() + .parent(root) + .display( + ItemsRegistry.GUIDE.get(), + new TranslationTextComponent(String.format(titleFormat, obtainedSoulKey)), + new TranslationTextComponent(String.format(descriptionFormat, obtainedSoulKey)), + (ResourceLocation)null, + FrameType.TASK, + true, //showToast + true, //announce + false)//hidden + .addCriterion( + "has_item", + InventoryChangeTrigger.Instance.hasItems(ItemsRegistry.SOUL_KEY.get())) + .rewards(new AdvancementRewards(50, new ResourceLocation[]{new ResourceLocation("soulhome:guide")}, new ResourceLocation[0], FunctionObject.CacheableFunction.NONE)) + .save(advancementConsumer, String.format(achievementPathFormat, tabName, obtainedSoulKey)); + + + + final String obtainedGuide = "obtained_guide"; + Advancement advancement2 = Advancement.Builder.advancement() + .parent(advancement1) + .display( + ItemsRegistry.GUIDE.get(), + new TranslationTextComponent(String.format(titleFormat, obtainedGuide)), + new TranslationTextComponent(String.format(descriptionFormat, obtainedGuide)), + (ResourceLocation)null, + FrameType.TASK, + true, //showToast + true, //announce + false)//hidden + .addCriterion( + "has_item", + InventoryChangeTrigger.Instance.hasItems(ItemsRegistry.GUIDE.get())) + .rewards(new AdvancementRewards(5, new ResourceLocation[0], new ResourceLocation[0], FunctionObject.CacheableFunction.NONE)) + .save(advancementConsumer, String.format(achievementPathFormat, tabName, obtainedGuide)); + + + final String enteredSoulDimension = "entered_soul_dimension"; + Advancement advancement3 = Advancement.Builder.advancement() + .parent(advancement1) + .display( + ItemsRegistry.GUIDE.get(), + new TranslationTextComponent(String.format(titleFormat, enteredSoulDimension)), + new TranslationTextComponent(String.format(descriptionFormat, enteredSoulDimension)), + (ResourceLocation)null, + FrameType.TASK, + true, //showToast + true, //announce + false)//hidden + .addCriterion("entered_soul", PositionTrigger.Instance.located(LocationPredicate.inBiome(RegistryKey.create(Registry.BIOME_REGISTRY, SoulHome.SOULHOME_LOC)))) + .rewards(new AdvancementRewards(5, new ResourceLocation[0], new ResourceLocation[0], FunctionObject.CacheableFunction.NONE)) + .save(advancementConsumer, String.format(achievementPathFormat, tabName, enteredSoulDimension)); + + final String blank = "blank"; + Advancement advancement4 = Advancement.Builder.advancement() + .parent(advancement2) + .display( + ItemsRegistry.GUIDE.get(), + new TranslationTextComponent(String.format(titleFormat, blank)), + new TranslationTextComponent(String.format(descriptionFormat, blank)), + (ResourceLocation)null, + FrameType.TASK, + true, //showToast + true, //announce + true)//hidden + .addCriterion("impossible", new ImpossibleTrigger.Instance()) + .rewards(new AdvancementRewards(5, new ResourceLocation[0], new ResourceLocation[0], FunctionObject.CacheableFunction.NONE)) + .save(advancementConsumer, String.format(achievementPathFormat, tabName, blank)); + + + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/datagen/blocks/BlockModelsGen.java b/src/main/java/leaf/soulhome/datagen/blocks/BlockModelsGen.java new file mode 100644 index 0000000..140f76b --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/blocks/BlockModelsGen.java @@ -0,0 +1,53 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.blocks; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.BlocksRegistry; +import net.minecraft.block.Block; +import net.minecraft.data.DataGenerator; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.generators.BlockStateProvider; +import net.minecraftforge.client.model.generators.ModelFile; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.fml.RegistryObject; + +import java.util.function.Supplier; + +public class BlockModelsGen extends BlockStateProvider +{ + public BlockModelsGen(DataGenerator generator, ExistingFileHelper existingFileHelper) + { + super(generator, SoulHome.MODID, existingFileHelper); + } + + @Override + protected void registerStatesAndModels() + { + for (RegistryObject itemRegistryObject : BlocksRegistry.BLOCKS.getEntries()) + { + simpleBlock(itemRegistryObject); + } + + } + + public void simpleBlock(Supplier blockSupplier) + { + simpleBlock(blockSupplier.get()); + } + + public String getPath(Supplier blockSupplier) + { + ResourceLocation location = blockSupplier.get().getRegistryName(); + return location.getPath(); + } + + @Override + public void simpleBlock(Block block, ModelFile model) + { + super.simpleBlock(block, model); + this.simpleBlockItem(block, model); + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/datagen/items/ItemModelsGen.java b/src/main/java/leaf/soulhome/datagen/items/ItemModelsGen.java new file mode 100644 index 0000000..6307a18 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/items/ItemModelsGen.java @@ -0,0 +1,61 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.items; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.ItemsRegistry; +import net.minecraft.data.DataGenerator; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.model.generators.ItemModelBuilder; +import net.minecraftforge.client.model.generators.ItemModelProvider; +import net.minecraftforge.client.model.generators.ModelFile; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.fml.RegistryObject; + +import java.util.function.Supplier; + +public class ItemModelsGen extends ItemModelProvider +{ + + public ItemModelsGen(DataGenerator generator, ExistingFileHelper existingFileHelper) + { + super(generator, SoulHome.MODID, existingFileHelper); + } + + @Override + protected void registerModels() + { + for (RegistryObject itemRegistryObject : ItemsRegistry.ITEMS.getEntries()) + { + String path = getPath(itemRegistryObject); + Item item = itemRegistryObject.get(); + + //blocks have their own model rules + if (item instanceof BlockItem) + { + continue; + } + + //else normal item texture rules apply + simpleItem(path, path); + } + + } + + public String getPath(Supplier itemSupplier) + { + ResourceLocation location = itemSupplier.get().getRegistryName(); + return location.getPath(); + } + + public ItemModelBuilder simpleItem(String path, String texturePath) + { + return this.getBuilder(path) + .parent(new ModelFile.UncheckedModelFile("item/generated")) + .texture("layer0", modLoc("item/" + texturePath)); + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/datagen/language/EngLangGen.java b/src/main/java/leaf/soulhome/datagen/language/EngLangGen.java new file mode 100644 index 0000000..fc55026 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/language/EngLangGen.java @@ -0,0 +1,133 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.language; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.constants.Constants; +import leaf.soulhome.items.SoulHomeItemGroups; +import leaf.soulhome.utils.StringHelper; +import net.minecraft.data.DataGenerator; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; +import net.minecraftforge.common.data.LanguageProvider; +import net.minecraftforge.registries.ForgeRegistries; + +public class EngLangGen extends LanguageProvider +{ + private final DataGenerator generator; + + public EngLangGen(DataGenerator gen) + { + super(gen, SoulHome.MODID, "en_us"); + this.generator = gen; + } + + @Override + protected void addTranslations() + { + + //Items and Blocks + for (Item item : ForgeRegistries.ITEMS.getValues()) + { + if (item.getRegistryName().getNamespace().contentEquals(SoulHome.MODID)) + { + final String path = item.getRegistryName().getPath(); + String localisedString = StringHelper.fixCapitalisation(path); + final String tooltipStringKey = String.format(Constants.StringKeys.SOULHOME_ITEM_TOOLTIP, path); + + String tooltipString = ""; + + + //string overrides + switch (localisedString) + { + case "Guide": + //localisedString = "exampleOverride"; + tooltipString = "If patchouli is installed, this is your guide to the mod"; + break; + case "Soulkey": + tooltipString = "The key to accessing your own soul. Use for the full duration and it will take you there. As well as anything else nearby."; + break; + } + + add(tooltipStringKey, tooltipString); + add(item.getDescriptionId(), localisedString); + + + } + } + + //Entities + for (EntityType type : ForgeRegistries.ENTITIES) + { + if (type.getRegistryName().getNamespace().equals(SoulHome.MODID)) + { + add(type.getDescriptionId(), StringHelper.fixCapitalisation(type.getRegistryName().getPath())); + } + } + + //ItemGroups/Tabs + add("itemGroup." + SoulHomeItemGroups.ITEMS.getRecipeFolderName(), "SoulHome Items"); + + //Damage Sources + + //Containers + + //effects + + //Sound Schemes + + //Configs + + //Commands + + + //Tooltips + add(Constants.StringKeys.SHIFT_ITEM_TOOLTIP, "\u00A77Hold \u00A78[\u00A7eShift\u00A78]"); + add(Constants.StringKeys.SHIFT_CONTROL_ITEM_TOOLTIP, "\u00A77Hold \u00A78[\u00A7eShift\u00A78] \u00A77and \u00A78[\u00A7eControl\u00A78]"); + add(Constants.StringKeys.CONTROL_ITEM_TOOLTIP, "\u00A77Hold \u00A78[\u00A7eControl\u00A78]"); + + //Guide book + add("soulhome.landing", "They say the soul is infinite. They didn't say how empty it was. Fortunately, we can fill it."); + + add("category.basics", "Basics"); + add("category.multiblock", "Multiblocks"); + + add("entry.welcome", "Welcome"); + add("entry.soul", "Soul"); + add("entry.soul_key", "SoulKey"); + add("entry.guide", "Guide"); + + + //KeyBindings + add(Constants.StringKeys.KEYS_CATEGORY, "SoulHome"); + add(Constants.StringKeys.KEY_SOUL_CHARGE, "Charge Key To Transport"); + + + //Advancements + + add("advancements.soulhome.main.title", "SoulHome"); + add("advancements.soulhome.main.description", "Welcome to SoulHome. The way to your inner soul."); + + add("advancements.soulhome.obtained_soul_key.title", "Obtained SoulKey"); + add("advancements.soulhome.obtained_soul_key.description", "By using this key, you can transport yourself and nearby entities to your soul."); + + add("advancements.soulhome.entered_soul_dimension.title", "Enlightened"); + add("advancements.soulhome.entered_soul_dimension.description", "Hey wait, why is it so empty in here?"); + + add("advancements.soulhome.obtained_guide.title", "Well Read"); + add("advancements.soulhome.obtained_guide.description", ""); + + add("advancements.soulhome.blank.title", "blank"); + add("advancements.soulhome.blank.description", "blank"); + + //misc + + add(SoulHome.SOULHOME_LOC.toString(), "SoulHome"); + add("biome.soulhome.soulhome", "SoulHome"); + + } + +} diff --git a/src/main/java/leaf/soulhome/datagen/loottables/BlockLootTableGen.java b/src/main/java/leaf/soulhome/datagen/loottables/BlockLootTableGen.java new file mode 100644 index 0000000..19cb262 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/loottables/BlockLootTableGen.java @@ -0,0 +1,28 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.loottables; + +import leaf.soulhome.registry.BlocksRegistry; +import net.minecraft.block.Block; +import net.minecraft.data.loot.BlockLootTables; +import net.minecraftforge.fml.RegistryObject; + +public class BlockLootTableGen extends BlockLootTables +{ + @Override + protected void addTables() + { + for (RegistryObject itemRegistryObject : BlocksRegistry.BLOCKS.getEntries()) + { + this.dropSelf(itemRegistryObject.get()); + } + } + + @Override + protected Iterable getKnownBlocks() + { + return BlocksRegistry.BLOCKS.getEntries().stream().map(RegistryObject::get)::iterator; + } +} diff --git a/src/main/java/leaf/soulhome/datagen/loottables/LootTableGen.java b/src/main/java/leaf/soulhome/datagen/loottables/LootTableGen.java new file mode 100644 index 0000000..58311bb --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/loottables/LootTableGen.java @@ -0,0 +1,43 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.loottables; + +import com.google.common.collect.ImmutableList; +import com.mojang.datafixers.util.Pair; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.LootTableProvider; +import net.minecraft.loot.LootParameterSet; +import net.minecraft.loot.LootParameterSets; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.LootTable.Builder; +import net.minecraft.loot.ValidationTracker; +import net.minecraft.util.ResourceLocation; + +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class LootTableGen extends LootTableProvider +{ + private final List>>, LootParameterSet>> loot_tables = ImmutableList.of(Pair.of(BlockLootTableGen::new, LootParameterSets.BLOCK)); + + public LootTableGen(DataGenerator dataGeneratorIn) + { + super(dataGeneratorIn); + } + + @Override + protected List>>, LootParameterSet>> getTables() + { + return this.loot_tables; + } + + @Override + protected void validate(Map map, ValidationTracker validationtracker) + { + } +} diff --git a/src/main/java/leaf/soulhome/datagen/patchouli/BookStuff.java b/src/main/java/leaf/soulhome/datagen/patchouli/BookStuff.java new file mode 100644 index 0000000..7d44a65 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/patchouli/BookStuff.java @@ -0,0 +1,508 @@ +/* + * File created ~ 14 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.patchouli; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.Map; + +public class BookStuff +{ + public static class Category + { + public String name; + public String description; + public String icon; + public String parent = ""; + public String flag = ""; + public Integer sortnum = 0; + public boolean secret = false; + + public Category(String name, String description, String icon) + { + this.name = "category." + name.toLowerCase(); + this.description = description; + this.icon = icon; + } + + + public JsonElement serialize() + { + JsonObject jsonobject = new JsonObject(); + + jsonobject.addProperty("name", this.name); + jsonobject.addProperty("description", this.description); + jsonobject.addProperty("icon", this.icon); + + if (!this.parent.isEmpty()) + { + jsonobject.addProperty("parent", this.parent); + } + if (!this.flag.isEmpty()) + { + jsonobject.addProperty("flag", this.flag); + } + jsonobject.addProperty("sortnum", this.sortnum); + jsonobject.addProperty("secret", this.secret); + + return jsonobject; + } + } + + public static class Entry + { + public String name; + public Category category; + public String icon; + + public Page[] pages; + + public String advancement = ""; + public String flag = ""; + + public boolean priority = false; + public boolean secret = false; + public boolean read_by_default = false; + public Integer sortnum = 0; + + public String turnin = ""; // advancement needed to mark entry complete + + //itemstack strings -> page 0-index num + public Map extra_recipe_mappings; + + public Entry() { } + + public Entry(String name, Category category) + { + this(name, category, category.icon); + } + + public Entry(String name, Category category, String icon) + { + this.name = "entry." + name.toLowerCase(); + this.category = category; + this.icon = icon; + } + + + public JsonElement serialize() + { + JsonObject jsonobject = new JsonObject(); + + //enforced + jsonobject.addProperty("name", this.name); + jsonobject.addProperty("category", this.category.name); + jsonobject.addProperty("icon", this.icon); + + JsonArray jsonarray = new JsonArray(); + for (Page page : this.pages) + { + jsonarray.add(page.serialize()); + } + jsonobject.add("pages", jsonarray); + + if (advancement != null && !this.advancement.isEmpty()) + { + jsonobject.addProperty("advancement", this.advancement); + } + + if (!this.flag.isEmpty()) + { + jsonobject.addProperty("advancement", this.flag); + } + + jsonobject.addProperty("priority", this.priority); + jsonobject.addProperty("secret", this.secret); + jsonobject.addProperty("read_by_default", this.read_by_default); + + jsonobject.addProperty("sortnum", this.sortnum); + + if (!this.turnin.isEmpty()) + { + jsonobject.addProperty("turnin", this.turnin); + } + + if (extra_recipe_mappings != null && !extra_recipe_mappings.isEmpty()) + { + JsonObject extraRecipeMappingsArray = new JsonObject(); + for (Map.Entry entry : this.extra_recipe_mappings.entrySet()) + { + extraRecipeMappingsArray.addProperty(entry.getKey(), entry.getValue()); + } + jsonobject.add("extra_recipe_mappings", extraRecipeMappingsArray); + } + + + return jsonobject; + } + } + + public abstract static class Page + { + public String type; + public String text; + public String title = ""; + public String advancement = ""; + public String flag = ""; + public String anchor = ""; + public String[] recipes = null; + + public Page(String type, String text) + { + this.type = type; + this.text = text; + } + + public Page(String type, String text, String title) + { + this.type = type; + this.text = text; + this.title = title; + } + + public Page(String type, String text, String[] recipes) + { + this.type = type; + this.text = text; + this.recipes = recipes; + } + + public JsonElement serialize() + { + JsonObject jsonObject = new JsonObject(); + + addElement(jsonObject, "type", this.type); + addElement(jsonObject, "text", this.text); + addElement(jsonObject, "advancement", this.advancement); + addElement(jsonObject, "title", this.title); + + if (recipes != null && recipes.length > 0) + { + JsonArray jsonArray = new JsonArray(); + for (String recipe : this.recipes) + { + jsonArray.add(recipe); + } + jsonObject.add("pages", jsonArray); + } + + return jsonObject; + } + + protected void addElement(JsonObject jsonObject, String key, String value) + { + if (!value.isEmpty()) + { + jsonObject.addProperty(key, value); + } + } + + public Page setTitle(String title) + { + this.title = title; + return this; + } + } + + public static class CraftingPage extends Page + { + public String recipe; + public String recipe2 = ""; + + public CraftingPage(String recipe) + { + super("crafting", ""); + this.recipe = recipe; + } + + public CraftingPage(String text, String recipe) + { + super("crafting", text); + this.recipe = recipe; + } + + public CraftingPage(String text, String recipe, String recipe2) + { + super("crafting", text); + this.recipe = recipe; + this.recipe2 = recipe2; + } + + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + jsonObject.addProperty("recipe", this.recipe); + jsonObject.addProperty("recipe2", this.recipe2); + + + return jsonObject; + } + } + + static class EmptyPage extends Page + { + public boolean draw_filler = true; + + public EmptyPage() + { + super("empty", ""); + } + + public EmptyPage(boolean draw_filler) + { + super("empty", ""); + this.draw_filler = draw_filler; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + jsonObject.addProperty("draw_filler", draw_filler); + + return jsonObject; + } + } + + static class EntityPage extends Page + { + public String name = ""; + public String entity = ""; + public float scale = 1; + public float offset = 0; + public boolean rotate = false; + public float default_rotation = -45; + + public EntityPage(String entity) + { + super("entity", ""); + this.entity = entity; + } + + public EntityPage(String text, String entity) + { + super("entity", text); + this.entity = entity; + } + + public EntityPage(String text, String name, String entity) + { + super("entity", text); + this.name = name; + this.entity = entity; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + addElement(jsonObject, "name", this.name); + addElement(jsonObject, "entity", this.entity); + jsonObject.addProperty("scale", this.scale); + jsonObject.addProperty("offset", this.offset); + jsonObject.addProperty("rotate", this.rotate); + jsonObject.addProperty("default_rotation", this.default_rotation); + + return jsonObject; + } + } + + static class ImagePage extends Page + { + public String[] images; + public boolean border = false; + + public ImagePage(String text, String[] images) + { + super("image", text); + this.images = images; + } + + public ImagePage(String text, String title, String[] images) + { + super("image", text, title); + this.images = images; + } + + public ImagePage(String text, String title, boolean border, String[] images) + { + super("image", text, title); + this.images = images; + this.border = border; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + jsonObject.addProperty("border", this.border); + + if (images != null && images.length > 0) + { + JsonArray jsonarray = new JsonArray(); + for (String image : this.images) + { + jsonarray.add(image); + } + jsonObject.add("images", jsonarray); + } + + return jsonObject; + } + } + + static class QuestPage extends Page + { + public String trigger; + + public QuestPage(String text, String trigger) + { + super("quest", text); + this.trigger = trigger; + } + + public QuestPage(String text, String title, String trigger) + { + super("quest", text, title); + this.trigger = trigger; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + addElement(jsonObject, "trigger", this.trigger); + + return jsonObject; + } + } + + static class RelationsPage extends Page + { + public String[] entries; + + public RelationsPage(String text, String[] entries) + { + super("relations", text); + this.entries = entries; + } + + public RelationsPage(String text, String title, String[] entries) + { + super("relations", text, title); + this.entries = entries; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + if (entries != null && entries.length > 0) + { + JsonArray jsonarray = new JsonArray(); + for (String entry : this.entries) + { + jsonarray.add(entry); + } + jsonObject.add("entries", jsonarray); + } + + return jsonObject; + } + + + } + + static class SmeltingPage extends Page + { + public String recipe; + public String recipe2 = ""; + + public SmeltingPage(String recipe) + { + super("smelting", ""); + this.recipe = recipe; + } + + public SmeltingPage(String text, String recipe) + { + super("smelting", text); + this.recipe = recipe; + } + + public SmeltingPage(String text, String recipe, String recipe2) + { + super("smelting", text); + this.recipe = recipe; + this.recipe2 = recipe2; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + jsonObject.addProperty("recipe", this.recipe); + jsonObject.addProperty("recipe2", this.recipe2); + + + return jsonObject; + } + } + + public static class SpotlightPage extends Page + { + public String item; + public boolean link_recipe = false; + + public SpotlightPage(String text, String item) + { + super("spotlight", text); + this.item = item; + } + + public SpotlightPage(String text, String title, String item) + { + super("spotlight", text, title); + this.item = item; + } + + @Override + public JsonElement serialize() + { + JsonObject jsonObject = (JsonObject) super.serialize(); + + jsonObject.addProperty("item", this.item); + jsonObject.addProperty("link_recipe", this.link_recipe); + + return jsonObject; + } + } + + public static class TextPage extends Page + { + public TextPage(String text) + { + super("text", text); + } + + public TextPage(String text, String title) + { + super("text", text, title); + } + } +} + + diff --git a/src/main/java/leaf/soulhome/datagen/patchouli/PatchouliGen.java b/src/main/java/leaf/soulhome/datagen/patchouli/PatchouliGen.java new file mode 100644 index 0000000..53b9de5 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/patchouli/PatchouliGen.java @@ -0,0 +1,172 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.patchouli; + +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import leaf.soulhome.datagen.patchouli.categories.PatchouliBasics; +import leaf.soulhome.datagen.patchouli.categories.PatchouliMultiblocks; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DirectoryCache; +import net.minecraft.data.IDataProvider; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; + +// +// In-Game Documentation generator +// +public class PatchouliGen implements IDataProvider +{ + private static final Logger LOGGER = LogManager.getLogger(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + public static final String GUIDE_NAME = "guide"; + private final DataGenerator generator; + + + private final List categories = new ArrayList<>(); + private final List entries = new ArrayList<>(); + + public PatchouliGen(DataGenerator generatorIn) + { + this.generator = generatorIn; + } + + /** + * Performs this provider's action. + */ + public void run(DirectoryCache cache) throws IOException + { + Path path = this.generator.getOutputFolder(); + Set entryIDs = Sets.newHashSet(); + + Consumer entryConsumer = getEntryConsumer(cache, path, entryIDs); + Consumer categoryConsumer = getCategoryConsumer(cache, path, entryIDs); + + //adds to our categories and entries fields. + collectInfoForBook(); + + for (BookStuff.Category categoryToConsume : this.categories) + { + categoryConsumer.accept(categoryToConsume); + } + + for (BookStuff.Entry entryToConsume : this.entries) + { + entryConsumer.accept(entryToConsume); + } + + } + + private void collectInfoForBook() + { + //dynamically figure out all the things we wanna generate categories/entries for? + //------------------------------------------// + // Categories // + //------------------------------------------// + // - Basics // + // - Curios // + // - Machines ? // + // - Challenges ? // + // - // + // - // + // - // + // - // + // - // + //------------------------------------------// + + PatchouliBasics.collect(this.categories, this.entries); + PatchouliMultiblocks.collect(this.categories, this.entries); + + + } + + private Consumer getCategoryConsumer(DirectoryCache cache, Path path, Set categoryIDs) + { + return category -> + { + if (!categoryIDs.add(category.name)) + { + throw new IllegalStateException("Duplicate page " + category.name); + } + else + { + Path path1 = getCategoryPath(path, category); + + try + { + IDataProvider.save(GSON, cache, category.serialize(), path1); + } catch (IOException ioexception) + { + LOGGER.error("Couldn't save page {}", path1, ioexception); + } + + } + }; + } + + private Consumer getEntryConsumer(DirectoryCache cache, Path path, Set entryIDs) + { + return entry -> + { + if (!entryIDs.add(entry.name)) + { + throw new IllegalStateException("Duplicate page " + entry.name); + } + else + { + Path path1 = getEntryPath(path, entry); + + try + { + IDataProvider.save(GSON, cache, entry.serialize(), path1); + } catch (IOException ioexception) + { + LOGGER.error("Couldn't save page {}", path1, ioexception); + } + + } + }; + } + + private static Path getCategoryPath(Path pathIn, BookStuff.Category category) + { + return pathIn.resolve( + String.format( + "data/soulhome/patchouli_books/%s/en_us/categories/%s.json", + GUIDE_NAME, + category.name)); + } + + private static Path getEntryPath(Path pathIn, BookStuff.Entry entry) + { + return pathIn.resolve( + String.format( + "data/soulhome/patchouli_books/%s/en_us/entries/%s/%s.json", + GUIDE_NAME, + entry.category.name, + entry.name)); + } + + /** + * Gets a name for this provider, to use in logging. + */ + public String getName() + { + return "PatchouliGeneration"; + } + + +} + + + diff --git a/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliBasics.java b/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliBasics.java new file mode 100644 index 0000000..915bd91 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliBasics.java @@ -0,0 +1,71 @@ +/* + * File created ~ 14 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.patchouli.categories; + +import leaf.soulhome.datagen.patchouli.BookStuff; + +import java.util.ArrayList; +import java.util.List; + +public class PatchouliBasics +{ + public static void collect(List categories, List entries) + { + BookStuff.Category basics = new BookStuff.Category( + "basics", + "An introduction to the mod, serving as a tutorial.", + "soulhome:guide"); + + basics.sortnum = 0; + + categories.add(basics); + + BookStuff.Entry welcomeEntry = new BookStuff.Entry("welcome", basics, basics.icon); + welcomeEntry.pages = new BookStuff.Page[] + { + new BookStuff.TextPage("Hey, thanks for checking out this mod! It came about from my love of the $(item)Spectre Key$(0) from $(thing)RandomThings$(0). $(p)The idea of having a safe area in a different dimension that you could go to and come back from was very appealing. "), + new BookStuff.TextPage("This current iteration of SoulHome is very basic, with a low barrier of entry on purpose. $(p)There's some exciting stuff coming in future versions though, so I hope you'll stick around!"), + new BookStuff.TextPage("If you still aren't sure where to start, this book (as well as advancements) should help you find what the next step is. The book is set up to unlock new entries with every advancement completed.$(p) $(p)For now though, here's a tip:"), + new BookStuff.CraftingPage("All you need is a little bit of iron and an ender pearl", "soulhome:soulkey").setTitle("SoulKey"), + }; + welcomeEntry.priority = true; + welcomeEntry.sortnum = -10; + entries.add(welcomeEntry); + + BookStuff.Entry bookEntry = new BookStuff.Entry("guide", basics, basics.icon); + bookEntry.sortnum = 2; + bookEntry.pages = new BookStuff.Page[] + { + new BookStuff.TextPage("Your guide to everything in the mod! There isn't much at the moment, but future versions will allow you to build structures within your soul in order to gain benefits when you're outside of it. "), + new BookStuff.TextPage("For example, building a farm in a specific multiblock structure might mean that you get more saturation out of each thing that you eat. Or maybe you'd build an armoury in order to gain a buff to toughness. At this point in time though, there's only the $(l:soulhome:category.basics/entry.soul_key)$(item)SoulKey$(0) $(/l)"), + }; + entries.add(bookEntry); + + BookStuff.Entry soulkeyEntry = new BookStuff.Entry("soul_key", basics, basics.icon); + soulkeyEntry.sortnum = 3; + soulkeyEntry.advancement = "soulhome:main/obtained_soul_key"; + soulkeyEntry.turnin = "soulhome:main/obtained_soul_key"; + soulkeyEntry.pages = new BookStuff.Page[] + { + new BookStuff.TextPage("Hey, well done! You've managed to obtain the centerpiece to this mod. Now you just need to enter your soul by holding [$(k:use)]. You'll see some particles start appearing at your feet, an every widening circle showing the area of effect."), + new BookStuff.TextPage("If you hold [$(k:use)] for the full duration, you and all other entities within the circle will be transported to your soul. This is how you'd bring friends and livestock into your soul."), + new BookStuff.CraftingPage("All you need is a little bit of iron and an ender pearl", "soulhome:soulkey").setTitle("SoulKey"), + + }; + entries.add(soulkeyEntry); + + BookStuff.Entry enteredSoul = new BookStuff.Entry("soul", basics, basics.icon); + enteredSoul.sortnum = 4; + enteredSoul.turnin = "soulhome:main/entered_soul_dimension"; + enteredSoul.advancement = "soulhome:main/obtained_soul_key"; + enteredSoul.pages = new BookStuff.Page[] + { + new BookStuff.TextPage("Woo! Welcome to your soul. $(p)Kinda empty, isn't it? I wonder what that says about you, huh. $(p)For now, that's all there is to the mod. Look out for future updates that will let you build multiblock structures to give yourself buffs."), + }; + entries.add(enteredSoul); + + + } +} diff --git a/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliMultiblocks.java b/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliMultiblocks.java new file mode 100644 index 0000000..91e99ba --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/patchouli/categories/PatchouliMultiblocks.java @@ -0,0 +1,43 @@ +/* + * File created ~ 14 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.patchouli.categories; + +import leaf.soulhome.datagen.patchouli.BookStuff; + +import java.util.List; + +public class PatchouliMultiblocks +{ + public static void collect(List categories, List entries) + { + BookStuff.Category multiblocks = new BookStuff.Category( + "multiblocks", + "Structures you can build within your soul that will grant you power.", + "soulhome:guide"); + + multiblocks.sortnum = 0; + + categories.add(multiblocks); + + + + BookStuff.Entry blankEntry = new BookStuff.Entry("Blank", multiblocks, multiblocks.icon); + blankEntry.pages = new BookStuff.Page[] + { + new BookStuff.TextPage( + "Blank Blank Blank! ",blankEntry.icon), + }; + blankEntry.priority = true; + blankEntry.sortnum = -10; + blankEntry.advancement = "soulhome:main/blank"; + entries.add(blankEntry); + + + + + + + } +} diff --git a/src/main/java/leaf/soulhome/datagen/recipe/RecipeGen.java b/src/main/java/leaf/soulhome/datagen/recipe/RecipeGen.java new file mode 100644 index 0000000..61f3157 --- /dev/null +++ b/src/main/java/leaf/soulhome/datagen/recipe/RecipeGen.java @@ -0,0 +1,119 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.datagen.recipe; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.ItemsRegistry; +import leaf.soulhome.utils.ResourceLocationHelper; +import net.minecraft.block.Blocks; +import net.minecraft.data.*; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.tags.ITag; +import net.minecraft.util.IItemProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.crafting.conditions.IConditionBuilder; + +import javax.annotation.Nullable; +import java.util.function.Consumer; + +public class RecipeGen extends RecipeProvider implements IConditionBuilder +{ + public RecipeGen(DataGenerator generatorIn) + { + super(generatorIn); + } + + @Override + protected void buildShapelessRecipes(Consumer consumer) + { + + //example recipes obtained from following website on 3rd April '21. Thank you ChampionAsh5357! + //https://github.com/ChampionAsh5357/1.16.x-Minecraft-Tutorial/blob/1.16.1-32.0.61-web/src/main/java/io/github/championash5357/tutorial/data/TutorialRecipeProvider.java + + //addBasicArmorRecipes(consumer, ItemsRegistry.RUBY.get(), ItemsRegistry.RUBY_HELMET.get(), ItemsRegistry.RUBY_CHESTPLATE.get(), ItemsRegistry.RUBY_LEGGINGS.get(), ItemsRegistry.RUBY_BOOTS.get()); + //ShapedRecipeBuilder.shapedRecipe(BlocksRegistry.WASHER.get()).key('I', Items.IRON_INGOT).key('W', Items.WATER_BUCKET).patternLine("III").patternLine("IWI").patternLine("III").addCriterion("in_water", enteredBlock(Blocks.WATER)).build(consumer); + + + //addOreSmeltingRecipes(consumer, BlocksRegistry.GEM_BLOCK.get(), ItemsRegistry.GUIDE.get(), 1.0f, 200); + + ShapedRecipeBuilder + .shaped(ItemsRegistry.SOUL_KEY.get()) //output + .define('I', Items.IRON_INGOT) + .define('E', Items.ENDER_PEARL) + .pattern("I ") //top row + .pattern("II ") //middle row + .pattern(" E") //bottom row + .unlockedBy("has_material", has(Items.ENDER_PEARL)) + .save(consumer); + + ShapelessRecipeBuilder + .shapeless(ItemsRegistry.GUIDE.get()) + .requires(Items.BOOK) + .requires(ItemsRegistry.SOUL_KEY.get()) + .unlockedBy("has_soul_key", has(ItemsRegistry.SOUL_KEY.get())) + .save(consumer); + + + + } + + + protected static void addBasicArmorRecipes(Consumer consumer, ITag inputMaterial, @Nullable Item head, @Nullable Item chest, @Nullable Item legs, @Nullable Item feet) + { + if (head != null) + { + ShapedRecipeBuilder.shaped(head).define('X', inputMaterial).pattern("XXX").pattern("X X").group("helmets").unlockedBy("has_material", has(inputMaterial)).save(consumer); + } + if (chest != null) + { + ShapedRecipeBuilder.shaped(chest).define('X', inputMaterial).pattern("X X").pattern("XXX").pattern("XXX").group("chestplates").unlockedBy("has_material", has(inputMaterial)).save(consumer); + } + if (legs != null) + { + ShapedRecipeBuilder.shaped(legs).define('X', inputMaterial).pattern("XXX").pattern("X X").pattern("X X").group("leggings").unlockedBy("has_material", has(inputMaterial)).save(consumer); + } + if (feet != null) + { + ShapedRecipeBuilder.shaped(feet).define('X', inputMaterial).pattern("X X").pattern("X X").group("boots").unlockedBy("has_material", has(inputMaterial)).save(consumer); + } + } + + private void decompressRecipe(Consumer consumer, IItemProvider output, ITag input, String name) + { + ShapelessRecipeBuilder.shapeless(output, 9) + .unlockedBy("has_item", has(output)) + .requires(input) + .save(consumer, ResourceLocationHelper.prefix("conversions/" + name)); + } + + private ShapedRecipeBuilder compressRecipe(IItemProvider output, ITag input) + { + return ShapedRecipeBuilder.shaped(output) + .define('I', input) + .pattern("III") + .pattern("III") + .pattern("III") + .unlockedBy("has_item", has(input)); + } + + protected static void addOreSmeltingRecipes(Consumer consumer, IItemProvider ore, Item result, float experience, int time) + { + String name = result.getRegistryName().getPath(); + String path = ore.asItem().getRegistryName().getPath(); + CookingRecipeBuilder.smelting(Ingredient.of(ore), result, experience, time).unlockedBy("has_ore", has(ore)).save(consumer, ResourceLocationHelper.prefix(name + "_from_smelting_" + path)); + CookingRecipeBuilder.blasting(Ingredient.of(ore), result, experience, time / 2).unlockedBy("has_ore", has(ore)).save(consumer, ResourceLocationHelper.prefix(name + "_from_blasting_" + path)); + } + + protected static void addCookingRecipes(Consumer consumer, IItemProvider inputItem, Item result, float experience, int time) + { + String name = result.getRegistryName().getPath(); + CookingRecipeBuilder.smelting(Ingredient.of(inputItem), result, experience, time).unlockedBy("has_item", has(inputItem)).save(consumer, ResourceLocationHelper.prefix(name + "_from_smelting")); + CookingRecipeBuilder.cooking(Ingredient.of(inputItem), result, experience, time / 2, IRecipeSerializer.SMOKING_RECIPE).unlockedBy("has_item", has(inputItem)).save(consumer, ResourceLocationHelper.prefix(name + "_from_smoking")); + CookingRecipeBuilder.cooking(Ingredient.of(inputItem), result, experience, time, IRecipeSerializer.CAMPFIRE_COOKING_RECIPE).unlockedBy("has_item", has(inputItem)).save(consumer, ResourceLocationHelper.prefix(name + "_from_campfire")); + } +} diff --git a/src/main/java/leaf/soulhome/dimensions/SoulChunkGenerator.java b/src/main/java/leaf/soulhome/dimensions/SoulChunkGenerator.java new file mode 100644 index 0000000..08b7a2a --- /dev/null +++ b/src/main/java/leaf/soulhome/dimensions/SoulChunkGenerator.java @@ -0,0 +1,132 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.dimensions; + +import com.mojang.serialization.Codec; +import leaf.soulhome.registry.BiomeRegistry; +import leaf.soulhome.utils.DimensionHelper; +import net.minecraft.block.BlockState; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.registry.DynamicRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryLookupCodec; +import net.minecraft.world.Blockreader; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.ISeedReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeManager; +import net.minecraft.world.biome.provider.SingleBiomeProvider; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.GenerationStage; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.gen.WorldGenRegion; +import net.minecraft.world.gen.feature.structure.Structure; +import net.minecraft.world.gen.feature.structure.StructureManager; +import net.minecraft.world.gen.feature.template.TemplateManager; +import net.minecraft.world.gen.settings.DimensionStructuresSettings; +import net.minecraft.world.server.ServerWorld; + +import javax.annotation.Nullable; + +public class SoulChunkGenerator extends ChunkGenerator +{ + public static final Codec providerCodec = + RegistryLookupCodec.create(Registry.BIOME_REGISTRY) + .xmap(SoulChunkGenerator::new, SoulChunkGenerator::getBiomeRegistry) + .codec(); + + private final Registry biomeRegistry; + + public SoulChunkGenerator(MinecraftServer server) + { + this(server.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)); + } + + public SoulChunkGenerator(Registry biomes) + { + super(new SingleBiomeProvider(biomes.getOrThrow(BiomeRegistry.SOUL_BIOME_KEY)), new DimensionStructuresSettings(false)); + this.biomeRegistry = biomes; + } + + @Override + public int getSpawnHeight() + { + return DimensionHelper.FLOOR_LEVEL; + } + + @Override + protected Codec codec() + { + return providerCodec; + } + + @Override + public IBlockReader getBaseColumn(int x, int z) + { + BlockState[] blockstate = new BlockState[0]; + return new Blockreader(blockstate); + } + + @Override + public ChunkGenerator withSeed(long seedIn) + { + return this; + } + + @Override + public void fillFromNoise(IWorld world, StructureManager structures, IChunk chunk) { } + + @Override + public void buildSurfaceAndBedrock(WorldGenRegion region, IChunk chunk) { } + + @Override + public int getBaseHeight(int x, int z, Heightmap.Type heightmapType) + { + return 0; + } + + public Registry getBiomeRegistry() + { + return this.biomeRegistry; + } + + @Override + public int getGenDepth() + { + return 256; + } + + @Override + public void applyCarvers(long seed, BiomeManager biomes, IChunk chunk, GenerationStage.Carving carvingStage) { } + + @Override + public void spawnOriginalMobs(WorldGenRegion p_230354_1_) { } + + @Nullable + @Override + public BlockPos findNearestMapFeature(ServerWorld world, Structure structure, BlockPos start, int radius, boolean skipExistingChunks) + { + return null; + } + + @Override + public void applyBiomeDecoration(WorldGenRegion world, StructureManager structures) { } + + @Override + public boolean hasStronghold(ChunkPos chunkPos) + { + return false; + } + + @Override + public void createStructures(DynamicRegistries registries, StructureManager structures, IChunk chunk, TemplateManager templates, long seed) { } + + @Override + public void createReferences(ISeedReader world, StructureManager structures, IChunk chunk) { } +} diff --git a/src/main/java/leaf/soulhome/dimensions/SoulDimensionRenderInfo.java b/src/main/java/leaf/soulhome/dimensions/SoulDimensionRenderInfo.java new file mode 100644 index 0000000..d4064f4 --- /dev/null +++ b/src/main/java/leaf/soulhome/dimensions/SoulDimensionRenderInfo.java @@ -0,0 +1,42 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.dimensions; + +import leaf.soulhome.client.renderers.EmptyWeatherRenderer; +import net.minecraft.client.world.DimensionRenderInfo; +import net.minecraft.util.math.vector.Vector3d; + + +public class SoulDimensionRenderInfo extends DimensionRenderInfo +{ + + public SoulDimensionRenderInfo() + { + this(128, + false, + FogType.NONE, + false, + true); + } + + public SoulDimensionRenderInfo(float cloudLevel, boolean hasGround, FogType skyType, boolean forceBrightLightmap, boolean constantAmbientLight) + { + super(cloudLevel, hasGround, skyType, forceBrightLightmap, constantAmbientLight); + this.setWeatherRenderHandler(new EmptyWeatherRenderer()); + } + + @Override + public Vector3d getBrightnessDependentFogColor(Vector3d p_230494_1_, float p_230494_2_) + { + //copied from overworld + return p_230494_1_.multiply(p_230494_2_ * 0.94F + 0.06F, p_230494_2_ * 0.94F + 0.06F, p_230494_2_ * 0.91F + 0.09F); + } + + @Override + public boolean isFoggyAt(int p_230493_1_, int p_230493_2_) + { + return false; + } +} diff --git a/src/main/java/leaf/soulhome/handlers/CommonEvents.java b/src/main/java/leaf/soulhome/handlers/CommonEvents.java new file mode 100644 index 0000000..abdb423 --- /dev/null +++ b/src/main/java/leaf/soulhome/handlers/CommonEvents.java @@ -0,0 +1,54 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.handlers; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.commands.SoulCommand; +import leaf.soulhome.commands.permissions.PermissionManager; +import leaf.soulhome.utils.DimensionHelper; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.DamageSource; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; + + +@Mod.EventBusSubscriber(modid = SoulHome.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class CommonEvents +{ + @SubscribeEvent + public static void registerCommands(RegisterCommandsEvent event) + { + SoulCommand.register(event.getDispatcher()); + } + + + @SubscribeEvent + public static void onServerStarting(FMLServerStartingEvent event) + { + PermissionManager.init(); + } + + @SubscribeEvent + public static void onLivingHurt(LivingHurtEvent event) + { + final LivingEntity entityLiving = event.getEntityLiving(); + if (entityLiving instanceof PlayerEntity + && DimensionHelper.isInSoulDimension(entityLiving)) + { + event.setCanceled(true); + event.getEntityLiving().fallDistance = 0; + + if (event.getSource() == DamageSource.OUT_OF_WORLD) + { + DimensionHelper.FlipDimension((PlayerEntity) entityLiving, entityLiving.getServer(), null); + } + + } + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/items/BaseItem.java b/src/main/java/leaf/soulhome/items/BaseItem.java new file mode 100644 index 0000000..c46eb93 --- /dev/null +++ b/src/main/java/leaf/soulhome/items/BaseItem.java @@ -0,0 +1,25 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.items; + + +import leaf.soulhome.properties.PropTypes; +import net.minecraft.item.Item; + +public class BaseItem extends Item +{ + + public BaseItem() + { + super(PropTypes.Items.SIXTY_FOUR.get().tab(SoulHomeItemGroups.ITEMS)); + } + + public BaseItem(Properties prop) + { + super(prop); + } + + +} diff --git a/src/main/java/leaf/soulhome/items/GuideItem.java b/src/main/java/leaf/soulhome/items/GuideItem.java new file mode 100644 index 0000000..2e9dd47 --- /dev/null +++ b/src/main/java/leaf/soulhome/items/GuideItem.java @@ -0,0 +1,95 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.items; + +import leaf.soulhome.compat.patchouli.PatchouliCompat; +import leaf.soulhome.constants.Constants; +import leaf.soulhome.properties.PropTypes; +import leaf.soulhome.registry.ItemsRegistry; +import leaf.soulhome.utils.TextHelper; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Rarity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import vazkii.patchouli.api.PatchouliAPI; + +import javax.annotation.Nonnull; +import java.util.List; + +public class GuideItem extends BaseItem +{ + + public GuideItem() + { + super(PropTypes.Items.ONE.get().rarity(Rarity.RARE)); + } + + public static boolean isOpen() + { + return ItemsRegistry.GUIDE.getId().equals(PatchouliAPI.get().getOpenBookGui()); + } + + + public static ITextComponent getTitle(ItemStack stack) + { + //botania uses this when they are rendering their book title in the world. + + ITextComponent title = stack.getDisplayName(); + + String akashicTomeNBT = "akashictome:displayName"; + if (stack.hasTag() && stack.getTag().contains(akashicTomeNBT)) + { + title = ITextComponent.Serializer.fromJson(stack.getTag().getString(akashicTomeNBT)); + } + + return title; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void appendHoverText(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) + { + tooltip.add(getEdition().copy().withStyle(TextFormatting.GRAY)); + } + + public static ITextComponent getEdition() + { + if (PatchouliCompat.PatchouliIsPresent()) + { + return PatchouliAPI.get().getSubtitle(ItemsRegistry.GUIDE.getId()); + } + else + { + return TextHelper.createTranslatedText(Constants.StringKeys.PATCHOULI_NOT_INSTALLED); + } + } + + @Nonnull + @Override + public ActionResult use(World worldIn, PlayerEntity playerIn, Hand handIn) + { + ItemStack stack = playerIn.getItemInHand(handIn); + + if (playerIn instanceof ServerPlayerEntity) + { + ServerPlayerEntity player = (ServerPlayerEntity) playerIn; + PatchouliAPI.get().openBookGUI(player, ItemsRegistry.GUIDE.getId()); + } + + return new ActionResult<>(ActionResultType.SUCCESS, stack); + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/items/SoulHomeItemGroups.java b/src/main/java/leaf/soulhome/items/SoulHomeItemGroups.java new file mode 100644 index 0000000..48280eb --- /dev/null +++ b/src/main/java/leaf/soulhome/items/SoulHomeItemGroups.java @@ -0,0 +1,22 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.items; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.ItemsRegistry; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; + +public class SoulHomeItemGroups +{ + public static ItemGroup ITEMS = new ItemGroup(SoulHome.MODID + ".items") + { + @Override + public ItemStack makeIcon() + { + return new ItemStack(ItemsRegistry.SOUL_KEY.get()); + } + }; +} diff --git a/src/main/java/leaf/soulhome/items/SoulKeyItem.java b/src/main/java/leaf/soulhome/items/SoulKeyItem.java new file mode 100644 index 0000000..ca0404c --- /dev/null +++ b/src/main/java/leaf/soulhome/items/SoulKeyItem.java @@ -0,0 +1,158 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.items; + +import leaf.soulhome.compat.curios.CuriosCompat; +import leaf.soulhome.compat.curios.SoulHomeCurios; +import leaf.soulhome.constants.Constants; +import leaf.soulhome.properties.PropTypes; +import leaf.soulhome.utils.DimensionHelper; +import leaf.soulhome.utils.MathUtils; +import leaf.soulhome.utils.TextHelper; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Rarity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import top.theillusivec4.curios.api.CuriosCapability; +import top.theillusivec4.curios.api.type.capability.ICurio; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +public class SoulKeyItem extends BaseItem +{ + final int USE_TICKS_REQUIRED = 80; + + public SoulKeyItem() + { + super(PropTypes.Items.ONE.get().rarity(Rarity.RARE)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void appendHoverText(ItemStack stack, World worldIn, List tooltip, ITooltipFlag flagIn) + { + tooltip.add(TextHelper.createTranslatedText(Constants.StringKeys.KEY_SOUL_CHARGE)); + } + + @Override + public int getUseDuration(ItemStack stack) + { + return USE_TICKS_REQUIRED; + } + + @Nonnull + @Override + public ActionResult use(World worldIn, PlayerEntity playerIn, Hand handIn) + { + ItemStack stack = playerIn.getItemInHand(handIn); + if (playerIn instanceof ServerPlayerEntity) + { + ServerPlayerEntity player = (ServerPlayerEntity) playerIn; + player.startUsingItem(handIn); + } + return new ActionResult<>(ActionResultType.SUCCESS, stack); + } + + @Nonnull + @Override + public ItemStack finishUsingItem(ItemStack stack, World world, LivingEntity livingEntity) + { + if (!livingEntity.level.isClientSide && livingEntity instanceof PlayerEntity) + { + //find all creatures in range + AxisAlignedBB areaOfEffect = new AxisAlignedBB(livingEntity.blockPosition()).inflate(2.5d); + List entitiesInRange = world.getEntitiesOfClass(Entity.class, areaOfEffect); + DimensionHelper.FlipDimension((PlayerEntity) livingEntity, livingEntity.getServer(), entitiesInRange); + } + + return stack; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void onUseTick(World world, LivingEntity livingEntity, ItemStack stack, int count) + { + if (livingEntity.level.isClientSide) + { + float percentage = MathUtils.clamp01((USE_TICKS_REQUIRED - count) / (float) USE_TICKS_REQUIRED); + int particlesToCreate = MathHelper.floor((percentage * percentage * percentage) * USE_TICKS_REQUIRED); + + final float maxRadius = 5; + float bits = 360f / particlesToCreate; + float radius = percentage * maxRadius; + + for (int i = particlesToCreate; i >= 0; --i) + { + float ang = (bits * i);// + (Math.random() * 10); + + livingEntity.level.addParticle( + ParticleTypes.POOF, + livingEntity.getX() + MathHelper.sin(MathHelper.wrapDegrees(ang)) * radius, + livingEntity.getY(), + livingEntity.getZ() + MathHelper.cos(MathHelper.wrapDegrees(ang)) * radius, + 0.0D, + 0.0D, + 0.0D); + } + } + } + +//region Remaining item from crafting, using the soul key as an ingredient. We want to keep the key. + @Override + public boolean hasContainerItem(ItemStack stack) + { + return true; + } + + @Override + public ItemStack getContainerItem(ItemStack stack) + { + return new ItemStack(stack.getItem()); + } +//endregion + +//region Curio capability stuff. Only used if curios is installed. + @Nullable + @Override + public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundNBT nbt) + { + if (CuriosCompat.CuriosIsPresent()) + { + return new ICapabilityProvider() + { + final LazyOptional curio = LazyOptional.of(SoulHomeCurios::createKeyCurioProvider); + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability capability, @Nullable Direction side) + { + return CuriosCapability.ITEM.orEmpty(capability, curio); + } + }; + } + return null; + } +//endregion +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/mixin/EffectInstanceMixin.java b/src/main/java/leaf/soulhome/mixin/EffectInstanceMixin.java new file mode 100644 index 0000000..b3040e5 --- /dev/null +++ b/src/main/java/leaf/soulhome/mixin/EffectInstanceMixin.java @@ -0,0 +1,14 @@ +/* + * File created ~ 29 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.mixin; + +import net.minecraft.potion.EffectInstance; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(EffectInstance.class) +public class EffectInstanceMixin +{ + +} diff --git a/src/main/java/leaf/soulhome/mixin/EntityMixin.java b/src/main/java/leaf/soulhome/mixin/EntityMixin.java new file mode 100644 index 0000000..d545e7e --- /dev/null +++ b/src/main/java/leaf/soulhome/mixin/EntityMixin.java @@ -0,0 +1,16 @@ +/* + * File created ~ 6 - 6 - 2021 ~ Leaf + */ + +package leaf.soulhome.mixin; + +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(Entity.class) +public class EntityMixin +{ + + +} + diff --git a/src/main/java/leaf/soulhome/network/ClientPacketHandler.java b/src/main/java/leaf/soulhome/network/ClientPacketHandler.java new file mode 100644 index 0000000..43e58b5 --- /dev/null +++ b/src/main/java/leaf/soulhome/network/ClientPacketHandler.java @@ -0,0 +1,34 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.network; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.util.RegistryKey; +import net.minecraft.world.World; + +import java.util.Set; + +public class ClientPacketHandler +{ + public static void syncDimensionList(SyncDimensionListMessage packet) + { + ClientPlayerEntity player = Minecraft.getInstance().player; + RegistryKey key = packet.getId(); + if (player == null || key == null) + { + return; + } + Set> worlds = player.connection.levels(); + if (packet.getAdd()) + { + worlds.add(key); + } + else + { + worlds.remove(key); + } + } +} diff --git a/src/main/java/leaf/soulhome/network/Network.java b/src/main/java/leaf/soulhome/network/Network.java new file mode 100644 index 0000000..5cd2889 --- /dev/null +++ b/src/main/java/leaf/soulhome/network/Network.java @@ -0,0 +1,104 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.network; + +import com.mojang.serialization.Codec; +import leaf.soulhome.SoulHome; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.fml.network.NetworkEvent; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.PacketDistributor; +import net.minecraftforge.fml.network.simple.SimpleChannel; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class Network +{ + private static final String PROTOCOL_VERSION = Integer.toString(1); + private static final SimpleChannel NETWORK_CHANNEL = NetworkRegistry.newSimpleChannel(SoulHome.SOULHOME_LOC, () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals); + + public static void init() + { + int id = 0; + registerCodecPacket(id++, NETWORK_CHANNEL, SyncDimensionListMessage.CODEC, SyncDimensionListMessage.INVALID); + } + + public static > void registerCodecPacket(int id, SimpleChannel channel, Codec codec, PACKET defaultPacket) + { + final BiConsumer encoder = (packet, buffer) -> codec.encodeStart(NBTDynamicOps.INSTANCE, packet) + .result() + .ifPresent(nbt -> buffer.writeNbt((CompoundNBT) nbt)); + final Function decoder = buffer -> codec.parse(NBTDynamicOps.INSTANCE, buffer.readNbt()) + .result() + .orElse(defaultPacket); + final BiConsumer> handler = (packet, context) -> + { + packet.accept(context.get()); + context.get().setPacketHandled(true); + }; + + final Class packetClass = (Class) (defaultPacket.getClass()); + + channel.registerMessage(id, packetClass, encoder, decoder, handler); + } + + + //client side to server + public static void sendToServer(Object msg) + { + NETWORK_CHANNEL.sendToServer(msg); + } + + //server side to client + public static void sendTo(Object msg, ServerPlayerEntity player) + { + if (!(player instanceof FakePlayer)) + { + NETWORK_CHANNEL.send(PacketDistributor.PLAYER.with(() -> player), msg); + } + } + + public static void sendPacketToAll(Object packet) + { + NETWORK_CHANNEL.send(PacketDistributor.ALL.noArg(), packet); + } + + public static SUpdateTileEntityPacket createTEUpdatePacket(TileEntity tile) + { + return new SUpdateTileEntityPacket(tile.getBlockPos(), -1, tile.getUpdateTag()); + } + + public static void sendToAllAround(Object mes, RegistryKey dim, BlockPos pos, int radius) + { + NETWORK_CHANNEL.send(PacketDistributor.NEAR.with(() -> new PacketDistributor.TargetPoint(pos.getX(), pos.getY(), pos.getZ(), radius, dim)), mes); + } + + public static void sendToAllInWorld(Object mes, ServerWorld world) + { + NETWORK_CHANNEL.send(PacketDistributor.DIMENSION.with(world::dimension), mes); + } + + public static void sendToTrackingTE(Object mes, TileEntity te) + { + if (te != null && !te.getLevel().isClientSide) + { + NETWORK_CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> te.getLevel().getChunkAt(te.getBlockPos())), mes); + } + } +} diff --git a/src/main/java/leaf/soulhome/network/SyncDimensionListMessage.java b/src/main/java/leaf/soulhome/network/SyncDimensionListMessage.java new file mode 100644 index 0000000..966afca --- /dev/null +++ b/src/main/java/leaf/soulhome/network/SyncDimensionListMessage.java @@ -0,0 +1,54 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.network; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.util.RegistryKey; +import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +import java.util.function.Consumer; + +public class SyncDimensionListMessage implements Consumer +{ + + public static final SyncDimensionListMessage INVALID = new SyncDimensionListMessage(null, false); + + public static final Codec CODEC = + RecordCodecBuilder.create(instance -> instance + .group(World.RESOURCE_KEY_CODEC + .optionalFieldOf("id", null) + .forGetter(SyncDimensionListMessage::getId), + Codec.BOOL.fieldOf("add") + .forGetter(SyncDimensionListMessage::getAdd)) + .apply(instance, SyncDimensionListMessage::new)); + + + private final RegistryKey id; + private final boolean add; + + public SyncDimensionListMessage(RegistryKey id, boolean add) + { + this.id = id; + this.add = add; + } + + public RegistryKey getId() + { + return this.id; + } + + public boolean getAdd() + { + return this.add; + } + + @Override + public void accept(Context context) + { + context.enqueueWork(() -> ClientPacketHandler.syncDimensionList(this)); + } +} diff --git a/src/main/java/leaf/soulhome/properties/PropTypes.java b/src/main/java/leaf/soulhome/properties/PropTypes.java new file mode 100644 index 0000000..881364b --- /dev/null +++ b/src/main/java/leaf/soulhome/properties/PropTypes.java @@ -0,0 +1,31 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.properties; + +import leaf.soulhome.items.SoulHomeItemGroups; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.item.Item; +import net.minecraft.item.Rarity; +import net.minecraftforge.common.ToolType; + +import java.util.function.Supplier; + +public class PropTypes +{ + public static class Blocks + { + public static final Supplier EXAMPLE = () -> Block.Properties.of(Material.GLASS).strength(2.0F, 6.0F).harvestLevel(0).harvestTool(ToolType.PICKAXE); + } + + public static class Items + { + public static final Supplier ONE = () -> new Item.Properties().tab(SoulHomeItemGroups.ITEMS).stacksTo(1); + + public static final Supplier SIXTEEN = () -> new Item.Properties().tab(SoulHomeItemGroups.ITEMS).stacksTo(16); + + public static final Supplier SIXTY_FOUR = () -> new Item.Properties().tab(SoulHomeItemGroups.ITEMS).stacksTo(64); + } +} diff --git a/src/main/java/leaf/soulhome/registry/BiomeRegistry.java b/src/main/java/leaf/soulhome/registry/BiomeRegistry.java new file mode 100644 index 0000000..d49124c --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/BiomeRegistry.java @@ -0,0 +1,28 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.registry; + +import leaf.soulhome.SoulHome; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeMaker; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + +public class BiomeRegistry +{ + public static RegistryKey SOUL_BIOME_KEY; + public static final DeferredRegister BIOMES = DeferredRegister.create(ForgeRegistries.BIOMES, SoulHome.MODID); + public static final RegistryObject SOUL_BIOME = BIOMES.register(SoulHome.MODID, () -> BiomeMaker.plainsBiome(false)); + + + public static void registerBiomeKeys() + { + SOUL_BIOME_KEY = RegistryKey.create(Registry.BIOME_REGISTRY, SoulHome.SOULHOME_LOC); + } + +} diff --git a/src/main/java/leaf/soulhome/registry/BlocksRegistry.java b/src/main/java/leaf/soulhome/registry/BlocksRegistry.java new file mode 100644 index 0000000..ade202b --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/BlocksRegistry.java @@ -0,0 +1,37 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + * Special thank you to SizableShrimp from the Forge Project discord! + * Java isn't my first programming language, so I didn't know you could collect and set up items like this! + * Makes setting up items for metals a breeze~ + */ + +package leaf.soulhome.registry; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.items.SoulHomeItemGroups; +import net.minecraft.block.Block; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.Rarity; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.function.Supplier; + +public class BlocksRegistry +{ + public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, SoulHome.MODID); + //public static final RegistryObject TEST_BLOCK = register("test_block", () -> (new BaseBlock(PropTypes.Blocks.EXAMPLE.get(), SoundType.STONE, 1F, 2F)), Rarity.COMMON); + + + private static RegistryObject register(String id, Supplier blockSupplier, Rarity itemRarity) + { + RegistryObject registryObject = BLOCKS.register(id, blockSupplier); + ItemsRegistry.ITEMS.register(id, () -> new BlockItem(registryObject.get(), new Item.Properties().tab(SoulHomeItemGroups.ITEMS).rarity(itemRarity))); + + + return registryObject; + } + +} diff --git a/src/main/java/leaf/soulhome/registry/ClientRegistry.java b/src/main/java/leaf/soulhome/registry/ClientRegistry.java new file mode 100644 index 0000000..38272a2 --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/ClientRegistry.java @@ -0,0 +1,27 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.registry; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.dimensions.SoulDimensionRenderInfo; +import leaf.soulhome.utils.ResourceLocationHelper; +import net.minecraft.client.world.DimensionRenderInfo; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; + +@Mod.EventBusSubscriber(value = Dist.CLIENT, modid = SoulHome.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class ClientRegistry +{ + public static final ResourceLocation SOUL_SKY_PROPERTY_LOC = ResourceLocationHelper.prefix("soul_sky_property"); + + @SubscribeEvent + public static void register(FMLClientSetupEvent event) + { + DimensionRenderInfo.EFFECTS.put(SOUL_SKY_PROPERTY_LOC, new SoulDimensionRenderInfo()); + } +} diff --git a/src/main/java/leaf/soulhome/registry/DataSerializersRegistry.java b/src/main/java/leaf/soulhome/registry/DataSerializersRegistry.java new file mode 100644 index 0000000..803d804 --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/DataSerializersRegistry.java @@ -0,0 +1,40 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.registry; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.IDataSerializer; +import net.minecraft.util.ResourceLocation; + +public class DataSerializersRegistry +{ + public static final IDataSerializer RESOURCE_LOCATION = new IDataSerializer() + { + + @Override + public void write(PacketBuffer buf, ResourceLocation value) + { + buf.writeResourceLocation(value); + } + + public ResourceLocation read(PacketBuffer buf) + { + return buf.readResourceLocation(); + } + + @Override + public ResourceLocation copy(ResourceLocation value) + { + return value; + } + }; + + public static void register() + { + DataSerializers.registerSerializer(RESOURCE_LOCATION); + } + +} diff --git a/src/main/java/leaf/soulhome/registry/DimensionRegistry.java b/src/main/java/leaf/soulhome/registry/DimensionRegistry.java new file mode 100644 index 0000000..3c28e5f --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/DimensionRegistry.java @@ -0,0 +1,166 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.registry; + +import com.google.common.collect.ImmutableList; +import com.mojang.serialization.Lifecycle; +import leaf.soulhome.SoulHome; +import leaf.soulhome.dimensions.SoulChunkGenerator; +import leaf.soulhome.network.Network; +import leaf.soulhome.network.SyncDimensionListMessage; +import leaf.soulhome.utils.DimensionHelper; +import leaf.soulhome.utils.LogHelper; +import net.minecraft.block.Blocks; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.DynamicRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.Dimension; +import net.minecraft.world.DimensionType; +import net.minecraft.world.World; +import net.minecraft.world.biome.BiomeManager; +import net.minecraft.world.border.IBorderListener; +import net.minecraft.world.chunk.listener.IChunkStatusListener; +import net.minecraft.world.gen.DimensionSettings; +import net.minecraft.world.gen.settings.DimensionGeneratorSettings; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.DerivedWorldInfo; +import net.minecraft.world.storage.IServerConfiguration; +import net.minecraft.world.storage.SaveFormat; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.WorldEvent; + +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.function.BiFunction; + +public class DimensionRegistry +{ + + + public static RegistryKey DIMENSION_NOISE_SETTINGS; + + public static class DimensionTypes + { + public static final RegistryKey SOUL_DIMENSION_TYPE = RegistryKey.create(Registry.DIMENSION_TYPE_REGISTRY, SoulHome.SOULHOME_LOC); + } + + public static void registerNoiseSettings() + { + DIMENSION_NOISE_SETTINGS = RegistryKey.create(Registry.NOISE_GENERATOR_SETTINGS_REGISTRY, SoulHome.SOULHOME_LOC); + } + + public static void registerChunkGenerators() + { + Registry.register(Registry.CHUNK_GENERATOR, SoulHome.SOULHOME_LOC, SoulChunkGenerator.providerCodec); + } + + public static Dimension soulDimensionBuilder(MinecraftServer server, RegistryKey dimensionKey) + { + DynamicRegistries registries = server.registryAccess(); + + return new Dimension( + () -> + { + try + { + return registries.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY).getOrThrow(DimensionTypes.SOUL_DIMENSION_TYPE); + } catch (Exception e) + { + LogHelper.error(e); + } + return null; + + }, + new SoulChunkGenerator(server)); + } + + + // Once a dimension is created using this method, it will load automatically on server boot + // Special thanks to the NewTardisMod team. This would have been a nightmare to figure out + // https://gitlab.com/Spectre0987/TardisMod-1-14/-/tree/1.16 + public static ServerWorld createSoulDimension(MinecraftServer server, RegistryKey worldKey) + { + RegistryKey dimensionKey = RegistryKey.create(Registry.LEVEL_STEM_REGISTRY, worldKey.location()); + + BiFunction, Dimension> dimensionFactory = DimensionRegistry::soulDimensionBuilder; + Dimension dimension = dimensionFactory.apply(server, dimensionKey); + + // Refer to META-INF/accesstransformer.cfg here for changing private fields to public + Executor executor = server.executor; + SaveFormat.LevelSave levelSave = server.storageSource; + IChunkStatusListener chunkStatusListener = server.progressListenerFactory.create(11); + + //configs + IServerConfiguration serverConfiguration = server.getWorldData(); + DimensionGeneratorSettings dimensionGeneratorSettings = serverConfiguration.worldGenSettings(); + + + // register the dimension + dimensionGeneratorSettings.dimensions().register( + dimensionKey, + dimension, + Lifecycle.stable() //experimental has issues apparently? Lets avoid that. + ); + + //base the world info on overworld? Not actually sure if that's what I want for soul dimensions + //todo revisit this later. Don't just forget about it. + DerivedWorldInfo derivedWorldInfo = new DerivedWorldInfo(serverConfiguration, serverConfiguration.overworldData()); + + ServerWorld newSoulWorld = new ServerWorld( + server, + executor, + levelSave, + derivedWorldInfo, + worldKey, + dimension.type(), + chunkStatusListener, + dimension.generator(), + dimensionGeneratorSettings.isDebug(), + BiomeManager.obfuscateSeed(dimensionGeneratorSettings.seed()), + ImmutableList.of(), + false); + + // pay attention to borders? + // why do we link the soul world borders to the over world borders? + // todo ask whether this is actually needed + server.getLevel(World.OVERWORLD).getWorldBorder().addListener(new IBorderListener.Impl(newSoulWorld.getWorldBorder())); + + // add the new dimension to the map, so that it auto loads on server boot. + // forgeGetWorldMap is marked as deprecated because you can + // screw up a lot of things if you mess with this map. + // So be very very careful when touching it. + Map, ServerWorld> map = server.forgeGetWorldMap(); + map.put(worldKey, newSoulWorld); + + // increment forge worldArrayMarker, so that the world will tick() + server.markWorldsDirty(); + + //then post an event for our new world. Welcome :) + MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(newSoulWorld)); + LogHelper.info("New soul dimension has been created: " + dimensionKey.location().toString()); + + //put in the platform + final int PLATFORM_RADIUS = 16; + for (int x = -PLATFORM_RADIUS; x < PLATFORM_RADIUS; x++) + { + for (int z = -PLATFORM_RADIUS; z < PLATFORM_RADIUS; z++) + { + newSoulWorld.setBlockAndUpdate(new BlockPos(x, DimensionHelper.FLOOR_LEVEL, z), Blocks.GRASS_BLOCK.defaultBlockState()); + newSoulWorld.setBlockAndUpdate(new BlockPos(x, DimensionHelper.FLOOR_LEVEL - 1, z), Blocks.DIRT.defaultBlockState()); + newSoulWorld.setBlockAndUpdate(new BlockPos(x, DimensionHelper.FLOOR_LEVEL - 2, z), Blocks.DIRT.defaultBlockState()); + newSoulWorld.setBlockAndUpdate(new BlockPos(x, DimensionHelper.FLOOR_LEVEL - 3, z), Blocks.DIRT.defaultBlockState()); + newSoulWorld.setBlockAndUpdate(new BlockPos(x, DimensionHelper.FLOOR_LEVEL - 4, z), Blocks.STONE.defaultBlockState()); + } + } + + //send a packet to all players, requesting that they refresh their dimension list. + Network.sendPacketToAll(new SyncDimensionListMessage(worldKey, true)); + + //finally return the new world so the player can finish teleporting there + return newSoulWorld; + } +} diff --git a/src/main/java/leaf/soulhome/registry/ItemsRegistry.java b/src/main/java/leaf/soulhome/registry/ItemsRegistry.java new file mode 100644 index 0000000..f8c573f --- /dev/null +++ b/src/main/java/leaf/soulhome/registry/ItemsRegistry.java @@ -0,0 +1,34 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + * Special thank you to SizableShrimp from the Forge Project discord! + * Java isn't my first programming language, so I didn't know you could collect and set up items like this! + * Makes setting up items for metals a breeze~ + */ + +package leaf.soulhome.registry; + + +import leaf.soulhome.SoulHome; +import leaf.soulhome.items.GuideItem; +import leaf.soulhome.items.SoulKeyItem; +import net.minecraftforge.fml.RegistryObject; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + + +public class ItemsRegistry +{ + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, SoulHome.MODID); + + //other items + + public static final RegistryObject SOUL_KEY = ITEMS.register("soulkey", () -> createItem(new SoulKeyItem())); + public static final RegistryObject GUIDE = ITEMS.register("guide", () -> createItem(new GuideItem())); + + + private static T createItem(T item) + { + return item; + } + +} diff --git a/src/main/java/leaf/soulhome/utils/CompoundNBTHelper.java b/src/main/java/leaf/soulhome/utils/CompoundNBTHelper.java new file mode 100644 index 0000000..8c6a462 --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/CompoundNBTHelper.java @@ -0,0 +1,259 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + * Thank you botania! Pretty much directly copied from botania as this is so much easier to work with! + */ + +package leaf.soulhome.utils; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.UUID; + +public final class CompoundNBTHelper +{ + + private static final int[] EMPTY_INT_ARRAY = new int[0]; + + + public static void set(CompoundNBT compoundTag, String tag, INBT nbt) + { + compoundTag.put(tag, nbt); + } + + public static void setBoolean(CompoundNBT compoundTag, String tag, boolean b) + { + compoundTag.putBoolean(tag, b); + } + + public static void setByte(CompoundNBT compoundTag, String tag, byte b) + { + compoundTag.putByte(tag, b); + } + + public static void setShort(CompoundNBT compoundTag, String tag, short s) + { + compoundTag.putShort(tag, s); + } + + public static void setInt(CompoundNBT compoundTag, String tag, int i) + { + compoundTag.putInt(tag, i); + } + + public static void setIntArray(CompoundNBT compoundTag, String tag, int[] val) + { + compoundTag.putIntArray(tag, val); + } + + public static void setIntArray(CompoundNBT compoundTag, String tag, List val) + { + compoundTag.putIntArray(tag, val); + } + + public static void setLong(CompoundNBT compoundTag, String tag, long l) + { + compoundTag.putLong(tag, l); + } + + public static void setFloat(CompoundNBT compoundTag, String tag, float f) + { + compoundTag.putFloat(tag, f); + } + + public static void setDouble(CompoundNBT compoundTag, String tag, double d) + { + compoundTag.putDouble(tag, d); + } + + public static void setCompound(CompoundNBT compoundTag, String tag, CompoundNBT cmp) + { + if (!tag.equalsIgnoreCase("ench")) // not override the enchantments + { + compoundTag.put(tag, cmp); + } + } + + public static void setString(CompoundNBT compoundTag, String tag, String s) + { + compoundTag.putString(tag, s); + } + + public static void setUuid(CompoundNBT compoundTag, String tag, UUID value) + { + compoundTag.putUUID(tag, value); + } + + public static void setList(CompoundNBT compoundTag, String tag, ListNBT list) + { + compoundTag.put(tag, list); + } + + public static void removeEntry(CompoundNBT compoundTag, String tag) + { + compoundTag.remove(tag); + } + + // GETTERS + + public static boolean verifyExistance(CompoundNBT compoundTag, String tag) + { + return compoundTag.contains(tag); + } + + @Nullable + public static INBT get(CompoundNBT compoundTag, String tag) + { + return verifyExistance(compoundTag, tag) ? compoundTag.get(tag) : null; + } + + public static boolean getBoolean(CompoundNBT compoundTag, String tag, boolean defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getBoolean(tag) : defaultExpected; + } + + public static byte getByte(CompoundNBT compoundTag, String tag, byte defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getByte(tag) : defaultExpected; + } + + public static short getShort(CompoundNBT compoundTag, String tag, short defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getShort(tag) : defaultExpected; + } + + public static int getInt(CompoundNBT compoundTag, String tag, int defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getInt(tag) : defaultExpected; + } + + public static int[] getIntArray(CompoundNBT compoundTag, String tag) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getIntArray(tag) : EMPTY_INT_ARRAY; + } + + public static long getLong(CompoundNBT compoundTag, String tag, long defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getLong(tag) : defaultExpected; + } + + public static float getFloat(CompoundNBT compoundTag, String tag, float defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getFloat(tag) : defaultExpected; + } + + public static double getDouble(CompoundNBT compoundTag, String tag, double defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getDouble(tag) : defaultExpected; + } + + /** + * If nullifyOnFail is true it'll return null if it doesn't find any + * compounds, otherwise it'll return a new one. + **/ + public static CompoundNBT getCompound(CompoundNBT compoundTag, String tag, boolean nullifyOnFail) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getCompound(tag) + : nullifyOnFail ? null + : (CompoundNBT) compoundTag.put(tag, new CompoundNBT()); + } + + public static CompoundNBT getOrCreateTag(CompoundNBT compoundTag, String tag) + { + if (!verifyExistance(compoundTag, tag)) + { + compoundTag.put(tag, new CompoundNBT()); + } + + return compoundTag.getCompound(tag); + } + + public static String getString(CompoundNBT compoundTag, String tag, String defaultExpected) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getString(tag) : defaultExpected; + } + + @Nullable + public static UUID getUuid(CompoundNBT compoundTag, String tag) + { + return verifyExistance(compoundTag, tag + "Most") && verifyExistance(compoundTag, tag + "Least") + ? compoundTag.getUUID(tag) : null; + } + + public static ListNBT getList(CompoundNBT compoundTag, String tag, int objtype, boolean nullifyOnFail) + { + return verifyExistance(compoundTag, tag) ? compoundTag.getList(tag, objtype) + : nullifyOnFail ? null : new ListNBT(); + } + + /** + * Returns true if the `target` tag contains all of the tags and values present in the `template` tag. Recurses into + * compound tags and matches all template keys and values; recurses into list tags and matches the template against + * the first elements of target. Empty lists and compounds in the template will match target lists and compounds of + * any size. + */ + public static boolean matchTag(@Nullable INBT template, @Nullable INBT target) + { + if (template instanceof CompoundNBT && target instanceof CompoundNBT) + { + return matchTagCompound((CompoundNBT) template, (CompoundNBT) target); + } + else if (template instanceof ListNBT && target instanceof ListNBT) + { + return matchTagList((ListNBT) template, (ListNBT) target); + } + else + { + return template == null || (target != null && target.equals(template)); + } + } + + private static boolean matchTagCompound(CompoundNBT template, CompoundNBT target) + { + if (template.size() > target.size()) + { + return false; + } + + for (String key : template.getAllKeys()) + { + if (!matchTag(template.get(key), target.get(key))) + { + return false; + } + } + + return true; + } + + private static boolean matchTagList(ListNBT template, ListNBT target) + { + if (template.size() > target.size()) + { + return false; + } + + for (int i = 0; i < template.size(); i++) + { + if (!matchTag(template.get(i), target.get(i))) + { + return false; + } + } + + return true; + } + + public static void renameTag(CompoundNBT nbt, String oldName, String newName) + { + INBT tag = nbt.get(oldName); + if (tag != null) + { + nbt.remove(oldName); + nbt.put(newName, tag); + } + } +} diff --git a/src/main/java/leaf/soulhome/utils/DimensionHelper.java b/src/main/java/leaf/soulhome/utils/DimensionHelper.java new file mode 100644 index 0000000..0486a55 --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/DimensionHelper.java @@ -0,0 +1,163 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.utils; + +import leaf.soulhome.SoulHome; +import leaf.soulhome.registry.DimensionRegistry; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3i; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.DimensionType; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +import java.util.ArrayList; +import java.util.List; + +import static leaf.soulhome.constants.Constants.NBTKeys.*; + +public class DimensionHelper +{ + public static final int FLOOR_LEVEL = 64; + + // Check if the user is in the soul dimension + // used for deciding if we are moving the player in or out of the dimension. + public static boolean isInSoulDimension(LivingEntity livingEntity) + { + //done by comparing the user's dimension to the soul dimension type. + return isDimensionOfType(livingEntity.getCommandSenderWorld(), DimensionRegistry.DimensionTypes.SOUL_DIMENSION_TYPE); + } + + public static boolean isDimensionOfType(World world, RegistryKey dimTypeKey) + { + // I think it has to be done this way since the soul dimension is not + // shared between players like it is in random things SpectreKey dimension + DimensionType type = world.registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY).get(dimTypeKey); + return type != null && type.equalTo(world.dimensionType()); + } + + // move the player to/from their soul dimension + public static void FlipDimension(PlayerEntity playerEntity, MinecraftServer server, List entitiesInRange) + { + //get (or create if this is the first time) our little save + CompoundNBT soulNBT = PlayerHelper.getPersistentTag(playerEntity, SoulHome.SOULHOME_LOC.toString()); + ServerWorld destination; + double x = 0.5d; + double y = FLOOR_LEVEL + 2; + double z = 0.5d; + + if (entitiesInRange == null) + { + entitiesInRange = new ArrayList(); + entitiesInRange.add(playerEntity); + } + + // move to the last saved place before player went to soul dimension + if (isInSoulDimension(playerEntity)) + { + //get the dimension key, based on the info we saved. + RegistryKey destinationKey = + RegistryKey.create( + Registry.DIMENSION_REGISTRY, + new ResourceLocation( + soulNBT.getString(LAST_DIMENSION_MOD_ID), + soulNBT.getString(LAST_DIMENSION_MOD_DIMENSION)) + ); + + //positioning + x = soulNBT.getDouble(LAST_DIMENSION_X); + y = soulNBT.getDouble(LAST_DIMENSION_Y); + z = soulNBT.getDouble(LAST_DIMENSION_Z); + + //then get the destination dimension by using that key. + try + { + destination = server.getLevel(destinationKey); + } + catch (Exception e)//sometimes people remove mods. Protect against unknown by sending them to overworld spawn. + { + destination = server.overworld(); + + final BlockPos sharedSpawnPos = destination.getSharedSpawnPos(); + x = sharedSpawnPos.getX(); + y = sharedSpawnPos.getY(); + z = sharedSpawnPos.getZ(); + } + } + // not in the soul, lets go there + else + { + //now we can go to the soul + //will create the dimension for that user if it's the first time accessing it + destination = getOrCreateSoulDimension(playerEntity.getStringUUID(), server); + + } + + //dimension location eg minecraft:overworld + ResourceLocation location = playerEntity.getCommandSenderWorld().dimension().location(); + + //then teleport everyone + for (Entity ent : entitiesInRange) + { + //if it's a player entity, save their last dimension position individually. + //helps them leave another player's soul. Nothing else can leave without help. + if (ent instanceof PlayerEntity && !isInSoulDimension((PlayerEntity) ent)) + { + soulNBT = PlayerHelper.getPersistentTag((PlayerEntity) ent, SoulHome.SOULHOME_LOC.toString()); + // XYZ + soulNBT.putDouble(LAST_DIMENSION_X, ent.getX()); + soulNBT.putDouble(LAST_DIMENSION_Y, ent.getY()); + soulNBT.putDouble(LAST_DIMENSION_Z, ent.getZ()); + + // save the dimension info + soulNBT.putString(LAST_DIMENSION_MOD_ID, location.getNamespace()); + soulNBT.putString(LAST_DIMENSION_MOD_DIMENSION, location.getPath()); + + } + + + Vector3d posRelativeToTeleporter = ent.position().subtract(playerEntity.position()); + Vector3d newPosByDestination = new Vector3d(x,y,z).add(posRelativeToTeleporter); + + + TeleportHelper.teleportEntity( + ent, + destination, + newPosByDestination.x, + y, + newPosByDestination.z, + playerEntity.getYHeadRot(), + playerEntity.xRot); + } + } + + private static ServerWorld getOrCreateSoulDimension(String userUUID, MinecraftServer server) + { + //we use the user's UUID as the dimension ID. + //There can only be one soul dimension per user + ResourceLocation loc = ResourceLocationHelper.prefix(userUUID); + + //the key used in the map, Map + //if we've already made the dimension, we can grab it straight from server.getLevel + RegistryKey worldKey = RegistryKey.create(Registry.DIMENSION_REGISTRY, loc); + + //check to find our special dimension + ServerWorld soulDimensionForPlayer = server.getLevel(worldKey); + + return soulDimensionForPlayer != null + ? soulDimensionForPlayer // Found it! return it. Otherwise make a new one + : DimensionRegistry.createSoulDimension(server, worldKey); + } + + +} diff --git a/src/main/java/leaf/soulhome/utils/EntityHelper.java b/src/main/java/leaf/soulhome/utils/EntityHelper.java new file mode 100644 index 0000000..8d4181f --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/EntityHelper.java @@ -0,0 +1,48 @@ +/* + * File created ~ 25 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.AxisAlignedBB; + +import java.util.List; + +public class EntityHelper +{ + public static List getLivingEntitiesInRange(LivingEntity selfEntity, int range, boolean includeSelf) + { + AxisAlignedBB areaOfEffect = new AxisAlignedBB(selfEntity.blockPosition()); + areaOfEffect = areaOfEffect.expandTowards(range, range, range); + + List entitiesFound = selfEntity.level.getEntitiesOfClass(LivingEntity.class, areaOfEffect); + + if (!includeSelf) + { + //removes self entity if it exists in the list + //otherwise list unchanged + entitiesFound.remove(selfEntity); + } + + return entitiesFound; + } + + public static List getEntitiesInRange(Entity entity, int range, boolean includeSelf) + { + AxisAlignedBB areaOfEffect = new AxisAlignedBB(entity.blockPosition()); + areaOfEffect = areaOfEffect.expandTowards(range, range, range); + + List entitiesFound = entity.level.getEntitiesOfClass(Entity.class, areaOfEffect); + + if (!includeSelf) + { + entitiesFound.remove(entity); + } + + return entitiesFound; + } + + +} diff --git a/src/main/java/leaf/soulhome/utils/ListHelper.java b/src/main/java/leaf/soulhome/utils/ListHelper.java new file mode 100644 index 0000000..52bbeea --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/ListHelper.java @@ -0,0 +1,19 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.utils; + +import java.util.Collection; +import java.util.Map; + +public class ListHelper +{ + public static boolean isNullOrEmpty( final Collection< ? > c ) { + return c == null || c.isEmpty(); + } + + public static boolean isNullOrEmpty( final Map< ?, ? > m ) { + return m == null || m.isEmpty(); + } +} diff --git a/src/main/java/leaf/soulhome/utils/LogHelper.java b/src/main/java/leaf/soulhome/utils/LogHelper.java new file mode 100644 index 0000000..943c84d --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/LogHelper.java @@ -0,0 +1,60 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import leaf.soulhome.SoulHome; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class LogHelper +{ + public static Logger LOGGER = LogManager.getLogger(SoulHome.MODID); + + public static void log(Level logLevel, Object object) + { + LOGGER.log(logLevel, String.valueOf(object)); + } + + public static void all(Object object) + { + log(Level.ALL, object); + } + + public static void debug(Object object) + { + log(Level.DEBUG, object); + } + + public static void error(Object object) + { + log(Level.ERROR, object); + } + + public static void fatal(Object object) + { + log(Level.FATAL, object); + } + + public static void info(Object object) + { + log(Level.INFO, object); + } + + public static void off(Object object) + { + log(Level.OFF, object); + } + + public static void trace(Object object) + { + log(Level.TRACE, object); + } + + public static void warn(Object object) + { + log(Level.WARN, object); + } +} \ No newline at end of file diff --git a/src/main/java/leaf/soulhome/utils/MathUtils.java b/src/main/java/leaf/soulhome/utils/MathUtils.java new file mode 100644 index 0000000..7b14e61 --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/MathUtils.java @@ -0,0 +1,50 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import java.util.Random; + +public class MathUtils +{ + final static Random rand = new Random(); + + public static int randomInt(int min, int max) + { + return rand.nextInt((max - min) + 1) + min; + } + + public static boolean randomBool() + { + return rand.nextBoolean(); + } + + + public static float clamp01(final float f) + { + return Math.max(0.0f, Math.min(1.0f, f)); + } + + + public static boolean inTriangle( + final double x1, + final double y1, + final double x2, + final double y2, + final double x3, + final double y3, + final double x, + final double y) + { + final double ab = (x1 - x) * (y2 - y) - (x2 - x) * (y1 - y); + final double bc = (x2 - x) * (y3 - y) - (x3 - x) * (y2 - y); + final double ca = (x3 - x) * (y1 - y) - (x1 - x) * (y3 - y); + return sign(ab) == sign(bc) && sign(bc) == sign(ca); + } + + public static int sign(final double n) + { + return n > 0 ? 1 : -1; + } +} diff --git a/src/main/java/leaf/soulhome/utils/PlayerHelper.java b/src/main/java/leaf/soulhome/utils/PlayerHelper.java new file mode 100644 index 0000000..b86336b --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/PlayerHelper.java @@ -0,0 +1,29 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.server.MinecraftServer; + +import java.util.UUID; + +import static net.minecraft.entity.player.PlayerEntity.PERSISTED_NBT_TAG; + +public class PlayerHelper +{ + public static String getPlayerName(UUID id, MinecraftServer server) + { + GameProfile profileByUUID = server.getProfileCache().get(id); + return profileByUUID != null ? profileByUUID.getName() : "OFFLINE Player"; + } + + public static CompoundNBT getPersistentTag(PlayerEntity playerEntity, String tag) + { + CompoundNBT persistentNBT = CompoundNBTHelper.getOrCreateTag(playerEntity.getPersistentData(), PERSISTED_NBT_TAG); + return CompoundNBTHelper.getOrCreateTag(persistentNBT, tag); + } +} diff --git a/src/main/java/leaf/soulhome/utils/ResourceLocationHelper.java b/src/main/java/leaf/soulhome/utils/ResourceLocationHelper.java new file mode 100644 index 0000000..34ff51b --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/ResourceLocationHelper.java @@ -0,0 +1,18 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import leaf.soulhome.SoulHome; +import net.minecraft.util.ResourceLocation; + +import java.util.Locale; + +public class ResourceLocationHelper +{ + public static ResourceLocation prefix(String path) + { + return new ResourceLocation(SoulHome.MODID, path.toLowerCase(Locale.ROOT)); + } +} diff --git a/src/main/java/leaf/soulhome/utils/StringHelper.java b/src/main/java/leaf/soulhome/utils/StringHelper.java new file mode 100644 index 0000000..ba751e6 --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/StringHelper.java @@ -0,0 +1,19 @@ +/* + * File created ~ 13 - 7 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import java.util.Arrays; +import java.util.stream.Collectors; + +public class StringHelper +{ + + public static String fixCapitalisation(String text) + { + String original = text.trim().replace(" ", "").replace("_", " ").replace("/", "."); + String output = Arrays.stream(original.split("\\s+")).map(t -> t.substring(0, 1).toUpperCase() + t.substring(1)).collect(Collectors.joining(" ")); + return output; + } +} diff --git a/src/main/java/leaf/soulhome/utils/TeleportHelper.java b/src/main/java/leaf/soulhome/utils/TeleportHelper.java new file mode 100644 index 0000000..ec6fe21 --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/TeleportHelper.java @@ -0,0 +1,131 @@ +/* + * File created ~ 27 - 1 - 2022 ~Leaf + */ + +package leaf.soulhome.utils; + +import net.minecraft.entity.CreatureEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.play.server.SPlayEntityEffectPacket; +import net.minecraft.network.play.server.SPlayerAbilitiesPacket; +import net.minecraft.network.play.server.SServerDifficultyPacket; +import net.minecraft.network.play.server.SSetExperiencePacket; +import net.minecraft.potion.EffectInstance; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.server.TicketType; +import net.minecraft.world.storage.IWorldInfo; + +public class TeleportHelper +{ + public static void teleportEntity(Entity entity, ServerWorld destinationDimension, double x, double y, double z, float yRot, float xRot) + { + if (entity == null || entity.level.isClientSide || !entity.canChangeDimensions()) + { + return; + } + + ServerWorld currentDimension = entity.getServer().getLevel(entity.getCommandSenderWorld().dimension()); + + + boolean isChangingDimension = !currentDimension.dimension().location().equals(destinationDimension.dimension().location()); + final boolean entityIsPlayer = entity instanceof ServerPlayerEntity; + final ServerPlayerEntity serverPlayerEntity = entityIsPlayer ? (ServerPlayerEntity) entity : null; + + if (isChangingDimension && !entity.canChangeDimensions()) + { + //early exit + return; + } + + //no passengers allowed. + if (entity.isPassenger()) + { + entity.getRootVehicle().unRide(); + } + + + //This section is mostly copied and then modified from TeleportCommand.performTeleport() + if (entityIsPlayer) + { + ChunkPos chunkPos = new ChunkPos(new BlockPos(x, y, z)); + destinationDimension.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, chunkPos, 1, entity.getId()); + entity.stopRiding(); + if (serverPlayerEntity.isSleeping()) + { + serverPlayerEntity.stopSleepInBed(true, true); + } + + if (isChangingDimension) + { + serverPlayerEntity.teleportTo(destinationDimension, x, y, z, yRot, xRot); + } + else + { + serverPlayerEntity.connection.teleport(x, y, z, yRot, xRot); + } + + serverPlayerEntity.setYHeadRot(yRot); + + //restore stuff. Annoyingly it doesn't happen automatically + for (EffectInstance effectinstance : serverPlayerEntity.getActiveEffects()) + { + serverPlayerEntity.connection.send(new SPlayEntityEffectPacket(serverPlayerEntity.getId(), effectinstance)); + } + + IWorldInfo worldInfo = serverPlayerEntity.level.getLevelData(); + //I'd always wondered what the deal was with xp not showing properly. + serverPlayerEntity.connection.send(new SPlayerAbilitiesPacket(serverPlayerEntity.abilities)); + serverPlayerEntity.connection.send(new SServerDifficultyPacket(worldInfo.getDifficulty(), worldInfo.isDifficultyLocked())); + serverPlayerEntity.connection.send(new SSetExperiencePacket(serverPlayerEntity.experienceProgress, serverPlayerEntity.totalExperience, serverPlayerEntity.experienceLevel)); + } + else + { + float entityYRot = MathHelper.wrapDegrees(yRot); + float entityXRot = MathHelper.wrapDegrees(xRot); + entityXRot = MathHelper.clamp(entityXRot, -90.0F, 90.0F); + if (isChangingDimension) + { + Entity originalEntity = entity; + entity = originalEntity.getType().create(destinationDimension); + if (entity == null) + { + //error + LogHelper.error("Was unable to create an entity when trying to teleport it."); + return; + } + entity.restoreFrom(originalEntity); + entity.moveTo(x, y, z, entityYRot, entityXRot); + entity.setYHeadRot(entityYRot); + + currentDimension.despawn(originalEntity); + + destinationDimension.addFromAnotherDimension(entity); + + currentDimension.resetEmptyTime(); + destinationDimension.resetEmptyTime(); + } + else + { + entity.moveTo(x, y, z, entityYRot, entityXRot); + entity.setYHeadRot(entityYRot); + } + } + + //not sure if I care about elytra, SO todo decide later. might be fun to let them keep flying? + if (!(entity instanceof LivingEntity) || !((LivingEntity) entity).isFallFlying()) + { + entity.setDeltaMovement(entity.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); + entity.setOnGround(true); + } + + if (entity instanceof CreatureEntity) + { + ((CreatureEntity) entity).getNavigation().stop(); + } + } +} diff --git a/src/main/java/leaf/soulhome/utils/TextHelper.java b/src/main/java/leaf/soulhome/utils/TextHelper.java new file mode 100644 index 0000000..29169ab --- /dev/null +++ b/src/main/java/leaf/soulhome/utils/TextHelper.java @@ -0,0 +1,63 @@ +/* + * File created ~ 24 - 4 - 2021 ~ Leaf + */ + +package leaf.soulhome.utils; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.util.text.event.ClickEvent; +import net.minecraft.util.text.event.HoverEvent; +import net.minecraft.world.server.ServerWorld; + +import java.util.UUID; + +public class TextHelper +{ + public static TextComponent getPlayerTextObject(ServerWorld world, UUID id) + { + return getPlayerTextObject(world.getServer(), id); + } + + public static TextComponent getPlayerTextObject(MinecraftServer server, UUID id) + { + String playerName = PlayerHelper.getPlayerName(id, server); + return createTextComponentWithTip(playerName, id.toString()); + } + + public static TextComponent createTextComponentWithTip(String text, String tooltipText) + { + //Always surround tool tip items with brackets + TextComponent textComponent = new StringTextComponent("[" + text + "]"); + textComponent.withStyle(style -> + { + return style.applyFormat(TextFormatting.GREEN)//color tool tip items green + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent(tooltipText))).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, tooltipText)); + }); + return textComponent; + } + + public static TextComponent createTextWithTooltip(TranslationTextComponent translation, TranslationTextComponent description) + { + //Always surround tool tip items with brackets + translation.withStyle(style -> + { + return style.applyFormat(TextFormatting.GREEN)//color tool tip items green + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, description)).withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, translation.getKey())); + }); + return translation; + } + + public static TextComponent createTranslatedText(String s, Object... a) + { + return new TranslationTextComponent(s, a); + } + + public static TextComponent createText(Object s) + { + return new StringTextComponent(s.toString()); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..dc2c7de --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,4 @@ +public-f net.minecraft.client.world.DimensionRenderInfo field_239208_a_ #SKY_PROPERTIES +public net.minecraft.server.MinecraftServer field_213220_d # chunkStatusListenerFactory +public net.minecraft.server.MinecraftServer field_213217_au # backgroundExecutor +public net.minecraft.server.MinecraftServer field_71310_m # anvilConverterForAnvilFile \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..86d2bdf --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,61 @@ +# This is an example mods.toml file. It contains the data relating to the loading mods. +# There are several mandatory fields (#mandatory), and many more that are optional (#optional). +# The overall format is standard TOML format, v0.5.0. +# Note that there are a couple of TOML lists in this file. +# Find more information on toml format here: https://github.com/toml-lang/toml +# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml +modLoader="javafml" #mandatory +# A version range to match for said mod loader - for regular FML @Mod it will be the forge version +loaderVersion="[36,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. +# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. +license="All rights reserved" +# A URL to refer people to when problems occur with this mod +#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] #mandatory +# The modid of the mod +modId="soulhome" #mandatory +# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it +# ${file.jarVersion} will substitute the value of the Implementation-Version as read from the mod's JAR file metadata +# see the associated build.gradle script for how to populate this completely automatically during a build +version="${version}" #mandatory + # A display name for the mod +displayName="SoulHome" #mandatory +# A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ +#updateJSONURL="https://change.me.example.invalid/updates.json" #optional +# A URL for the "homepage" for this mod, displayed in the mod UI +#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional +# A file name (in the root of the mod JAR) containing a logo for display +logoFile="soulhome.png" #optional +# A text field displayed in the mod UI +credits="Thanks for this example mod goes to Java" #optional +# A text field displayed in the mod UI +authors="Leaf Reynolds" #optional +# The description text for the mod (multi line!) (#mandatory) +description=''' +This is a long form description of the mod. You can write whatever you want here + +Have some lorem ipsum. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis lacinia magna. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed sagittis luctus odio eu tempus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque volutpat ligula eget lacus auctor sagittis. In hac habitasse platea dictumst. Nunc gravida elit vitae sem vehicula efficitur. Donec mattis ipsum et arcu lobortis, eleifend sagittis sem rutrum. Cras pharetra quam eget posuere fermentum. Sed id tincidunt justo. Lorem ipsum dolor sit amet, consectetur adipiscing elit. +''' +# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. +[[dependencies.soulhome]] #optional + # the modid of the dependency + modId="forge" #mandatory + # Does this dependency have to exist - if not, ordering below must be specified + mandatory=true #mandatory + # The version range of the dependency + versionRange="[36,)" #mandatory + # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory + ordering="NONE" + # Side this dependency is applied on - BOTH, CLIENT or SERVER + side="BOTH" + +[[dependencies.soulhome]] + modId="minecraft" + mandatory=true + versionRange="[1.16.4, 1.16.5]" + ordering="NONE" + side="BOTH" diff --git a/src/main/resources/assets/soulhome/textures/block/test_block.png b/src/main/resources/assets/soulhome/textures/block/test_block.png new file mode 100644 index 0000000000000000000000000000000000000000..57870e4e80451a9bca127fedd35765b799d02030 GIT binary patch literal 3087 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/soulhome/textures/item/guide.png b/src/main/resources/assets/soulhome/textures/item/guide.png new file mode 100644 index 0000000000000000000000000000000000000000..f7461e14c0f36b2240657edd96daf9190c958da5 GIT binary patch literal 4205 zcmV-z5R&hSP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000G;Nklzgd!hxwPML$l%~$2+(S^$mjDoj>FW{l-S9$;#XTRI5-$~Ivsj@dkKO7(=>5i zm&L_JUcGuH{t*JzYBlsc4=E+x-Q6gqSYBQxlgS{2Kq*DL-NtoY#>dCSZzC``I2am+ zfl>+p+qMDleVCK3rO%R)*?DwQG#0suVE z!!Qh@bA z3G4Mbj^og3wFrWMR4Rp(l3$$>QJZ|hYlTzGwb_4LWo$x&C%QL@a-xHf-NbLQlgY%VPS!G zyN%;G|MP$lf=ib!ar*RWQmGUxD=Vz5tl&5f?RJ|m41d@UQ46EwNGX|{o1@umGCVwt zloHogQHT#jO~$h~{_NG6j2jEs!1wzh`jIBaZe5Cp-t1fmuML4fCZ zapnOW$6;=6j#{mTX_{QVe3^xX1x}tkNnc+dLI?_lLMVEAdH}*=v50NkoH%iUWHQO@ z>@3fpKPR0|W11%EbUFr%qNSADG97*2r(Une)AR7*!;FlK&}cNM)oSeCy_s$J(>pEc=vcA4ftyW`g zZH-c?#KD6HNvG4CKYyMVFJ4e66zJ*c;o-xFJbU(xiHQmRoIhV%gb1n#mvkMqoboF5()0yxf3reN~tZtf4dJvBnpKBsZ@%g zp&=~G;?t*3Jb3VcqeqW&{rYum+eXtg-oJkjK!1Nfw{G3y?%lhruCCH-Hn+X;j<@2E zA3stmm3aB`C6!8rfq?-4u3o*0WmzPXNv5Wz&~=>~H*QcamwEj7F+zwKJnHig?}U*G zy}iBozR&*s`#FC6IHyjXqS0tz7)C7n#ful?VfE$9mmLHDUj^Fjwp>_P2#UobZ{ED2 zR4VcA-8){te$A01M>uol45?I#OeRAl@s9xSXer(72g5Kpd-g21Z{H@7NMM>Ki;Igt z4ZP#6cyl{k*G1R$U%K&6t>qDkZ->b5DDj_vJN{z;Cz8~3ZG4WP00000NkvXXu0mjf DxI*KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0003hNkluP@DtMa0D(x!2u{~abqpAg|dniOO{Itju3Goj)25Z zIaZ8fJsNgN6rvcIYIimB=Dm5dP7?nLNk}4upkWvk?_+=^k&4Ys!!XFq^qc0X*vu4J zj0KUz1aJUt+foz-Wmz(t%^1xjgn*e58JHQ~du=wGqfF8a%q&X5%mDD-@5$L7a2j+x z#NrS_>aY#+Q?VpYVshKINm7iaX&j)suIai?F$Z8ipF02-{dUeB)at!gUDrErWmy8a z$(SVrSg+Sy-xpjy-T?3gsL2?o`o0I?_5F?0muUjo>vD)ep66-VF7B>mX3FziagoM^ ztEvis)$Id|#eyu$=(_IPg=3#*xm>!cs+46JPt#|2{&B{R3xAEz0RT&)9xStpNDBY} N002ovPDHLkV1o9ew7>uW literal 0 HcmV?d00001 diff --git a/src/main/resources/data/soulhome/dimension_type/soulhome.json b/src/main/resources/data/soulhome/dimension_type/soulhome.json new file mode 100644 index 0000000..c136440 --- /dev/null +++ b/src/main/resources/data/soulhome/dimension_type/soulhome.json @@ -0,0 +1,19 @@ +{ + "name": "soulhome:soulhome", + "effects": "soulhome:soul_sky_property", + "infiniburn": "minecraft:infiniburn_overworld", + "min_y": 0, + "height": 256, + "logical_height": 256, + "natural": true, + "piglin_safe": true, + "coordinate_scale": 1.0, + "bed_works": true, + "has_skylight": true, + "has_ceiling": false, + "ultrawarm": false, + "has_raids": false, + "respawn_anchor_works": true, + "ambient_light": 0.8, + "fixed_time": 6000 +} \ No newline at end of file diff --git a/src/main/resources/data/soulhome/patchouli_books/guide/book.json b/src/main/resources/data/soulhome/patchouli_books/guide/book.json new file mode 100644 index 0000000..f919236 --- /dev/null +++ b/src/main/resources/data/soulhome/patchouli_books/guide/book.json @@ -0,0 +1,25 @@ +{ + "name": "item.soulhome.guide", + + "landing_text": "soulhome.landing", + "version": "buildNumber", + + "book_texture": "patchouli:textures/gui/book_gray.png", + "model": "soulhome:guide", + + "creative_tab": "soulhome.items", + "pause_game": true, + + "dont_generate_book": true, + "custom_book_item": "soulhome:guide", + + "advancements_tab": "soulhome:core/root", + "advancement_namespaces": ["soulhome"], + + "i18n": true, + + "macros": { + "$(item)": "$(1)", + "$(thing)": "$(4)" + } +} \ No newline at end of file diff --git a/src/main/resources/data/soulhome/worldgen/biome/soulhome.json b/src/main/resources/data/soulhome/worldgen/biome/soulhome.json new file mode 100644 index 0000000..0465ca5 --- /dev/null +++ b/src/main/resources/data/soulhome/worldgen/biome/soulhome.json @@ -0,0 +1,27 @@ +{ + "scale": 1.0, + "effects": { + "mood_sound": { + "sound": "minecraft:ambient.cave", + "tick_delay": 6000, + "block_search_extent": 8, + "offset": 2.0 + }, + "sky_color": 7907327, + "fog_color": 12638463, + "water_color": 4159204, + "water_fog_color": 329011 + }, + "surface_builder": "nope", + "carvers": {}, + "features": [], + "starts": [], + "spawners": {}, + "spawn_costs": {}, + "player_spawn_friendly": true, + "precipitation": "none", + "temperature": 0.5, + "downfall": 0.4, + "category": "none", + "depth": 0.125 +} \ No newline at end of file diff --git a/src/main/resources/data/soulhome/worldgen/noise_settings/soulhome.json b/src/main/resources/data/soulhome/worldgen/noise_settings/soulhome.json new file mode 100644 index 0000000..ce32ebd --- /dev/null +++ b/src/main/resources/data/soulhome/worldgen/noise_settings/soulhome.json @@ -0,0 +1,49 @@ +{ + "bedrock_roof_position": -2147483648, + "bedrock_floor_position": 0, + "sea_level": 63, + "disable_mob_generation": true, + "structures": { + "stronghold": { + "distance": 0, + "spread": 0, + "count": 0 + }, + "structures": {} + }, + "noise": { + "simplex_surface_noise": true, + "random_density_offset": true, + "size_vertical": 2, + "density_factor": 1.0, + "density_offset": -0.46875, + "top_slide": { + "target": -10, + "size": 3, + "offset": 0 + }, + "bottom_slide": { + "target": -30, + "size": 0, + "offset": 0 + }, + "size_horizontal": 1, + "min_y": 0, + "height": 256, + "sampling": { + "xz_scale": 0.9999999814507745, + "y_scale": 0.9999999814507745, + "xz_factor": 80.0, + "y_factor": 160.0 + } + }, + "default_block": { + "Name": "minecraft:stone" + }, + "default_fluid": { + "Properties": { + "level": "0" + }, + "Name": "minecraft:water" + } +} \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..a533a48 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "SoulHome Mod Resources", + "pack_format": 6, + "_comment": "Default SoulHome Mod Resources" + } +} diff --git a/src/main/resources/soulhome.mixins.json b/src/main/resources/soulhome.mixins.json new file mode 100644 index 0000000..fede38e --- /dev/null +++ b/src/main/resources/soulhome.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "leaf.soulhome.mixin", + "compatibilityLevel": "JAVA_8", + "refmap": "soulhome.refmap.json", + "mixins": [ + ], + "client": [ + "EffectInstanceMixin", + "EntityMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file