diff --git a/.github/workflows/ci-tests-nightly.yml b/.github/workflows/ci-tests-nightly.yml new file mode 100644 index 00000000..46f47c05 --- /dev/null +++ b/.github/workflows/ci-tests-nightly.yml @@ -0,0 +1,91 @@ +name: Gradle Tests and Nightly (CI) + +on: push + +jobs: + vars: + name: Get Variables + runs-on: ubuntu-20.04 + outputs: + release_type: ${{steps.cf_release_type.outputs.value }} + mod_version: ${{steps.mod_version.outputs.value }} + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Release Type + id: cf_release_type + uses: christian-draeger/read-properties@1.0.1 + with: + path: './gradle.properties' + property: 'cf_release_type' + + - name: Mod Version + id: mod_version + uses: christian-draeger/read-properties@1.0.1 + with: + path: './gradle.properties' + property: 'mod_version' + + tests: + name: Gradle Tests + runs-on: ubuntu-20.04 + needs: [ vars ] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up JDK 8 + uses: actions/setup-java@v1 + with: + java-version: "8.0.282" + + - name: Cache Gradle packages + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Test JAR with Gradle + run: ./gradlew test + env: + GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + nightly: + name: Publish Nightly + runs-on: ubuntu-20.04 + needs: [ vars, tests ] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up JDK 8 + uses: actions/setup-java@v1 + with: + java-version: "8.0.282" + + - name: Cache Gradle packages + uses: actions/cache@v2 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Publish gradle nightly jar + run: ./gradlew publishNightlyMavenPublicationToGitHubPackagesRepository + env: + CM_RELEASE: false + GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml deleted file mode 100644 index 56d5ac19..00000000 --- a/.github/workflows/ci-tests.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Gradle Tests (CI) - -on: push - -jobs: - vars: - name: Get Variables - runs-on: ubuntu-20.04 - outputs: - release_type: ${{steps.cf_release_type.outputs.value }} - mod_version: ${{steps.mod_version.outputs.value }} - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Release Type - id: cf_release_type - uses: christian-draeger/read-properties@1.0.1 - with: - path: './gradle.properties' - property: 'cf_release_type' - - - name: Mod Version - id: mod_version - uses: christian-draeger/read-properties@1.0.1 - with: - path: './gradle.properties' - property: 'mod_version' - - jar: - name: Publish JAR - runs-on: ubuntu-20.04 - needs: [vars] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up JDK 8 - uses: actions/setup-java@v1 - with: - java-version: "8.0.282" - - - name: Test JAR with Gradle - run: ./gradlew test - env: - GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual-build.yml b/.github/workflows/manual-build.yml index b5d19174..b01cb696 100644 --- a/.github/workflows/manual-build.yml +++ b/.github/workflows/manual-build.yml @@ -115,11 +115,8 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Gradle Dependencies - run: ./gradlew --refresh-dependencies - - name: Build JAR with Gradle - run: ./gradlew build + run: ./gradlew build --max-workers 1 env: GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual-gh-packages.yml b/.github/workflows/manual-gh-packages.yml index 784c1ad9..f38fec4e 100644 --- a/.github/workflows/manual-gh-packages.yml +++ b/.github/workflows/manual-gh-packages.yml @@ -117,8 +117,9 @@ jobs: run: chmod +x gradlew - name: Publish JAR with Gradle - run: ./gradlew publish + run: ./gradlew publish -x test env: + CM_RELEASE: true GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/tagged-release.yml b/.github/workflows/tagged-release.yml index eb56a41a..e9a35e3a 100644 --- a/.github/workflows/tagged-release.yml +++ b/.github/workflows/tagged-release.yml @@ -119,8 +119,9 @@ jobs: run: chmod +x gradlew - name: Publish package - run: ./gradlew publish + run: ./gradlew publish -x test env: + CM_RELEASE: true GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -205,9 +206,7 @@ jobs: java-version: "8.0.282" - name: Build JAR with Gradle - uses: eskatos/gradle-command-action@v1 - with: - arguments: build + run: ./gradlew build --max-workers 1 env: GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7c73c0ce..e51a7c00 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ forge*changelog.txt logs/ /mods/ /build-out/ + +*.dot diff --git a/build.gradle b/build.gradle index b9f269e3..3ddb904b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,11 @@ buildscript { repositories { maven { url = 'https://files.minecraftforge.net/maven' } - jcenter() mavenCentral() } dependencies { - classpath "net.minecraftforge.gradle:ForgeGradle:4.0.23" + classpath "net.minecraftforge.gradle:ForgeGradle:4.1.12" } } @@ -18,18 +17,38 @@ plugins { apply plugin: "net.minecraftforge.gradle" -version = "${mod_version}" -group = 'com.robotgryphon' // http://maven.apache.org/guides/mini/guide-naming-conventions.html +def gitCommitHash = 'git rev-parse --verify --short HEAD'.execute().text.trim() +def isRelease = (System.getenv("CM_RELEASE") ?: "false").equalsIgnoreCase("true") + +version = isRelease ? mod_version : "nightly-${gitCommitHash}" +group = "dev.compactmods" archivesBaseName = mod_id +println("Mod ID: ${mod_id}"); +println("Version: ${version}"); + sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. sourceSets { + api { + java { + srcDir "src/api/java" + } + compileClasspath += configurations.getByName("minecraft") + } + main { + java { + srcDir "src/api/java" + srcDir "src/main/java" + } + resources { + srcDir "src/main/resources" srcDir 'src/generated/resources' } } + test } @@ -38,7 +57,7 @@ minecraft { mappings channel: 'official', version: mappings_version // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. - // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Default run configurations. // These can be tweaked, removed, or duplicated as needed. @@ -52,6 +71,9 @@ minecraft { // Recommended logging level for the console property 'forge.logging.console.level', 'debug' + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg" + args '--username', 'Dev##' mods { @@ -70,6 +92,9 @@ minecraft { // Recommended logging level for the console property 'forge.logging.console.level', 'debug' + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg" + mods { compactmachines { source sourceSets.main @@ -86,7 +111,13 @@ minecraft { // Recommended logging level for the console property 'forge.logging.console.level', 'debug' - args '--mod', 'compactmachines', '--existing', file('src/main/resources'), '--all', '--output', file('src/generated/resources/') + property 'mixin.env.remapRefMap', 'true' + property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg" + + args '--mod', mod_id + args '--existing', file('src/main/resources') + args '--all' + args '--output', file('src/generated/resources/') mods { compactmachines { @@ -94,6 +125,29 @@ minecraft { } } } + + unitTests { + parent runs.server // This run config inherits settings from the server config + workingDirectory project.file('run/test') + main 'com.alcatrazescapee.mcjunitlib.DedicatedTestServerLauncher' + // The main class which launches a customized server which then runs JUnit tests + ideaModule "${project.name}.test" // Tell IDEA to use the classpath of the test module + property 'forge.logging.console.level', 'unittest' + // This logging level prevents any other server information messages and leaves only the unit test output + environment 'MOD_CLASSES', String.join(File.pathSeparator, + "${mod_id}%%${sourceSets.main.output.resourcesDir}", + "${mod_id}%%${sourceSets.main.output.classesDirs[0]}", + "${mod_id}%%${sourceSets.test.output.resourcesDir}", + "${mod_id}%%${sourceSets.test.output.classesDirs[0]}", + ) // Forge will ignore all test sources unless we explicitly tell it to include them as mod sources + environment 'target', 'fmltestserver' + // This is a custom service used to launch with ModLauncher's transforming class loader + mods { + compactmachines { // The mod that is being tested - Replace this with your mod ID! + sources sourceSets.api, sourceSets.main + } + } + } } } @@ -129,6 +183,9 @@ def getModVersion(filename) { def dev_mods_dir = "mods" +task("dev") { + println(sourceSets.main.output.classesDirs[0]); +} repositories { // Built mods flatDir { @@ -146,6 +203,20 @@ repositories { name 'tterrag maven' url "http://maven.tterrag.com/" } + + // Unit Tests + maven { + name 'MCUnitTests' + url 'https://jitpack.io' + } + + // Curseforge stuff + maven { + url "https://cursemaven.com" + content { + includeGroup "curse.maven" + } + } } def dev_mods = fileTree(dev_mods_dir).filter { it -> it.isFile() }.files.name.collect({ getModVersion(it) }) @@ -156,11 +227,10 @@ dependencies { // The userdev artifact is a special name and will get all sorts of transformations applied to it. minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" + // Deobfuscate each dev mod for runtime - dev_mods.each { - compileOnly fg.deobf(it) - runtimeOnly fg.deobf(it) - } + dev_mods.each { implementation(fg.deobf(it)) } + // JEI compileOnly fg.deobf("mezz.jei:jei-${jei_mc_version}:${jei_version}:api") @@ -170,11 +240,22 @@ dependencies { compileOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-1.16:${top_version}:api") runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-1.16:${top_version}") + testImplementation(fg.deobf("com.github.alcatrazEscapee:mcjunitlib:1.3.3-${minecraft_version}")) + + // Nicephore - Screenshots and Stuff + runtimeOnly(fg.deobf("curse.maven:nicephore-401014:3318114")) + + // Mekanism + Mek Generators - Tunnel testing + runtimeOnly(fg.deobf("curse.maven:mekanism-268560:3206392")) + runtimeOnly(fg.deobf("curse.maven:mekanismgenerators-268566:3206395")) } // Example for how to get properties into the manifest for reading by the runtime.. jar { + from sourceSets.api.output + from sourceSets.main.output destinationDirectory = file("$rootDir/build-out") + finalizedBy('reobfJar') manifest { attributes([ @@ -182,7 +263,7 @@ jar { "Specification-Vendor" : "", "Specification-Version" : "1", // We are version 1 of ourselves "Implementation-Title" : project.name, - "Implementation-Version" : "${archiveVersion}", + "Implementation-Version" : isRelease ? archiveVersion : "nightly-${gitCommitHash}", "Implementation-Vendor" : "", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") ]) @@ -190,10 +271,8 @@ jar { } task apiJar(type: Jar) { + from sourceSets.api.output // Sources included because of MinecraftForge/ForgeGradle#369 - from(sourceSets.main.allJava) - from(sourceSets.main.output) - include 'com/robotgryphon/compactmachines/api/**' archiveClassifier = 'api' destinationDirectory = file("$rootDir/build-out") } @@ -213,6 +292,18 @@ publishing { } } } + + nightlyMaven(MavenPublication) { + artifactId = mod_id + artifacts { + artifact(jar) { + group = "dev.compactmods.nightly" + } + artifact(apiJar) { + classifier = "api" + } + } + } } repositories { @@ -227,3 +318,9 @@ publishing { } } } + +test { + useJUnitPlatform { + excludeTags "minecraft" + } +} diff --git a/gradle.properties b/gradle.properties index f15d63dd..33e0e741 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,9 +11,9 @@ mod_id=compactmachines mod_version=4.0.0-beta.2 # Dependencies and Libs -jei_mc_version=1.16.4 -jei_version=7.6.1.71 -top_version=1.16-3.0.7-13 +jei_mc_version=1.16.5 +jei_version=7.7.1.110 +top_version=1.16-3.1.4-22 # Curseforge cf_project=224218 diff --git a/src/api/java/dev/compactmods/machines/api/core/Advancements.java b/src/api/java/dev/compactmods/machines/api/core/Advancements.java new file mode 100644 index 00000000..d5a2569e --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/core/Advancements.java @@ -0,0 +1,18 @@ +package dev.compactmods.machines.api.core; + +import net.minecraft.util.ResourceLocation; + +public class Advancements { + public static final ResourceLocation HOW_DID_YOU_GET_HERE = new ResourceLocation(Constants.MOD_ID, "how_did_you_get_here"); + public static final ResourceLocation ROOT = new ResourceLocation(Constants.MOD_ID, "root"); + public static final ResourceLocation FOUNDATIONS = new ResourceLocation(Constants.MOD_ID, "foundations"); + + public static final ResourceLocation GOT_SHRINKING_DEVICE = new ResourceLocation(Constants.MOD_ID, "got_shrinking_device"); + + public static final ResourceLocation CLAIMED_TINY_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_tiny"); + public static final ResourceLocation CLAIMED_SMALL_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_small"); + public static final ResourceLocation CLAIMED_NORMAL_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_normal"); + public static final ResourceLocation CLAIMED_LARGE_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_large"); + public static final ResourceLocation CLAIMED_GIANT_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_giant"); + public static final ResourceLocation CLAIMED_MAX_MACHINE = new ResourceLocation(Constants.MOD_ID, "claimed_machine_max"); +} diff --git a/src/api/java/dev/compactmods/machines/api/core/Constants.java b/src/api/java/dev/compactmods/machines/api/core/Constants.java new file mode 100644 index 00000000..954065b4 --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/core/Constants.java @@ -0,0 +1,5 @@ +package dev.compactmods.machines.api.core; + +public abstract class Constants { + public static final String MOD_ID = "compactmachines"; +} diff --git a/src/api/java/dev/compactmods/machines/api/core/JeiInfo.java b/src/api/java/dev/compactmods/machines/api/core/JeiInfo.java new file mode 100644 index 00000000..e3976fef --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/core/JeiInfo.java @@ -0,0 +1,10 @@ +package dev.compactmods.machines.api.core; + +import com.mojang.datafixers.kinds.Const; +import net.minecraft.util.ResourceLocation; + +public class JeiInfo { + public static final ResourceLocation MACHINE = new ResourceLocation(Constants.MOD_ID, "machines"); + + public static final ResourceLocation SHRINKING_DEVICE = new ResourceLocation(Constants.MOD_ID, "shrinking_device"); +} diff --git a/src/api/java/dev/compactmods/machines/api/core/Messages.java b/src/api/java/dev/compactmods/machines/api/core/Messages.java new file mode 100644 index 00000000..46668118 --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/core/Messages.java @@ -0,0 +1,12 @@ +package dev.compactmods.machines.api.core; + +import net.minecraft.util.ResourceLocation; + +public abstract class Messages { + public static final ResourceLocation CANNOT_ENTER_MACHINE = new ResourceLocation(Constants.MOD_ID, "cannot_enter"); + public static final ResourceLocation NO_MACHINE_DATA = new ResourceLocation(Constants.MOD_ID, "no_machine_data"); + public static final ResourceLocation MACHINE_SPAWNPOINT_SET = new ResourceLocation(Constants.MOD_ID, "spawnpoint_set"); + public static final ResourceLocation TELEPORT_OUT_OF_BOUNDS = new ResourceLocation(Constants.MOD_ID, "teleport_oob"); + public static final ResourceLocation HOW_DID_YOU_GET_HERE = new ResourceLocation(Constants.MOD_ID, "how_did_you_get_here"); + public static final ResourceLocation FIXBIOME_IN_BAD_DIMENSION = new ResourceLocation(Constants.MOD_ID, "fixbiome_bad_dim"); +} diff --git a/src/api/java/dev/compactmods/machines/api/core/Tooltips.java b/src/api/java/dev/compactmods/machines/api/core/Tooltips.java new file mode 100644 index 00000000..de00d05e --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/core/Tooltips.java @@ -0,0 +1,23 @@ +package dev.compactmods.machines.api.core; + +import net.minecraft.util.ResourceLocation; + +public abstract class Tooltips { + + public static final ResourceLocation UNKNOWN_PLAYER_NAME = new ResourceLocation(Constants.MOD_ID, "unknown_player"); + + public static abstract class Machines { + public static final ResourceLocation ID = new ResourceLocation(Constants.MOD_ID, "machine.id"); + public static final ResourceLocation OWNER = new ResourceLocation(Constants.MOD_ID, "machine.owner"); + public static final ResourceLocation SIZE = new ResourceLocation(Constants.MOD_ID, "machine.size"); + } + + //#region Hints and Details + public static final ResourceLocation HINT_HOLD_SHIFT = new ResourceLocation(Constants.MOD_ID, "hint.hold_shift"); + + public static abstract class Details { + public static final ResourceLocation PERSONAL_SHRINKING_DEVICE = new ResourceLocation(Constants.MOD_ID, "details.psd"); + public static final ResourceLocation SOLID_WALL = new ResourceLocation(Constants.MOD_ID, "details.solid_wall"); + } + //#endregion +} diff --git a/src/api/java/dev/compactmods/machines/api/teleportation/IDimensionalPosition.java b/src/api/java/dev/compactmods/machines/api/teleportation/IDimensionalPosition.java new file mode 100644 index 00000000..799166ee --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/teleportation/IDimensionalPosition.java @@ -0,0 +1,12 @@ +package dev.compactmods.machines.api.teleportation; + +import java.util.Optional; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.server.ServerWorld; + +public interface IDimensionalPosition { + BlockPos getBlockPosition(); + + Optional getWorld(MinecraftServer server); +} diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/EnumTunnelSide.java b/src/api/java/dev/compactmods/machines/api/tunnels/EnumTunnelSide.java similarity index 68% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/EnumTunnelSide.java rename to src/api/java/dev/compactmods/machines/api/tunnels/EnumTunnelSide.java index 75c552e4..8b9fa288 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/EnumTunnelSide.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/EnumTunnelSide.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.api.tunnels; +package dev.compactmods.machines.api.tunnels; /** * Represents the side of a tunnel (inside or outside). diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/ICapableTunnel.java b/src/api/java/dev/compactmods/machines/api/tunnels/ICapableTunnel.java similarity index 67% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/ICapableTunnel.java rename to src/api/java/dev/compactmods/machines/api/tunnels/ICapableTunnel.java index 1f4cfba9..70e363ba 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/ICapableTunnel.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/ICapableTunnel.java @@ -1,5 +1,6 @@ -package com.robotgryphon.compactmachines.api.tunnels; +package dev.compactmods.machines.api.tunnels; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.server.ServerWorld; @@ -7,6 +8,8 @@ import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; /** * A base interface that marks a tunnel as supporting capabilities (items, fluids, etc.) @@ -18,4 +21,6 @@ public interface ICapableTunnel { @Nonnull LazyOptional getExternalCapability(ServerWorld world, BlockPos tunnelPos, @Nonnull Capability cap, Direction side); + + Map, LazyOptional> rebuildCapabilityCache(ServerWorld compactLevel, BlockPos tunnelPos, BlockPos inside, @Nullable IDimensionalPosition external); } diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/IItemTunnel.java b/src/api/java/dev/compactmods/machines/api/tunnels/IItemTunnel.java similarity index 51% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/IItemTunnel.java rename to src/api/java/dev/compactmods/machines/api/tunnels/IItemTunnel.java index 85de97fc..7473d313 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/IItemTunnel.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/IItemTunnel.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.api.tunnels; +package dev.compactmods.machines.api.tunnels; public interface IItemTunnel extends ICapableTunnel { diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/ITunnelConnectionInfo.java b/src/api/java/dev/compactmods/machines/api/tunnels/ITunnelConnectionInfo.java similarity index 78% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/ITunnelConnectionInfo.java rename to src/api/java/dev/compactmods/machines/api/tunnels/ITunnelConnectionInfo.java index 69f25787..4e25b726 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/ITunnelConnectionInfo.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/ITunnelConnectionInfo.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.api.tunnels; +package dev.compactmods.machines.api.tunnels; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.world.IWorldReader; @@ -10,7 +10,7 @@ public interface ITunnelConnectionInfo { @Nonnull - Optional getConnectedPosition(EnumTunnelSide side); + Optional getConnectedPosition(EnumTunnelSide side); @Nonnull Optional getConnectedState(EnumTunnelSide side); diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/TunnelDefinition.java b/src/api/java/dev/compactmods/machines/api/tunnels/TunnelDefinition.java similarity index 77% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/TunnelDefinition.java rename to src/api/java/dev/compactmods/machines/api/tunnels/TunnelDefinition.java index f67ec525..c8b2a978 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/TunnelDefinition.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/TunnelDefinition.java @@ -1,8 +1,10 @@ -package com.robotgryphon.compactmachines.api.tunnels; +package dev.compactmods.machines.api.tunnels; import net.minecraftforge.registries.ForgeRegistryEntry; +import net.minecraftforge.registries.IForgeRegistryEntry; public abstract class TunnelDefinition extends ForgeRegistryEntry + implements IForgeRegistryEntry { /** * The color of a non-indicator (the same color as the wall) diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneReaderTunnel.java b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneReaderTunnel.java similarity index 73% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneReaderTunnel.java rename to src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneReaderTunnel.java index 3576deaf..2a263c4c 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneReaderTunnel.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneReaderTunnel.java @@ -1,11 +1,6 @@ -package com.robotgryphon.compactmachines.api.tunnels.redstone; +package dev.compactmods.machines.api.tunnels.redstone; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import net.minecraft.block.BlockState; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; /** * A redstone reader reads a redstone value from outside the machine (from a given side). diff --git a/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneTunnel.java b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneTunnel.java new file mode 100644 index 00000000..bfd4a713 --- /dev/null +++ b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneTunnel.java @@ -0,0 +1,4 @@ +package dev.compactmods.machines.api.tunnels.redstone; + +public interface IRedstoneTunnel { +} diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneWriterTunnel.java b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneWriterTunnel.java similarity index 50% rename from src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneWriterTunnel.java rename to src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneWriterTunnel.java index fdff30fd..32afc54d 100644 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneWriterTunnel.java +++ b/src/api/java/dev/compactmods/machines/api/tunnels/redstone/IRedstoneWriterTunnel.java @@ -1,10 +1,6 @@ -package com.robotgryphon.compactmachines.api.tunnels.redstone; +package dev.compactmods.machines.api.tunnels.redstone; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import net.minecraft.block.BlockState; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; /** * A redstone writer sends a redstone value from inside the machine (redstone connected to a tunnel). diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 25bb6ef4..6e1d57a5 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -13,8 +13,18 @@ bb446af024870e7a07d31a3c78cab75797392cd5 assets/compactmachines/models/tunnels/n 2781d8f8d22db668495872f1bb39e2dd1290ab66 assets/compactmachines/models/tunnels/south.json 955410e7497ca2252d75eac53d02fb96992d94c7 assets/compactmachines/models/tunnels/up.json f8748baf2b48a44db2cf8d3872bd09b54a822560 assets/compactmachines/models/tunnels/west.json -95bb11d93b0dee59240d959bc881caea0115970f data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json -b86297267feb2e7d28cb68a830a0d7ffd6b6539a data/compactmachines/advancements/recipes/compactmachines/wall.json +7611e10d6cb874469fee3209687504a964c1b7a5 data/compactmachines/advancements/claimed_machine_giant.json +c221bb570100c820a1fe904064492fcdaf245120 data/compactmachines/advancements/claimed_machine_large.json +82bae3a5d1558f86d39b69a31ef015ca25c64dc3 data/compactmachines/advancements/claimed_machine_max.json +fe844f6dfc795652f9b3c659b72a1edbf1a84438 data/compactmachines/advancements/claimed_machine_normal.json +f4bbe5fccc3b629f578958c90b84cce5776618d0 data/compactmachines/advancements/claimed_machine_small.json +5e06a5ab20a4d26b4301e24457546b618b7cee7c data/compactmachines/advancements/claimed_machine_tiny.json +29a4ead6392a01e2572b8047d84752ea461540e8 data/compactmachines/advancements/foundations.json +e08cdedde718a20284432a33903792518801d66c data/compactmachines/advancements/got_shrinking_device.json +26f679025def0ce9b0a9ec9d0e5f6ee83ea50bc3 data/compactmachines/advancements/how_did_you_get_here.json +e012e4b65799a56d195a6324c82e2cdf7a5a91be data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json +fd7ccf69e4445ba0a2d7b2cd405ebe2ae85be240 data/compactmachines/advancements/recipes/compactmachines/wall.json +2e9d5509d633970b1dd01bd99b535fd107e6e91a data/compactmachines/advancements/root.json fb5c7560898ae604661d0655c2a39e923eb1d4b4 data/compactmachines/loot_tables/blocks/machine_giant.json 056d363f46ab1cc37c16f08428a3d2a9e0dd66d2 data/compactmachines/loot_tables/blocks/machine_large.json 38a7648eb331daf18f5076126f31f31b6021ac51 data/compactmachines/loot_tables/blocks/machine_maximum.json diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_giant.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_giant.json new file mode 100644 index 00000000..2d773d15 --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_giant.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_giant" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_giant" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_giant.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_giant", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_large.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_large.json new file mode 100644 index 00000000..58cd546a --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_large.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_large" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_large" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_large.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_large", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_max.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_max.json new file mode 100644 index 00000000..381c1cf2 --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_max.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_maximum" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_max" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_max.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_max", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_normal.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_normal.json new file mode 100644 index 00000000..e63cc8b3 --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_normal.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_normal" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_normal" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_normal.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_normal", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_small.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_small.json new file mode 100644 index 00000000..261d936e --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_small.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_small" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_small" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_small.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_small", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/claimed_machine_tiny.json b/src/generated/resources/data/compactmachines/advancements/claimed_machine_tiny.json new file mode 100644 index 00000000..56c6e65d --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/claimed_machine_tiny.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:got_shrinking_device", + "display": { + "icon": { + "item": "compactmachines:machine_tiny" + }, + "title": { + "translate": "advancement.compactmachines.claimed_machine_tiny" + }, + "description": { + "translate": "advancement.compactmachines.claimed_machine_tiny.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "claimed_machine": { + "trigger": "compactmachines:claimed_machine_tiny", + "conditions": {} + } + }, + "requirements": [ + [ + "claimed_machine" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/foundations.json b/src/generated/resources/data/compactmachines/advancements/foundations.json new file mode 100644 index 00000000..4042749b --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/foundations.json @@ -0,0 +1,35 @@ +{ + "parent": "compactmachines:root", + "display": { + "icon": { + "item": "compactmachines:wall" + }, + "title": { + "translate": "advancement.compactmachines.foundations" + }, + "description": { + "translate": "advancement.compactmachines.foundations.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "obtained_wall": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "compactmachines:wall" + } + ] + } + } + }, + "requirements": [ + [ + "obtained_wall" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/got_shrinking_device.json b/src/generated/resources/data/compactmachines/advancements/got_shrinking_device.json new file mode 100644 index 00000000..b41b78f0 --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/got_shrinking_device.json @@ -0,0 +1,35 @@ +{ + "parent": "compactmachines:root", + "display": { + "icon": { + "item": "compactmachines:personal_shrinking_device" + }, + "title": { + "translate": "advancement.compactmachines.got_shrinking_device" + }, + "description": { + "translate": "advancement.compactmachines.got_shrinking_device.desc" + }, + "frame": "task", + "show_toast": true, + "announce_to_chat": true, + "hidden": false + }, + "criteria": { + "obtained_psd": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "compactmachines:personal_shrinking_device" + } + ] + } + } + }, + "requirements": [ + [ + "obtained_psd" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/how_did_you_get_here.json b/src/generated/resources/data/compactmachines/advancements/how_did_you_get_here.json new file mode 100644 index 00000000..d46cc1ce --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/how_did_you_get_here.json @@ -0,0 +1,29 @@ +{ + "parent": "compactmachines:root", + "display": { + "icon": { + "item": "compactmachines:personal_shrinking_device" + }, + "title": { + "translate": "advancement.compactmachines.how_did_you_get_here" + }, + "description": { + "translate": "advancement.compactmachines.how_did_you_get_here.desc" + }, + "frame": "challenge", + "show_toast": false, + "announce_to_chat": true, + "hidden": true + }, + "criteria": { + "got_stuck": { + "trigger": "compactmachines:how_did_you_get_here", + "conditions": {} + } + }, + "requirements": [ + [ + "got_stuck" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json b/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json index 9944fb53..44a41e91 100644 --- a/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json +++ b/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/personal_shrinking_device.json @@ -6,7 +6,7 @@ ] }, "criteria": { - "has_recipe": { + "picked_up_ender_eye": { "trigger": "minecraft:inventory_changed", "conditions": { "items": [ @@ -25,7 +25,7 @@ }, "requirements": [ [ - "has_recipe", + "picked_up_ender_eye", "has_the_recipe" ] ] diff --git a/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/wall.json b/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/wall.json index 41f67f75..e2047b76 100644 --- a/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/wall.json +++ b/src/generated/resources/data/compactmachines/advancements/recipes/compactmachines/wall.json @@ -6,7 +6,7 @@ ] }, "criteria": { - "has_recipe": { + "picked_up_iron": { "trigger": "minecraft:inventory_changed", "conditions": { "items": [ @@ -25,7 +25,7 @@ }, "requirements": [ [ - "has_recipe", + "picked_up_iron", "has_the_recipe" ] ] diff --git a/src/generated/resources/data/compactmachines/advancements/root.json b/src/generated/resources/data/compactmachines/advancements/root.json new file mode 100644 index 00000000..4f54aaec --- /dev/null +++ b/src/generated/resources/data/compactmachines/advancements/root.json @@ -0,0 +1,28 @@ +{ + "display": { + "icon": { + "item": "compactmachines:machine_normal" + }, + "title": { + "translate": "advancement.compactmachines.root" + }, + "description": { + "translate": "advancement.compactmachines.root.desc" + }, + "frame": "task", + "show_toast": false, + "announce_to_chat": false, + "hidden": false, + "background": "compactmachines:textures/block/wall.png" + }, + "criteria": { + "root": { + "trigger": "minecraft:impossible" + } + }, + "requirements": [ + [ + "root" + ] + ] +} \ No newline at end of file diff --git a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineBaseData.java b/src/legacy/CompactMachineBaseData.java similarity index 94% rename from src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineBaseData.java rename to src/legacy/CompactMachineBaseData.java index a09addaa..53fcdd30 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineBaseData.java +++ b/src/legacy/CompactMachineBaseData.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.data.machines; +package com.robotgryphon.compactmachines.data.legacy; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; @@ -9,6 +9,7 @@ /** * Holds basic information about a compact machine. */ +@Deprecated public abstract class CompactMachineBaseData implements INBTSerializable { private int id; diff --git a/src/main/java/com/robotgryphon/compactmachines/data/CompactMachineCommonData.java b/src/legacy/CompactMachineCommonData.java similarity index 53% rename from src/main/java/com/robotgryphon/compactmachines/data/CompactMachineCommonData.java rename to src/legacy/CompactMachineCommonData.java index 664f7999..aa91d369 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/CompactMachineCommonData.java +++ b/src/legacy/CompactMachineCommonData.java @@ -1,6 +1,7 @@ -package com.robotgryphon.compactmachines.data; +package com.robotgryphon.compactmachines.data.legacy; -import com.robotgryphon.compactmachines.data.machines.CompactMachinePlayerData; +import com.robotgryphon.compactmachines.data.codec.NbtListCollector; +import com.robotgryphon.compactmachines.data.player.CompactMachinePlayerData; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; import net.minecraftforge.common.util.Constants; @@ -9,6 +10,7 @@ import java.util.Map; import java.util.Optional; +@Deprecated public class CompactMachineCommonData { protected Map playerData; @@ -18,6 +20,7 @@ protected CompactMachineCommonData() { this.playerData = new HashMap<>(); } + @Deprecated public static CompactMachineCommonData getInstance() { if (INSTANCE == null) { INSTANCE = new CompactMachineCommonData(); @@ -45,39 +48,7 @@ public CompoundNBT serializeNBT(CompoundNBT compound) { } public void deserializeNBT(CompoundNBT nbt) { - deserializePlayerData(nbt); - } - - public void deserializePlayerData(CompoundNBT nbt) { - if (nbt.contains("players")) { - ListNBT players = nbt.getList("players", Constants.NBT.TAG_COMPOUND); - players.forEach(data -> { - CompactMachinePlayerData pmd = CompactMachinePlayerData.fromNBT(data); - playerData.put(pmd.getId(), pmd); - }); - } - } - - - - public void updatePlayerData(CompactMachinePlayerData pd) { - int id = pd.getId(); - - // Do we have an existing player data entry? If not, just add and return - if (!playerData.containsKey(id)) { - playerData.put(id, pd); - return; - } - - // If we have an existing entry, update and mark dirty - playerData.replace(id, pd); } - public Optional getPlayerData(int id) { - if (!playerData.containsKey(id)) - playerData.put(id, new CompactMachinePlayerData(id)); - - return Optional.ofNullable(playerData.get(id)); - } } diff --git a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineRegistrationData.java b/src/legacy/CompactMachineRegistrationData.java similarity index 97% rename from src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineRegistrationData.java rename to src/legacy/CompactMachineRegistrationData.java index 2a754385..36516d0b 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachineRegistrationData.java +++ b/src/legacy/CompactMachineRegistrationData.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.data.machines; +package com.robotgryphon.compactmachines.data.legacy; import com.robotgryphon.compactmachines.reference.EnumMachineSize; import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; @@ -14,13 +14,14 @@ import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; -import java.util.List; import java.util.Optional; import java.util.UUID; /** * Holds information that can be used to uniquely identify a compact machine. + * @deprecated Prefer InternalMachineData and CompactMachineInternalData instead. */ +@Deprecated public class CompactMachineRegistrationData extends CompactMachineBaseData { private BlockPos center; diff --git a/src/main/java/com/robotgryphon/compactmachines/data/CompactMachineServerData.java b/src/legacy/CompactMachineServerData.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/data/CompactMachineServerData.java rename to src/legacy/CompactMachineServerData.java index 73097b23..9e3c586a 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/CompactMachineServerData.java +++ b/src/legacy/CompactMachineServerData.java @@ -1,22 +1,21 @@ -package com.robotgryphon.compactmachines.data; +package com.robotgryphon.compactmachines.data.legacy; -import com.robotgryphon.compactmachines.data.machines.CompactMachinePlayerData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; +import com.robotgryphon.compactmachines.data.codec.NbtListCollector; +import com.robotgryphon.compactmachines.data.player.CompactMachinePlayerData; import com.robotgryphon.compactmachines.reference.EnumMachineSize; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; -import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.common.util.Constants; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +@Deprecated public class CompactMachineServerData extends CompactMachineCommonData { private Map machineData; @@ -69,7 +68,7 @@ public boolean registerMachine(int newID, CompactMachineRegistrationData compact return false; this.machineData.put(newID, compactMachineData); - this.playerData.put(newID, new CompactMachinePlayerData(newID)); + // TODO this.playerData.put(newID, new CompactMachinePlayerData(newID)); return true; } @@ -122,4 +121,15 @@ public Optional getMachineData(int machineId) { return Optional.ofNullable(machineData.get(machineId)); } + + public void removeMachine(int machineId) { + if(!machineData.containsKey(machineId)) + return; + + machineData.remove(machineId); + } + + public void removeMachine(CompactMachineRegistrationData mach) { + removeMachine(mach.getId()); + } } diff --git a/src/main/java/com/robotgryphon/compactmachines/data/SavedMachineData.java b/src/legacy/SavedMachineData.java similarity index 96% rename from src/main/java/com/robotgryphon/compactmachines/data/SavedMachineData.java rename to src/legacy/SavedMachineData.java index e663b419..1cc76eae 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/SavedMachineData.java +++ b/src/legacy/SavedMachineData.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.data; +package com.robotgryphon.compactmachines.data.legacy; import com.robotgryphon.compactmachines.CompactMachines; import com.robotgryphon.compactmachines.core.Registration; @@ -14,6 +14,7 @@ /** * Basically a wrapper around CompactMachineServerData. Allows read/write to disk. */ +@Deprecated public class SavedMachineData extends WorldSavedData { public final static String DATA_NAME = CompactMachines.MOD_ID + "_machines"; diff --git a/src/legacy/SavedMachineDataMigrator.java b/src/legacy/SavedMachineDataMigrator.java new file mode 100644 index 00000000..b48db8b7 --- /dev/null +++ b/src/legacy/SavedMachineDataMigrator.java @@ -0,0 +1,98 @@ +package com.robotgryphon.compactmachines.data.legacy; + +import com.robotgryphon.compactmachines.CompactMachines; +import com.robotgryphon.compactmachines.core.Registration; +import com.robotgryphon.compactmachines.data.legacy.CompactMachineServerData; +import com.robotgryphon.compactmachines.data.legacy.SavedMachineData; +import com.robotgryphon.compactmachines.data.machine.CompactMachineInternalData; +import com.robotgryphon.compactmachines.data.world.ExternalMachineData; +import com.robotgryphon.compactmachines.data.world.InternalMachineData; +import com.robotgryphon.compactmachines.reference.EnumMachineSize; +import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.storage.DimensionSavedDataManager; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; + +import javax.naming.OperationNotSupportedException; +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.UUID; + +public class SavedMachineDataMigrator { + + public static void migrate(MinecraftServer server) { + DimensionSavedDataManager ds = server + .getLevel(Registration.COMPACT_DIMENSION) + .getDataStorage(); + + SavedMachineData found = ds.get(SavedMachineData::new, SavedMachineData.DATA_NAME); + if (found == null) { + CompactMachines.LOGGER.debug("Migration complete; nothing available to migrate."); + return; + } + + ExternalMachineData emd = ExternalMachineData.get(server); + if (emd == null) { + CompactMachines.LOGGER.error("Could not perform migration; couldn't create the external machine file."); + return; + } + + InternalMachineData imd = InternalMachineData.get(server); + if (imd == null) { + CompactMachines.LOGGER.error("Could not perform migration; couldn't create the internal machine file."); + return; + } + + CompactMachineServerData data = found.getData(); + data.getMachines().forEach(mach -> { + DimensionalPosition outside = mach.getOutsidePosition(server); + BlockPos internalCenter = mach.getCenter(); + ChunkPos machineChunk = new ChunkPos(internalCenter); + + UUID owner = mach.getOwner(); + EnumMachineSize size = mach.getSize(); + BlockPos center = mach.getCenter(); + BlockPos spawn = mach.getSpawnPoint().orElse(center); + + int id = mach.getId(); + if (!emd.machineLocations.containsKey(id)) + emd.machineLocations.put(id, outside); + + if (!emd.machineMapping.containsKey(id)) + emd.machineMapping.put(id, machineChunk); + + if (!imd.isRegistered(machineChunk)) { + try { + CompactMachineInternalData d = new CompactMachineInternalData(owner, center, spawn, size); + imd.register(machineChunk, d); + } catch (OperationNotSupportedException e) { + e.printStackTrace(); + } + } + }); + + imd.setDirty(); + emd.setDirty(); + } + + private static boolean doFileDelete(DimensionSavedDataManager ds, SavedMachineData found) { + Method getDataFile = ObfuscationReflectionHelper.findMethod( + DimensionSavedDataManager.class, + "func_215754_a", + String.class); + + try { + File i = (File) getDataFile.invoke(ds, found.getId()); + System.out.println(i.getAbsolutePath()); + + return i.delete(); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + + return false; + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/CompactMachines.java b/src/main/java/com/robotgryphon/compactmachines/CompactMachines.java deleted file mode 100644 index a85403ba..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/CompactMachines.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.robotgryphon.compactmachines; - -import com.robotgryphon.compactmachines.compat.theoneprobe.TheOneProbeCompat; -import com.robotgryphon.compactmachines.config.CommonConfig; -import com.robotgryphon.compactmachines.config.EnableVanillaRecipesConfigCondition; -import com.robotgryphon.compactmachines.config.ServerConfig; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.network.NetworkHandler; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.config.ModConfig; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod(CompactMachines.MOD_ID) -public class CompactMachines -{ - public static final String MOD_ID = "compactmachines"; - - public static final Logger LOGGER = LogManager.getLogger(); - - public static ItemGroup COMPACT_MACHINES_ITEMS = new ItemGroup(MOD_ID) { - @Override - public ItemStack makeIcon() { - return new ItemStack(Registration.MACHINE_BLOCK_ITEM_NORMAL.get()); - } - }; - - public CompactMachines() { - IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); - - // Register blocks and items - Registration.init(); - - // Register the setup method for modloading - modBus.addListener(this::setup); - - // Register the enqueueIMC method for modloading - modBus.addListener(this::enqueueIMC); - - // Register ourselves for server and other game events we are interested in - MinecraftForge.EVENT_BUS.register(this); - - ModLoadingContext mlCtx = ModLoadingContext.get(); - mlCtx.registerConfig(ModConfig.Type.COMMON, CommonConfig.CONFIG); - mlCtx.registerConfig(ModConfig.Type.SERVER, ServerConfig.CONFIG); - - CraftingHelper.register(EnableVanillaRecipesConfigCondition.Serializer.INSTANCE); - } - - private void setup(final FMLCommonSetupEvent event) - { - NetworkHandler.initialize(); - } - - private void enqueueIMC(final InterModEnqueueEvent event) - { - if(ModList.get().isLoaded("theoneprobe")) - TheOneProbeCompat.sendIMC(); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneTunnel.java b/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneTunnel.java deleted file mode 100644 index cd7cd380..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/api/tunnels/redstone/IRedstoneTunnel.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.robotgryphon.compactmachines.api.tunnels.redstone; - -public interface IRedstoneTunnel { -} diff --git a/src/main/java/com/robotgryphon/compactmachines/block/tiles/CompactMachineTile.java b/src/main/java/com/robotgryphon/compactmachines/block/tiles/CompactMachineTile.java deleted file mode 100644 index 1e65a369..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/block/tiles/CompactMachineTile.java +++ /dev/null @@ -1,511 +0,0 @@ -package com.robotgryphon.compactmachines.block.tiles; - -import com.robotgryphon.compactmachines.config.ServerConfig; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.data.CompactMachineCommonData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachinePlayerData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.reference.Reference; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; -import com.robotgryphon.compactmachines.api.tunnels.ICapableTunnel; -import net.minecraft.block.BlockState; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.StringNBT; -import net.minecraft.network.NetworkManager; -import net.minecraft.network.play.server.SUpdateTileEntityPacket; -import net.minecraft.tileentity.ITickableTileEntity; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.Constants; -import net.minecraftforge.common.util.LazyOptional; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.*; - -public class CompactMachineTile extends TileEntity implements ICapabilityProvider, ITickableTileEntity { - public int machineId = -1; - private boolean initialized = false; - public boolean alreadyNotifiedOnTick = false; - public long nextSpawnTick = 0; - - protected UUID owner; - protected String schema; - protected boolean locked = false; - protected Set playerWhiteList; - - @Nullable - private CompactMachinePlayerData playerData; - - public CompactMachineTile() { - super(Registration.MACHINE_TILE_ENTITY.get()); - - playerWhiteList = new HashSet<>(); - playerData = null; - } - - @Override - public void clearRemoved() { - super.clearRemoved(); - - if (ServerConfig.MACHINE_CHUNKLOADING.get()) - doChunkload(true); - } - - @Override - public void onChunkUnloaded() { - super.onChunkUnloaded(); - - if (ServerConfig.MACHINE_CHUNKLOADING.get()) - doChunkload(false); - } - - @Override - public void setRemoved() { - super.setRemoved(); - - if (ServerConfig.MACHINE_CHUNKLOADING.get()) - doChunkload(false); - } - - @Override - public void load(BlockState state, CompoundNBT nbt) { - super.load(state, nbt); - - machineId = nbt.getInt("coords"); - // TODO customName = nbt.getString("CustomName"); - if (nbt.contains(Reference.CompactMachines.OWNER_NBT)) { - owner = nbt.getUUID(Reference.CompactMachines.OWNER_NBT); - } else { - owner = null; - } - - nextSpawnTick = nbt.getLong("spawntick"); - if (nbt.contains("schema")) { - schema = nbt.getString("schema"); - } else { - schema = null; - } - - if (nbt.contains("locked")) { - locked = nbt.getBoolean("locked"); - } else { - locked = false; - } - - playerWhiteList = new HashSet<>(); - if (nbt.contains("playerWhiteList")) { - ListNBT list = nbt.getList("playerWhiteList", Constants.NBT.TAG_STRING); - list.forEach(nametag -> playerWhiteList.add(nametag.getAsString())); - } - } - - @Override - public CompoundNBT save(CompoundNBT nbt) { - nbt = super.save(nbt); - - nbt.putInt("coords", machineId); - // nbt.putString("CustomName", customName.getString()); - - if (owner != null) { - nbt.putUUID(Reference.CompactMachines.OWNER_NBT, this.owner); - } - - nbt.putLong("spawntick", nextSpawnTick); - if (schema != null) { - nbt.putString("schema", schema); - } - - nbt.putBoolean("locked", locked); - - if (playerWhiteList.size() > 0) { - ListNBT list = new ListNBT(); - playerWhiteList.forEach(player -> { - StringNBT nameTag = StringNBT.valueOf(player); - list.add(nameTag); - }); - - nbt.put("playerWhiteList", list); - } - - return nbt; - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - if (level.isClientSide()) - return super.getCapability(cap, side); - - ServerWorld serverWorld = (ServerWorld) level; - ServerWorld compactWorld = serverWorld.getServer().getLevel(Registration.COMPACT_DIMENSION); - if (compactWorld == null) - return LazyOptional.empty(); - - Set tunnelPositions = TunnelHelper.getTunnelsForMachineSide(this.machineId, serverWorld, side); - if (tunnelPositions.isEmpty()) - return LazyOptional.empty(); - - for (BlockPos possibleTunnel : tunnelPositions) { - TunnelWallTile tile = (TunnelWallTile) compactWorld.getBlockEntity(possibleTunnel); - if (tile == null) - continue; - - Optional tunnel = tile.getTunnelDefinition(); - if (!tunnel.isPresent()) - continue; - - TunnelDefinition definition = tunnel.get(); - if (definition instanceof ICapableTunnel) { - LazyOptional capPoss = ((ICapableTunnel) definition).getInternalCapability(compactWorld, possibleTunnel, cap, side); - if (capPoss.isPresent()) - return capPoss; - } - } - - return LazyOptional.empty(); - } - - @Nullable - @Override - public SUpdateTileEntityPacket getUpdatePacket() { - return new SUpdateTileEntityPacket(worldPosition, 1, getUpdateTag()); - } - - @Override - public CompoundNBT getUpdateTag() { - CompoundNBT base = super.getUpdateTag(); - base.putInt("machine", this.machineId); - - if (level instanceof ServerWorld) { - Optional playerData = Optional.empty(); - try { - SavedMachineData machineData = SavedMachineData.getInstance(level.getServer()); - playerData = machineData.getData().getPlayerData(machineId); - } catch (Exception e) { - e.printStackTrace(); - } - - playerData.ifPresent(data -> { - CompoundNBT playerNbt = data.serializeNBT(); - base.put("players", playerNbt); - }); - - if (this.owner != null) - base.putUUID("owner", this.owner); - } - - return base; - } - - @Override - public void handleUpdateTag(BlockState state, CompoundNBT tag) { - super.handleUpdateTag(state, tag); - - this.machineId = tag.getInt("machine"); - if (tag.contains("players")) { - CompoundNBT players = tag.getCompound("players"); - playerData = CompactMachinePlayerData.fromNBT(players); - - } - - if (tag.contains("owner")) - owner = tag.getUUID("owner"); - } - - @Override - public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { - BlockState state = null; - if (this.level != null) { - state = this.level.getBlockState(worldPosition); - } - - load(state, pkt.getTag()); - } - - @Override - public void tick() { - - } - - public Optional getOwnerUUID() { - return Optional.ofNullable(this.owner); - } - - public void setOwner(UUID owner) { - this.owner = owner; - } - - public void setMachineId(int id) { - this.machineId = id; - this.setChanged(); - } - - public Optional getMachineData() { - if (this.machineId == 0) - return Optional.empty(); - - if (level instanceof ServerWorld) { - return Optional.ofNullable(level.getServer()) - .map(SavedMachineData::getInstance) - .map(SavedMachineData::getData) - .flatMap(d -> d.getMachineData(this.machineId)); - } else { - return Optional.empty(); - } - } - - public boolean hasPlayersInside() { - return CompactMachineCommonData - .getInstance() - .getPlayerData(machineId) - .map(CompactMachinePlayerData::hasPlayers) - .orElse(false); - } - - protected void doChunkload(boolean force) { - if (level == null || level.isClientSide) - return; - - getMachineData().ifPresent(data -> { - ServerWorld compact = this.level.getServer().getLevel(Registration.COMPACT_DIMENSION); - IChunk machineChunk = compact.getChunk(data.getCenter()); - ChunkPos chunkPos = machineChunk.getPos(); - compact.setChunkForced(chunkPos.x, chunkPos.z, force); - }); - } - - public void doPostPlaced() { - doChunkload(true); - } - - public void handlePlayerLeft(UUID playerID) { - if(this.playerData != null) - this.playerData.removePlayer(playerID); - } - - public void handlePlayerEntered(UUID playerID) { - if(this.playerData != null) - this.playerData.addPlayer(playerID); - } - - /* - * Chunk-Loading triggers - */ - -// private void initialize() { -// if (this.getWorld().isRemote) { -// return; -// } -// -// if (!ChunkLoadingMachines.isMachineChunkLoaded(this.coords)) { -// ChunkLoadingMachines.forceChunk(this.coords); -// } -// -// } - -// @Override -// public void update() { -// if (!this.initialized && !this.isInvalid() && this.coords != -1) { -// initialize(); -// this.initialized = true; -// } -// -// this.alreadyNotifiedOnTick = false; -// -// if (nextSpawnTick == 0) { -// nextSpawnTick = this.getWorld().getTotalWorldTime() + ConfigurationHandler.MachineSettings.spawnRate; -// } -// -// if (!this.getWorld().isRemote && this.coords != -1 && isInsideItself()) { -// if (this.getWorld().getTotalWorldTime() % 20 == 0) { -// world.playSound(null, getPos(), -// SoundEvent.REGISTRY.getObject(new ResourceLocation("entity.wither.spawn")), -// SoundCategory.MASTER, -// 1.0f, -// 1.0f -// ); -// } -// } -// -// if (!this.getWorld().isRemote && this.coords != -1 && this.getWorld().getTotalWorldTime() > nextSpawnTick) { -// if (ConfigurationHandler.MachineSettings.allowPeacefulSpawns || ConfigurationHandler.MachineSettings.allowHostileSpawns) { -// SpawnTools.spawnEntitiesInMachine(coords); -// } -// -// nextSpawnTick = this.getWorld().getTotalWorldTime() + ConfigurationHandler.MachineSettings.spawnRate; -// this.markDirty(); -// } -// -// /* -// // Use this once we render in world or use the proxy world to determine client side capabilities. -// if(!this.getWorld().isRemote && this.getWorld().getTotalWorldTime() % 20 == 0 && this.coords != -1) { -// PackageHandler.instance.sendToAllAround(new MessageMachineChunk(this.coords), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(), 32.0f)); -// } -// */ -// } - -// @Override -// public void onChunkUnload() { -// super.onChunkUnload(); -// if (this.getWorld().isRemote) { -// return; -// } -// -// if (ConfigurationHandler.Settings.forceLoadChunks) { -// return; -// } -// -// ChunkLoadingMachines.unforceChunk(this.coords); -// } -// -// public boolean isInsideItself() { -// if (this.getWorld().provider.getDimension() != ConfigurationHandler.Settings.dimensionId) { -// return false; -// } -// -// return StructureTools.getCoordsForPos(this.getPos()) == this.coords; -// } -// -// public ItemStack getConnectedPickBlock(EnumFacing facing) { -// BlockPos insetPos = getMachineWorldInsetPos(facing); -// if (insetPos == null) { -// return ItemStack.EMPTY; -// } -// -// WorldServer machineWorld = DimensionTools.getServerMachineWorld(); -// IBlockState state = machineWorld.getBlockState(insetPos); -// return state.getBlock().getItem(machineWorld, insetPos, state); -// } -// -// public int getRedstonePowerOutput(EnumFacing facing) { -// if (this.coords == -1) { -// return 0; -// } -// -// // We don't know the actual power on the client-side, which does not have the worldsaveddatamachines instance -// if (WorldSavedDataMachines.INSTANCE == null || WorldSavedDataMachines.INSTANCE.redstoneTunnels == null) { -// return 0; -// } -// -// HashMap tunnelMapping = WorldSavedDataMachines.INSTANCE.redstoneTunnels.get(this.coords); -// if (tunnelMapping == null) { -// return 0; -// } -// -// RedstoneTunnelData tunnelData = tunnelMapping.get(facing); -// if (tunnelData == null) { -// return 0; -// } -// -// -// if (!tunnelData.isOutput) { -// return 0; -// } -// -// WorldServer machineWorld = DimensionTools.getServerMachineWorld(); -// if (!(machineWorld.getTileEntity(tunnelData.pos) instanceof TileEntityRedstoneTunnel)) { -// return 0; -// } -// -// EnumFacing insetDirection = StructureTools.getInsetWallFacing(tunnelData.pos, this.getSize().getDimension()); -// BlockPos insetPos = tunnelData.pos.offset(insetDirection); -// IBlockState insetBlockState = machineWorld.getBlockState(insetPos); -// -// int power = 0; -// if (insetBlockState.getBlock() instanceof BlockRedstoneWire) { -// power = insetBlockState.getValue(BlockRedstoneWire.POWER); -// } else { -// power = machineWorld.getRedstonePower(insetPos, insetDirection); -// } -// -// return power; -// } -// -// @Override -// public boolean hasCapability(Capability capability, EnumFacing facing) { -// if (isInsideItself()) { -// return false; -// } -// -// if (world.isRemote || facing == null) { -// if (CapabilityNullHandlerRegistry.hasNullHandler(capability)) { -// return true; -// } -// -// return super.hasCapability(capability, facing); -// } -// -// BlockPos tunnelPos = this.getConnectedBlockPosition(facing); -// if (tunnelPos == null) { -// return false; -// } -// -// World machineWorld = DimensionTools.getServerMachineWorld(); -// if (!(machineWorld.getTileEntity(tunnelPos) instanceof TileEntityTunnel)) { -// return false; -// } -// -// EnumFacing insetDirection = StructureTools.getInsetWallFacing(tunnelPos, this.getSize().getDimension()); -// BlockPos insetPos = tunnelPos.offset(insetDirection); -// -// TileEntity te = machineWorld.getTileEntity(insetPos); -// if (te != null && te instanceof ICapabilityProvider && te.hasCapability(capability, insetDirection.getOpposite())) { -// return true; -// } -// -// if (CapabilityNullHandlerRegistry.hasNullHandler(capability)) { -// return true; -// } -// -// return false; -// } -// -// @Override -// public T getCapability(Capability capability, EnumFacing facing) { -// if (isInsideItself()) { -// return null; -// } -// -// if (this.getWorld().isRemote || facing == null) { -// if (CapabilityNullHandlerRegistry.hasNullHandler(capability)) { -// return CapabilityNullHandlerRegistry.getNullHandler(capability); -// } -// -// return super.getCapability(capability, facing); -// } -// -// BlockPos tunnelPos = this.getConnectedBlockPosition(facing); -// if (tunnelPos == null) { -// return null; -// } -// -// WorldServer machineWorld = DimensionTools.getServerMachineWorld(); -// if (!(machineWorld.getTileEntity(tunnelPos) instanceof TileEntityTunnel)) { -// return null; -// } -// -// EnumFacing insetDirection = StructureTools.getInsetWallFacing(tunnelPos, this.getSize().getDimension()); -// BlockPos insetPos = tunnelPos.offset(insetDirection); -// -// TileEntity te = machineWorld.getTileEntity(insetPos); -// if (te instanceof ICapabilityProvider && te.hasCapability(capability, insetDirection.getOpposite())) { -// return machineWorld.getTileEntity(insetPos).getCapability(capability, insetDirection.getOpposite()); -// } -// -// if (CapabilityNullHandlerRegistry.hasNullHandler(capability)) { -// return CapabilityNullHandlerRegistry.getNullHandler(capability); -// } -// -// return null; -// } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/block/tiles/TunnelWallTile.java b/src/main/java/com/robotgryphon/compactmachines/block/tiles/TunnelWallTile.java deleted file mode 100644 index dbb44072..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/block/tiles/TunnelWallTile.java +++ /dev/null @@ -1,221 +0,0 @@ -package com.robotgryphon.compactmachines.block.tiles; - -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.network.NetworkHandler; -import com.robotgryphon.compactmachines.network.TunnelAddedPacket; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.api.tunnels.ICapableTunnel; -import com.robotgryphon.compactmachines.util.CompactMachineUtil; -import net.minecraft.block.BlockState; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.world.IWorldReader; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.common.registry.GameRegistry; -import net.minecraftforge.fml.network.PacketDistributor; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Optional; - -public class TunnelWallTile extends TileEntity { - - private ResourceLocation tunnelType; - - public TunnelWallTile() { - super(Registration.TUNNEL_WALL_TILE.get()); - } - - public Optional getMachineInfo() { - if (this.level instanceof ServerWorld) { - ServerWorld serverWorld = (ServerWorld) this.level; - return CompactMachineUtil.getMachineInfoByInternalPosition(serverWorld, this.worldPosition); - } - - return Optional.empty(); - } - - @Override - public void load(BlockState state, CompoundNBT nbt) { - super.load(state, nbt); - - if(nbt.contains("tunnel_type")) { - ResourceLocation type = new ResourceLocation(nbt.getString("tunnel_type")); - this.tunnelType = type; - } - } - - @Override - public CompoundNBT save(CompoundNBT compound) { - compound = super.save(compound); - compound.putString("tunnel_type", tunnelType.toString()); - return compound; - } - - @Override - public CompoundNBT getUpdateTag() { - CompoundNBT nbt = super.getUpdateTag(); - nbt.putString("tunnel_type", tunnelType.toString()); - - return nbt; - } - - @Override - public void handleUpdateTag(BlockState state, CompoundNBT tag) { - super.handleUpdateTag(state, tag); - - if(tag.contains("tunnel_type")) { - this.tunnelType = new ResourceLocation(tag.getString("tunnel_type")); - } - } - - public Optional getConnectedWorld() { - if (level == null || level.isClientSide()) - return Optional.empty(); - - ServerWorld serverWorld = (ServerWorld) level; - - Optional machineInfo = getMachineInfo(); - if (!machineInfo.isPresent()) - return Optional.empty(); - - Direction outsideDir = getConnectedSide(); - - CompactMachineRegistrationData regData = machineInfo.get(); - - // Is the machine placed in world? If not, do not return an outside position - if (!regData.isPlacedInWorld()) - return Optional.empty(); - - DimensionalPosition machinePosition = regData.getOutsidePosition(serverWorld.getServer()); - if (machinePosition != null) { - return machinePosition.getWorld(serverWorld.getServer()); - } - - return Optional.empty(); - } - - /** - * Gets the position outside the machine where this tunnel is connected to. - * - * @return - */ - public Optional getConnectedPosition() { - if (level == null || level.isClientSide()) - return Optional.empty(); - - ServerWorld serverWorld = (ServerWorld) level; - - Optional machineInfo = getMachineInfo(); - if (!machineInfo.isPresent()) - return Optional.empty(); - - Direction outsideDir = getConnectedSide(); - - CompactMachineRegistrationData regData = machineInfo.get(); - - // Is the machine placed in world? If not, do not return an outside position - if (!regData.isPlacedInWorld()) - return Optional.empty(); - - DimensionalPosition machinePosition = regData.getOutsidePosition(serverWorld.getServer()); - if (machinePosition != null) { - Vector3d o = machinePosition.getPosition(); - BlockPos machineOutPos = new BlockPos(o.x, o.y, o.z); - - BlockPos connectedBlock = machineOutPos.relative(outsideDir); - Vector3d connectedBlockVec = new Vector3d(connectedBlock.getX(), connectedBlock.getY(), connectedBlock.getZ()); - - DimensionalPosition connectedPosition = new DimensionalPosition(machinePosition.getDimension(), connectedBlockVec); - return Optional.of(connectedPosition); - } - - return Optional.empty(); - } - - /** - * Gets the side the tunnel is placed on (the wall inside the machine) - * @return - */ - public Direction getTunnelSide() { - BlockState state = getBlockState(); - return state.getValue(TunnelWallBlock.TUNNEL_SIDE); - } - - /** - * Gets the side the tunnel connects to externally (the machine side) - * @return - */ - public Direction getConnectedSide() { - BlockState blockState = getBlockState(); - return blockState.getValue(TunnelWallBlock.CONNECTED_SIDE); - } - - public Optional getTunnelDefinitionId() { - return Optional.ofNullable(this.tunnelType); - } - - public Optional getTunnelDefinition() { - if(tunnelType == null) - return Optional.empty(); - - TunnelDefinition definition = GameRegistry - .findRegistry(TunnelDefinition.class) - .getValue(tunnelType); - - return Optional.ofNullable(definition); - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap) { - return LazyOptional.empty(); - } - - @Nonnull - @Override - public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { - Direction tunnelInDir = getConnectedSide(); - - Optional tunnelDef = getTunnelDefinition(); - - // If we don't have a definition for the tunnel, skip - if (!tunnelDef.isPresent()) - return super.getCapability(cap, side); - - // loop through tunnel definition for capabilities - TunnelDefinition definition = tunnelDef.get(); - if (definition instanceof ICapableTunnel) { - if(!level.isClientSide()) { - ServerWorld sw = (ServerWorld) level; - return ((ICapableTunnel) definition).getExternalCapability(sw, worldPosition, cap, side); - } - } - - return super.getCapability(cap, side); - } - - public void setTunnelType(ResourceLocation registryName) { - this.tunnelType = registryName; - - if(level != null && !level.isClientSide()) { - setChanged(); - - TunnelAddedPacket pkt = new TunnelAddedPacket(worldPosition, registryName); - - Chunk chunkAt = level.getChunkAt(worldPosition); - NetworkHandler.MAIN_CHANNEL - .send(PacketDistributor.TRACKING_CHUNK.with(() -> chunkAt), pkt); - } - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/jei/CompactMachinesJeiPlugin.java b/src/main/java/com/robotgryphon/compactmachines/compat/jei/CompactMachinesJeiPlugin.java deleted file mode 100644 index 03ae50e9..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/compat/jei/CompactMachinesJeiPlugin.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.robotgryphon.compactmachines.compat.jei; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.core.Registration; -import mezz.jei.api.IModPlugin; -import mezz.jei.api.JeiPlugin; -import mezz.jei.api.registration.ISubtypeRegistration; -import mezz.jei.api.runtime.IJeiRuntime; -import net.minecraft.util.ResourceLocation; - -@JeiPlugin -public class CompactMachinesJeiPlugin implements IModPlugin { - @Override - public ResourceLocation getPluginUid() { - return new ResourceLocation(CompactMachines.MOD_ID, "main"); - } - - @Override - public void registerItemSubtypes(ISubtypeRegistration registration) { - registration.useNbtForSubtypes(Registration.ITEM_TUNNEL.get()); - } - - @Override - public void onRuntimeAvailable(IJeiRuntime jeiRuntime) { - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/CompactMachineProvider.java b/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/CompactMachineProvider.java deleted file mode 100644 index 1143358b..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/CompactMachineProvider.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe.providers; - -import com.mojang.authlib.GameProfile; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.block.tiles.CompactMachineTile; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeData; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; -import mcjty.theoneprobe.api.IProbeHitData; -import mcjty.theoneprobe.api.IProbeInfo; -import mcjty.theoneprobe.api.ProbeMode; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.IFormattableTextComponent; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.World; -import net.minecraft.world.server.ServerWorld; - -import java.util.Optional; -import java.util.Set; - -public class CompactMachineProvider { - - public static void exec(IProbeData data, PlayerEntity player, World world, BlockState state) { - ProbeMode mode = data.getMode(); - IProbeInfo info = data.getInfo(); - IProbeHitData hitData = data.getHitData(); - - addProbeInfo(mode, info, player, world, state, hitData); - } - - private static void addProbeInfo(ProbeMode mode, IProbeInfo info, PlayerEntity player, World world, BlockState state, IProbeHitData hitData) { - TileEntity te = world.getBlockEntity(hitData.getPos()); - if (te instanceof CompactMachineTile) { - CompactMachineTile machine = (CompactMachineTile) te; - - Optional machineData = machine.getMachineData(); - machineData.ifPresent(md -> { - - IFormattableTextComponent id = new TranslationTextComponent( - String.format("tooltip.%s.machine_id", CompactMachines.MOD_ID), - md.getId() - ).withStyle(TextFormatting.GREEN); - info.text(id); - - // Owner Name - PlayerEntity owner = world.getPlayerByUUID(md.getOwner()); - if (owner != null) { - GameProfile ownerProfile = owner.getGameProfile(); - IFormattableTextComponent ownerText = new TranslationTextComponent( - String.format("tooltip.%s.owner", CompactMachines.MOD_ID), ownerProfile.getName() - ).withStyle(TextFormatting.GRAY); - - info.text(ownerText); - } - - Set tunnelsForMachineSide = TunnelHelper.getTunnelsForMachineSide(md.getId(), (ServerWorld) world, hitData.getSideHit()); - IProbeInfo vertical = info.vertical(info.defaultLayoutStyle().spacing(0)); - - ServerWorld cm = world.getServer().getLevel(Registration.COMPACT_DIMENSION); - tunnelsForMachineSide.forEach(pos -> { - TunnelWallTile tile = (TunnelWallTile) cm.getBlockEntity(pos); - if(tile == null) - return; - - tile.getTunnelDefinition().ifPresent(tunnelDef -> { - vertical.text( - new StringTextComponent(pos.toString() + ": " + tunnelDef.getRegistryName().toString()) - ); - }); - }); - - // TODO: Connected block info (inside) - // TunnelHelper.getConnectedState(world, te, EnumTunnelSide.INSIDE); - }); - } - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/core/EventHandler.java b/src/main/java/com/robotgryphon/compactmachines/core/EventHandler.java deleted file mode 100644 index 9dceff29..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/core/EventHandler.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.robotgryphon.compactmachines.core; - -import com.robotgryphon.compactmachines.CompactMachines; -import net.minecraftforge.fml.common.Mod; - -@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID) -public class EventHandler { - -} diff --git a/src/main/java/com/robotgryphon/compactmachines/data/NbtDataUtil.java b/src/main/java/com/robotgryphon/compactmachines/data/NbtDataUtil.java deleted file mode 100644 index 9c4b1ede..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/data/NbtDataUtil.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.robotgryphon.compactmachines.data; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.util.math.vector.Vector3d; - -public abstract class NbtDataUtil { - - public static CompoundNBT writeVectorCompound(Vector3d vector) { - CompoundNBT nbt = new CompoundNBT(); - nbt.putDouble("x", vector.x); - nbt.putDouble("y", vector.y); - nbt.putDouble("z", vector.z); - return nbt; - } - - public static Vector3d readVectorCompound(CompoundNBT nbt) { - double x = nbt.getDouble("x"); - double y = nbt.getDouble("y"); - double z = nbt.getDouble("z"); - return new Vector3d(x, y, z); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachinePlayerData.java b/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachinePlayerData.java deleted file mode 100644 index f873414c..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/data/machines/CompactMachinePlayerData.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.robotgryphon.compactmachines.data.machines; - -import com.robotgryphon.compactmachines.data.NbtListCollector; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import com.robotgryphon.compactmachines.util.PlayerUtil; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.nbt.*; -import net.minecraftforge.common.util.Constants; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Optional; -import java.util.UUID; - -/** - * Holds basic information about players inside a compact machine. - */ -public class CompactMachinePlayerData extends CompactMachineBaseData { - - private HashSet internalPlayers; - - /** - * Holds a mapping of where players entered a machine. - */ - private HashMap externalSpawns; - - protected CompactMachinePlayerData() { - super(); - this.internalPlayers = new HashSet<>(0); - this.externalSpawns = new HashMap<>(0); - } - - public CompactMachinePlayerData(int id) { - super(id); - this.internalPlayers = new HashSet<>(0); - this.externalSpawns = new HashMap<>(0); - } - - public static CompactMachinePlayerData fromNBT(INBT nbt) { - if (nbt instanceof CompoundNBT) { - Optional id = getIdFromNbt(nbt); - - // If we have an ID from nbt, create an instance, otherwise invalid - return id.map(i -> { - CompactMachinePlayerData d = new CompactMachinePlayerData(i); - d.deserializeNBT((CompoundNBT) nbt); - return d; - }).orElse(null); - } - - return null; - } - - @Override - public CompoundNBT serializeNBT() { - CompoundNBT nbt = super.serializeNBT(); - ListNBT ids = internalPlayers.stream() - .map(u -> { - IntArrayNBT intNBTS = NBTUtil.createUUID(u); - CompoundNBT pnbt = new CompoundNBT(); - pnbt.put("id", intNBTS); - return pnbt; - }) - .collect(NbtListCollector.toNbtList()); - nbt.put("players", ids); - - - ListNBT spawns = externalSpawns.entrySet() - .stream() - .map((pSpawn) -> { - CompoundNBT spawn = new CompoundNBT(); - - UUID playerId = pSpawn.getKey(); - DimensionalPosition pSpawnPos = pSpawn.getValue(); - spawn.put("id", NBTUtil.createUUID(playerId)); - spawn.put("spawn", pSpawnPos.serializeNBT()); - - return spawn; - }) - .collect(NbtListCollector.toNbtList()); - - nbt.put("spawns", spawns); - - return nbt; - } - - @Override - public void deserializeNBT(CompoundNBT nbt) { - super.deserializeNBT(nbt); - - if (nbt.contains("players")) { - ListNBT players = nbt.getList("players", Constants.NBT.TAG_COMPOUND); - players.forEach(playerData -> { - CompoundNBT pd = (CompoundNBT) playerData; - UUID id = pd.getUUID("id"); - this.internalPlayers.add(id); - }); - } - - if (nbt.contains("spawns")) { - ListNBT spawns = nbt.getList("spawns", Constants.NBT.TAG_COMPOUND); - spawns.forEach(spawnData -> { - - CompoundNBT spawn = (CompoundNBT) spawnData; - UUID playerId = spawn.getUUID("id"); - DimensionalPosition pos = DimensionalPosition.fromNBT(spawn.getCompound("spawn")); - - externalSpawns.put(playerId, pos); - }); - } - } - - public boolean hasPlayers() { - return !internalPlayers.isEmpty(); - } - - public void addPlayer(UUID playerID) { - if(!internalPlayers.contains(playerID)) { - internalPlayers.add(playerID); - } - } - - public void addPlayer(ServerPlayerEntity serverPlayer) { - UUID playerUUID = serverPlayer.getGameProfile().getId(); - addPlayer(playerUUID); - - // server support - add spawn to data - if(!externalSpawns.containsKey(playerUUID)) { - DimensionalPosition pos = PlayerUtil.getPlayerDimensionalPosition(serverPlayer); - externalSpawns.put(playerUUID, pos); - } - } - - public void removePlayer(UUID playerID) { - if (internalPlayers.contains(playerID)) { - internalPlayers.remove(playerID); - externalSpawns.remove(playerID); - } - } - - public void removePlayer(ServerPlayerEntity serverPlayer) { - UUID playerUUID = serverPlayer.getGameProfile().getId(); - removePlayer(playerUUID); - } - - public Optional getExternalSpawn(ServerPlayerEntity serverPlayer) { - UUID playerUUID = serverPlayer.getGameProfile().getId(); - if(!internalPlayers.contains(playerUUID)) - return Optional.empty(); - - if(!externalSpawns.containsKey(playerUUID)) - return Optional.empty(); - - return Optional.of(externalSpawns.get(playerUUID)); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/item/ItemBlockMachine.java b/src/main/java/com/robotgryphon/compactmachines/item/ItemBlockMachine.java deleted file mode 100644 index ff2f32db..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/item/ItemBlockMachine.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.robotgryphon.compactmachines.item; - -import com.mojang.authlib.GameProfile; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.block.BlockCompactMachine; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; -import com.robotgryphon.compactmachines.reference.Reference; -import com.robotgryphon.compactmachines.util.PlayerUtil; -import net.minecraft.block.Block; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemGroup; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.util.NonNullList; -import net.minecraft.util.text.*; -import net.minecraft.world.World; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import net.minecraft.item.Item.Properties; - -public class ItemBlockMachine extends BlockItem { - - public ItemBlockMachine(Block blockIn, EnumMachineSize size, Properties builder) { - super(blockIn, builder); - } - - @Override - public void fillItemCategory(ItemGroup group, NonNullList items) { - super.fillItemCategory(group, items); - } - - @Override - public void appendHoverText(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { - super.appendHoverText(stack, worldIn, tooltip, flagIn); - - // We need NBT data for the rest of this - if (!stack.hasTag()) - return; - - CompoundNBT nbt = stack.getTag(); - if (nbt.contains("cm")) { - CompoundNBT machineData = nbt.getCompound("cm"); - if (machineData.contains("coords")) { - int coords = machineData.getInt("coords"); - if (coords > -1) { - IFormattableTextComponent coordsTC = new TranslationTextComponent("tooltip.compactmachines.machine_id", coords); - tooltip.add(coordsTC); - } - } - } - - if (nbt.contains(Reference.CompactMachines.OWNER_NBT)) { - UUID owner = nbt.getUUID(Reference.CompactMachines.OWNER_NBT); - Optional playerProfile = PlayerUtil.getProfileByUUID(worldIn, owner); - - IFormattableTextComponent player = playerProfile - .map(p -> (IFormattableTextComponent) new StringTextComponent(p.getName())) - .orElseGet(() -> new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".unknown_player")); - - IFormattableTextComponent ownerText = new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".owner") - .append(player); - - tooltip.add(ownerText); - } - - if (Screen.hasShiftDown()) { - // TODO Show size information when sneaking - - Block b = Block.byItem(stack.getItem()); - if (b instanceof BlockCompactMachine) { - EnumMachineSize size = ((BlockCompactMachine) b).getSize(); - int internalSize = size.getInternalSize(); - - IFormattableTextComponent text = new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".machine.size", internalSize) - .withStyle(TextFormatting.YELLOW); - - tooltip.add(text); - } - } else { - IFormattableTextComponent text = new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".hold_shift.hint") - .withStyle(TextFormatting.GRAY); - - tooltip.add(text); - } - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/network/MachinePlayersChangedPacket.java b/src/main/java/com/robotgryphon/compactmachines/network/MachinePlayersChangedPacket.java deleted file mode 100644 index 05b43542..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/network/MachinePlayersChangedPacket.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.robotgryphon.compactmachines.network; - -import com.google.common.collect.ImmutableSet; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.client.machine.MachinePlayerEventHandler; -import com.robotgryphon.compactmachines.data.CompactMachineServerData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import net.minecraft.network.PacketBuffer; -import net.minecraft.server.MinecraftServer; -import net.minecraftforge.fml.network.NetworkEvent; - -import javax.annotation.Nullable; -import java.util.Optional; -import java.util.UUID; -import java.util.function.Supplier; - -public class MachinePlayersChangedPacket { - - private MinecraftServer server; - public int machineID; - public ImmutableSet machinePositions; - public EnumPlayerChangeType type; - public UUID playerID; - - public MachinePlayersChangedPacket(@Nullable MinecraftServer server, int machineID, UUID id, EnumPlayerChangeType type) { - this.server = server; - this.machineID = machineID; - this.machinePositions = ImmutableSet.of(); - this.playerID = id; - this.type = type; - } - - public static void handle(MachinePlayersChangedPacket message, Supplier context) { - NetworkEvent.Context ctx = context.get(); - - message.machinePositions.forEach(machinePos -> { - CompactMachines.LOGGER.debug("Player changed machine {}; outer position {}", message.machineID, machinePos); - MachinePlayerEventHandler.handlePlayerMachineChanged(message.playerID, message.type, machinePos); - }); - - ctx.setPacketHandled(true); - } - - public static void encode(MachinePlayersChangedPacket pkt, PacketBuffer buf) { - buf.writeInt(pkt.machineID); - buf.writeUUID(pkt.playerID); - buf.writeUtf(pkt.type.toString()); - - SavedMachineData md = SavedMachineData.getInstance(pkt.server); - CompactMachineServerData data = md.getData(); - - Optional machineData = data.getMachineData(pkt.machineID); - buf.writeBoolean(machineData.isPresent()); - machineData.ifPresent(mData -> { - DimensionalPosition out = mData.getOutsidePosition(pkt.server); - buf.writeNbt(out.serializeNBT()); - }); - } - - public static MachinePlayersChangedPacket decode(PacketBuffer buf) { - int machine = buf.readInt(); - UUID id = buf.readUUID(); - EnumPlayerChangeType changeType = EnumPlayerChangeType.valueOf(buf.readUtf()); - - MachinePlayersChangedPacket pkt = new MachinePlayersChangedPacket(null, machine, id, changeType); - if(buf.readBoolean()) { - DimensionalPosition tilePos = DimensionalPosition.fromNBT(buf.readNbt()); - pkt.machinePositions = ImmutableSet.of(tilePos); - } - - return pkt; - } - - public enum EnumPlayerChangeType { - ENTERED, - EXITED - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/network/NetworkHandler.java b/src/main/java/com/robotgryphon/compactmachines/network/NetworkHandler.java deleted file mode 100644 index 018a728b..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/network/NetworkHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.robotgryphon.compactmachines.network; - -import com.robotgryphon.compactmachines.CompactMachines; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.network.NetworkDirection; -import net.minecraftforge.fml.network.NetworkRegistry; -import net.minecraftforge.fml.network.simple.SimpleChannel; - -import java.util.Optional; - -public class NetworkHandler { - private static int index = 0; - private static final String PROTOCOL_VERSION = "1"; - public static final SimpleChannel MAIN_CHANNEL = NetworkRegistry.newSimpleChannel( - new ResourceLocation(CompactMachines.MOD_ID, "main"), - () -> PROTOCOL_VERSION, - PROTOCOL_VERSION::equals, - PROTOCOL_VERSION::equals - ); - - public static void initialize() { - MAIN_CHANNEL.registerMessage(index++, MachinePlayersChangedPacket.class, - MachinePlayersChangedPacket::encode, MachinePlayersChangedPacket::decode, - MachinePlayersChangedPacket::handle, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); - - MAIN_CHANNEL.registerMessage(index++, TunnelAddedPacket.class, - TunnelAddedPacket::encode, TunnelAddedPacket::decode, - TunnelAddedPacket::handle, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/teleportation/DimensionalPosition.java b/src/main/java/com/robotgryphon/compactmachines/teleportation/DimensionalPosition.java deleted file mode 100644 index e91ddecc..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/teleportation/DimensionalPosition.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.robotgryphon.compactmachines.teleportation; - -import com.robotgryphon.compactmachines.data.NbtDataUtil; -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.registry.Registry; -import net.minecraft.world.World; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.common.util.INBTSerializable; - -import javax.annotation.Nonnull; -import java.util.Optional; - -public class DimensionalPosition implements INBTSerializable { - - private RegistryKey dimension; - private Vector3d position; - - private DimensionalPosition() { } - - public DimensionalPosition(RegistryKey dim, Vector3d pos) { - this.dimension = dim; - this.position = pos; - } - - public DimensionalPosition(RegistryKey world, BlockPos positionBlock) { - this.dimension = world; - this.position = new Vector3d(positionBlock.getX(), positionBlock.getY(), positionBlock.getZ()); - } - - public Optional getWorld(@Nonnull MinecraftServer server) { - return Optional.ofNullable(server.getLevel(this.dimension)); - } - - public static DimensionalPosition fromNBT(CompoundNBT nbt) { - DimensionalPosition dp = new DimensionalPosition(); - dp.deserializeNBT(nbt); - - return dp; - } - - @Override - public CompoundNBT serializeNBT() { - CompoundNBT nbt = new CompoundNBT(); - nbt.putString("dim", dimension.location().toString()); - CompoundNBT posNbt = NbtDataUtil.writeVectorCompound(position); - nbt.put("pos", posNbt); - return nbt; - } - - @Override - public void deserializeNBT(CompoundNBT nbt) { - if(nbt.contains("dim")) - { - ResourceLocation dim = new ResourceLocation(nbt.getString("dim")); - this.dimension = RegistryKey.create(Registry.DIMENSION_REGISTRY, dim); - } - - if(nbt.contains("pos")) { - CompoundNBT bPosNbt = nbt.getCompound("pos"); - Vector3d bPos = NbtDataUtil.readVectorCompound(bPosNbt); - this.position = bPos; - } - } - - public RegistryKey getDimension() { - return this.dimension; - } - - public Vector3d getPosition() { - return this.position; - } - - public BlockPos getBlockPosition() { - return new BlockPos(position.x, position.y, position.z); - } - - @Override - public String toString() { - return "DimensionalPosition{" + - "dimension=" + dimension + - ", position=" + position + - '}'; - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/teleportation/TeleportationEventHandler.java b/src/main/java/com/robotgryphon/compactmachines/teleportation/TeleportationEventHandler.java deleted file mode 100644 index a3722420..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/teleportation/TeleportationEventHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.robotgryphon.compactmachines.teleportation; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.core.Registration; -import net.minecraft.entity.Entity; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraftforge.event.entity.living.EntityTeleportEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID) -public class TeleportationEventHandler { - - @SubscribeEvent - public static void onEntityTeleport(final EntityTeleportEvent evt) { - // Allow teleport commands, we don't want to trap people anywhere - if(evt instanceof EntityTeleportEvent.TeleportCommand) - return; - - // Allow ender pearls as well, since players can teleport around inside machines - if(evt instanceof EntityTeleportEvent.EnderPearl) - return; - - // Make sure we only target player entities on a server - Entity entity = evt.getEntity(); - if (entity instanceof ServerPlayerEntity) { - ServerPlayerEntity sp = (ServerPlayerEntity) entity; - if(sp.level.dimension() == Registration.COMPACT_DIMENSION) { - if(evt.isCancelable()) { - evt.setCanceled(true); - return; - } - - // If the event isn't cancelable, force the position to - // be the same as the starting point - Vector3d prev = evt.getPrev(); - evt.setTargetX(prev.x); - evt.setTargetY(prev.y); - evt.setTargetZ(prev.z); - } - } - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelHelper.java b/src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelHelper.java deleted file mode 100644 index 10375035..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelHelper.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.robotgryphon.compactmachines.tunnels; - -import com.robotgryphon.compactmachines.api.tunnels.EnumTunnelSide; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.data.CompactMachineServerData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import net.minecraft.block.BlockState; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Direction; -import net.minecraft.util.RegistryKey; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorldReader; -import net.minecraft.world.World; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.fml.RegistryObject; - -import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -public class TunnelHelper { - - public static ITunnelConnectionInfo generateConnectionInfo(TunnelWallTile tunnelTile) { - return new TunnelConnectionInfo(tunnelTile); - } - - public static ITunnelConnectionInfo generateConnectionInfo(@Nonnull IBlockReader tunnelWorld, @Nonnull BlockPos tunnelPos) { - TunnelWallTile tile = (TunnelWallTile) tunnelWorld.getBlockEntity(tunnelPos); - return generateConnectionInfo(tile); - } - - @Nonnull - public static Direction getNextDirection(Direction in) { - switch (in) { - case UP: - return Direction.DOWN; - - case DOWN: - return Direction.NORTH; - - case NORTH: - return Direction.SOUTH; - - case SOUTH: - return Direction.WEST; - - case WEST: - return Direction.EAST; - - case EAST: - return Direction.UP; - } - - return Direction.UP; - } - - @Nonnull - public static Optional getTunnelDefinitionFromType(ResourceLocation id) { - Optional> first = Registration.TUNNEL_DEFINITIONS.getEntries() - .stream() - .filter(t -> t.get().getRegistryName() == id) - .findFirst(); - - return first.map(RegistryObject::get); - - } - - public static Set getTunnelsForMachineSide(int machine, ServerWorld world, Direction machineSide) { - - ServerWorld compactWorld = world.getServer().getLevel(Registration.COMPACT_DIMENSION); - - Set tunnelPositions = new HashSet<>(); - - CompactMachineServerData data = SavedMachineData.getInstance(world.getServer()).getData(); - - Optional mData = data.getMachineData(machine); - mData.ifPresent(machineData -> { - BlockPos machineCenter = machineData.getCenter(); - int internalSize = machineData.getSize().getInternalSize(); - - AxisAlignedBB allBlocksInMachine = new AxisAlignedBB(machineCenter, machineCenter) - .inflate(internalSize); - - Set tunnelPositionsUnfiltered = BlockPos.betweenClosedStream(allBlocksInMachine) - .filter(pos -> !compactWorld.isEmptyBlock(pos)) - // .filter(pos -> world.getBlockState(pos).getBlock() instanceof TunnelWallBlock) - .map(BlockPos::immutable) - .collect(Collectors.toSet()); - - if(!tunnelPositionsUnfiltered.isEmpty()) { - Set tunnelPositionsFiltered = tunnelPositionsUnfiltered - .stream() - .filter(pos -> { - BlockState state = compactWorld.getBlockState(pos); - - boolean tunnel = state.getBlock() instanceof TunnelWallBlock; - if(!tunnel) - return false; - - Direction externalSide = state.getValue(TunnelWallBlock.CONNECTED_SIDE); - return externalSide == machineSide; - }) - .map(BlockPos::immutable) - .collect(Collectors.toSet()); - - tunnelPositions.addAll(tunnelPositionsFiltered); - } - }); - - return tunnelPositions; - } - - @Nonnull - public static Optional getTunnelConnectedPosition(TunnelWallTile tunnel, EnumTunnelSide side) { - switch (side) { - case OUTSIDE: - return tunnel.getConnectedPosition(); - - case INSIDE: - RegistryKey world = Registration.COMPACT_DIMENSION; - BlockPos offsetInside = tunnel.getBlockPos().relative(tunnel.getTunnelSide()); - - DimensionalPosition pos = new DimensionalPosition(world, offsetInside); - return Optional.of(pos); - } - - return Optional.empty(); - } - - @Nonnull - public static Optional getConnectedState(TunnelWallTile twt, EnumTunnelSide side) { - DimensionalPosition connectedPosition = getTunnelConnectedPosition(twt, side).orElse(null); - if(connectedPosition == null) - return Optional.empty(); - - // We need a server world to reach across dimensions to get information - if (twt.getLevel() instanceof ServerWorld) { - ServerWorld sw = (ServerWorld) twt.getLevel(); - - Optional connectedWorld = connectedPosition.getWorld(sw.getServer()); - if (!connectedWorld.isPresent()) - return Optional.empty(); - - ServerWorld csw = connectedWorld.get(); - BlockPos connectedPos = connectedPosition.getBlockPosition(); - - BlockState state = csw.getBlockState(connectedPos); - return Optional.of(state); - } - - return Optional.empty(); - } - - -} diff --git a/src/main/java/com/robotgryphon/compactmachines/util/CompactMachinePlayerUtil.java b/src/main/java/com/robotgryphon/compactmachines/util/CompactMachinePlayerUtil.java deleted file mode 100644 index 6013a47b..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/util/CompactMachinePlayerUtil.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.robotgryphon.compactmachines.util; - -import com.robotgryphon.compactmachines.data.CompactMachineServerData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachinePlayerData; -import com.robotgryphon.compactmachines.network.MachinePlayersChangedPacket; -import com.robotgryphon.compactmachines.network.NetworkHandler; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.math.BlockPos; -import net.minecraftforge.fml.network.PacketDistributor; - -import java.util.Optional; - -public class CompactMachinePlayerUtil { - public static void addPlayerToMachine(ServerPlayerEntity serverPlayer, BlockPos machinePos, int machineId) { - MinecraftServer serv = serverPlayer.getServer(); - SavedMachineData machineData = SavedMachineData.getInstance(serv); - CompactMachineServerData serverData = machineData.getData(); - Optional playerData = serverData.getPlayerData(machineId); - - playerData.ifPresent(d -> { - d.addPlayer(serverPlayer); - machineData.setDirty(); - - MachinePlayersChangedPacket p = new MachinePlayersChangedPacket(serv, machineId, serverPlayer.getUUID(), MachinePlayersChangedPacket.EnumPlayerChangeType.ENTERED); - NetworkHandler.MAIN_CHANNEL.send( - PacketDistributor.TRACKING_CHUNK.with(() -> serverPlayer.getLevel().getChunkAt(machinePos)), - p); - }); - } - - public static void removePlayerFromMachine(ServerPlayerEntity serverPlayer, BlockPos machinePos, int machineId) { - MinecraftServer serv = serverPlayer.getServer(); - SavedMachineData machineData = SavedMachineData.getInstance(serv); - CompactMachineServerData serverData = machineData.getData(); - Optional playerData = serverData.getPlayerData(machineId); - - playerData.ifPresent(d -> { - d.removePlayer(serverPlayer); - machineData.setDirty(); - - MachinePlayersChangedPacket p = new MachinePlayersChangedPacket(serv, machineId, serverPlayer.getUUID(), MachinePlayersChangedPacket.EnumPlayerChangeType.EXITED); - NetworkHandler.MAIN_CHANNEL.send( - PacketDistributor.TRACKING_CHUNK.with(() -> serverPlayer.getLevel().getChunkAt(machinePos)), - p); - }); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/util/CompactMachineUtil.java b/src/main/java/com/robotgryphon/compactmachines/util/CompactMachineUtil.java deleted file mode 100644 index 2332b05f..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/util/CompactMachineUtil.java +++ /dev/null @@ -1,233 +0,0 @@ -package com.robotgryphon.compactmachines.util; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.block.tiles.CompactMachineTile; -import com.robotgryphon.compactmachines.config.ServerConfig; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.data.CompactMachineServerData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; -import net.minecraft.block.Block; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.item.Item; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.util.math.vector.Vector3i; -import net.minecraft.util.text.IFormattableTextComponent; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.server.ServerWorld; - -import javax.annotation.Nullable; -import java.util.Optional; - -public abstract class CompactMachineUtil { - - public static void teleportInto(ServerPlayerEntity serverPlayer, BlockPos machinePos, EnumMachineSize size) { - ServerWorld serverWorld = serverPlayer.getLevel(); - - MinecraftServer serv = serverWorld.getServer(); - if (serverWorld.dimension() == Registration.COMPACT_DIMENSION) { - IFormattableTextComponent msg = new TranslationTextComponent(CompactMachines.MOD_ID + ".cannot_enter") - .withStyle(TextFormatting.RED); - - serverPlayer.displayClientMessage(msg, true); - return; - } - - ServerWorld compactWorld = serv.getLevel(Registration.COMPACT_DIMENSION); - if (compactWorld == null) { - CompactMachines.LOGGER.warn("Compact dimension not found; player attempted to enter machine."); - return; - } - - CompactMachineTile tile = (CompactMachineTile) serverWorld.getBlockEntity(machinePos); - if (tile == null) - return; - - serv.submitAsync(() -> { - BlockPos spawnPoint; - - SavedMachineData machineData = SavedMachineData.getInstance(serv); - CompactMachineServerData serverData = machineData.getData(); - - if (tile.machineId == -1) { - int nextID = serverData.getNextMachineId(); - - BlockPos center = getCenterForNewMachine(nextID, size); - - CompactStructureGenerator.generateCompactStructure(compactWorld, size, center); - - tile.setMachineId(nextID); - CompactMachineRegistrationData regData = new CompactMachineRegistrationData(nextID, center, serverPlayer.getUUID(), size); - regData.setWorldPosition(serverWorld, machinePos); - - serverData.registerMachine(nextID, regData); - machineData.setDirty(); - - BlockPos.Mutable spawn = center.mutable(); - spawn.setY(ServerConfig.MACHINE_FLOOR_Y.get()); - - spawnPoint = spawn.immutable(); - } else { - Optional info = serverData.getMachineData(tile.machineId); - - // We have no machine info here? - if (!info.isPresent()) { - IFormattableTextComponent text = new TranslationTextComponent("messages.compactmachines.no_machine_data") - .withStyle(TextFormatting.RED) - .withStyle(TextFormatting.BOLD); - - serverPlayer.displayClientMessage(text, true); - return; - } - - CompactMachineRegistrationData data = info.get(); - BlockPos.Mutable spawn = data.getCenter().mutable(); - spawn.setY(spawn.getY() - (size.getInternalSize() / 2)); - - spawnPoint = data.getSpawnPoint().orElse(spawn); - } - - try { - // Mark the player as inside the machine, set external spawn, and yeet - CompactMachinePlayerUtil.addPlayerToMachine(serverPlayer, machinePos, tile.machineId); - } catch (Exception ex) { - CompactMachines.LOGGER.error(ex); - } - - serverPlayer.teleportTo(compactWorld, spawnPoint.getX() + 0.5, spawnPoint.getY(), spawnPoint.getZ() + 0.5, serverPlayer.yRot, serverPlayer.xRot); - }); - } - - - public static EnumMachineSize getMachineSizeFromNBT(@Nullable CompoundNBT tag) { - try { - if (tag == null) - return EnumMachineSize.TINY; - - if (!tag.contains("size")) - return EnumMachineSize.TINY; - - String sizeFromTag = tag.getString("size"); - return EnumMachineSize.getFromSize(sizeFromTag); - } catch (Exception ex) { - return EnumMachineSize.TINY; - } - } - - public static Block getMachineBlockBySize(EnumMachineSize size) { - switch (size) { - case TINY: - return Registration.MACHINE_BLOCK_TINY.get(); - - case SMALL: - return Registration.MACHINE_BLOCK_SMALL.get(); - - case NORMAL: - return Registration.MACHINE_BLOCK_NORMAL.get(); - - case LARGE: - return Registration.MACHINE_BLOCK_LARGE.get(); - - case GIANT: - return Registration.MACHINE_BLOCK_GIANT.get(); - - case MAXIMUM: - return Registration.MACHINE_BLOCK_MAXIMUM.get(); - } - - return Registration.MACHINE_BLOCK_NORMAL.get(); - } - - public static Item getMachineBlockItemBySize(EnumMachineSize size) { - switch (size) { - case TINY: - return Registration.MACHINE_BLOCK_ITEM_TINY.get(); - - case SMALL: - return Registration.MACHINE_BLOCK_ITEM_SMALL.get(); - - case NORMAL: - return Registration.MACHINE_BLOCK_ITEM_NORMAL.get(); - - case LARGE: - return Registration.MACHINE_BLOCK_ITEM_LARGE.get(); - - case GIANT: - return Registration.MACHINE_BLOCK_ITEM_GIANT.get(); - - case MAXIMUM: - return Registration.MACHINE_BLOCK_ITEM_MAXIMUM.get(); - } - - return Registration.MACHINE_BLOCK_ITEM_NORMAL.get(); - } - - public static BlockPos getCenterForNewMachine(int id, EnumMachineSize size) { - Vector3i location = MathUtil.getRegionPositionByIndex(id); - int centerY = ServerConfig.MACHINE_FLOOR_Y.get() + (size.getInternalSize() / 2); - return new BlockPos((location.getX() * 1024) + 8, centerY, (location.getZ() * 1024) + 8); - } - - public static void setMachineSpawn(MinecraftServer server, BlockPos position) { - SavedMachineData machineData = SavedMachineData.getInstance(server); - CompactMachineServerData serverData = machineData.getData(); - - Optional compactMachineData = serverData.getMachineContainingPosition(position); - compactMachineData.ifPresent(d -> { - d.setSpawnPoint(position); - serverData.updateMachineData(d); - machineData.setDirty(); - }); - } - - public static Optional getMachineData(ServerWorld world) { - if (world == null) - return Optional.empty(); - - SavedMachineData md = SavedMachineData.getInstance(world.getServer()); - return Optional.of(md); - } - - public static Optional getMachineInfoByInternalPosition(ServerWorld world, Vector3d pos) { - SavedMachineData machineData = SavedMachineData.getInstance(world.getServer()); - CompactMachineServerData serverData = machineData.getData(); - - return serverData.getMachineContainingPosition(pos); - } - - public static Optional getMachineInfoByInternalPosition(ServerWorld world, BlockPos pos) { - SavedMachineData machineData = SavedMachineData.getInstance(world.getServer()); - CompactMachineServerData serverData = machineData.getData(); - - return serverData.getMachineContainingPosition(pos); - } - - /** - * Server only; updates the machine data to reflect where the "outside" of the machine is, - * in-world. - * - * @param world - * @param machineID - * @param pos - */ - public static void updateMachineInWorldPosition(ServerWorld world, int machineID, BlockPos pos) { - SavedMachineData machineData = SavedMachineData.getInstance(world.getServer()); - CompactMachineServerData serverData = machineData.getData(); - - Optional machineById = serverData.getMachineData(machineID); - machineById.ifPresent(data -> { - data.setWorldPosition(world, pos); - data.removeFromPlayerInventory(); - - // Write changes to disk - serverData.updateMachineData(data); - machineData.setDirty(); - }); - } -} diff --git a/src/main/java/com/robotgryphon/compactmachines/util/PlayerUtil.java b/src/main/java/com/robotgryphon/compactmachines/util/PlayerUtil.java deleted file mode 100644 index 5e4bc5fd..00000000 --- a/src/main/java/com/robotgryphon/compactmachines/util/PlayerUtil.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.robotgryphon.compactmachines.util; - -import com.mojang.authlib.GameProfile; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.data.CompactMachineServerData; -import com.robotgryphon.compactmachines.data.SavedMachineData; -import com.robotgryphon.compactmachines.data.machines.CompactMachinePlayerData; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.util.RegistryKey; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.IWorld; -import net.minecraft.world.World; -import net.minecraft.world.server.ServerWorld; - -import java.util.Optional; -import java.util.UUID; - -public abstract class PlayerUtil { - public static Optional getProfileByUUID(IWorld world, UUID uuid) { - PlayerEntity player = world.getPlayerByUUID(uuid); - if (player == null) - return Optional.empty(); - - GameProfile profile = player.getGameProfile(); - return Optional.of(profile); - } - - public static DimensionalPosition getPlayerDimensionalPosition(PlayerEntity player) { - Vector3d pos = player.position(); - RegistryKey dim = player.level.dimension(); - - return new DimensionalPosition(dim, pos); - } - - public static void teleportPlayerOutOfMachine(ServerWorld world, ServerPlayerEntity serverPlayer) { - - SavedMachineData machineData = SavedMachineData.getInstance(world.getServer()); - CompactMachineServerData serverData = machineData.getData(); - - Optional machine = serverData.getMachineContainingPosition(serverPlayer.position()); - - if (!machine.isPresent()) { - serverPlayer.displayClientMessage( - new TranslationTextComponent("not_inside_machine"), - true); - - return; - } - - CompactMachineRegistrationData machineInfo = machine.get(); - - Optional machinePlayers = serverData.getPlayerData(machineInfo.getId()); - if (!machinePlayers.isPresent()) { - // No player data for machine, wut - CompactMachines.LOGGER.warn("Warning: Machine player data not set but machine registered, and player is inside. Machine ID: {}", machineInfo.getId()); - serverPlayer.displayClientMessage(new TranslationTextComponent("ah_crap"), true); - return; - } - - Optional lastPos = machinePlayers.get().getExternalSpawn(serverPlayer); - if (!lastPos.isPresent()) { - // PANIC - - return; - } else { - DimensionalPosition p = lastPos.get(); - Vector3d bp = p.getPosition(); - Optional outsideWorld = p.getWorld(world.getServer()); - outsideWorld.ifPresent(w -> { - machine.ifPresent(m -> { - serverPlayer.teleportTo(w, bp.x(), bp.y(), bp.z(), serverPlayer.yRot, serverPlayer.xRot); - CompactMachinePlayerUtil.removePlayerFromMachine(serverPlayer, - machineInfo.getOutsidePosition(serverPlayer.getServer()).getBlockPosition(), - m.getId()); - }); - }); - } - } -} diff --git a/src/main/java/dev/compactmods/machines/CompactMachines.java b/src/main/java/dev/compactmods/machines/CompactMachines.java new file mode 100644 index 00000000..ca60911f --- /dev/null +++ b/src/main/java/dev/compactmods/machines/CompactMachines.java @@ -0,0 +1,44 @@ +package dev.compactmods.machines; + +import dev.compactmods.machines.config.CommonConfig; +import dev.compactmods.machines.config.EnableVanillaRecipesConfigCondition; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.rooms.chunkloading.CMRoomChunkloadingManager; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Mod(CompactMachines.MOD_ID) +public class CompactMachines { + public static final String MOD_ID = "compactmachines"; + + public static final Logger LOGGER = LogManager.getLogger(); + + public static ItemGroup COMPACT_MACHINES_ITEMS = new ItemGroup(MOD_ID) { + @Override + public ItemStack makeIcon() { + return new ItemStack(Registration.MACHINE_BLOCK_ITEM_NORMAL.get()); + } + }; + + public static CMRoomChunkloadingManager CHUNKLOAD_MANAGER; + + public CompactMachines() { + // Register blocks and items + Registration.init(); + + ModLoadingContext mlCtx = ModLoadingContext.get(); + mlCtx.registerConfig(ModConfig.Type.COMMON, CommonConfig.CONFIG); + mlCtx.registerConfig(ModConfig.Type.SERVER, ServerConfig.CONFIG); + + CraftingHelper.register(EnableVanillaRecipesConfigCondition.Serializer.INSTANCE); + } +} diff --git a/src/main/java/dev/compactmods/machines/advancement/AdvancementTriggers.java b/src/main/java/dev/compactmods/machines/advancement/AdvancementTriggers.java new file mode 100644 index 00000000..d8e33f53 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/advancement/AdvancementTriggers.java @@ -0,0 +1,34 @@ +package dev.compactmods.machines.advancement; + +import dev.compactmods.machines.advancement.trigger.ClaimedMachineTrigger; +import dev.compactmods.machines.advancement.trigger.HowDidYouGetHereTrigger; +import dev.compactmods.machines.api.core.Advancements; +import dev.compactmods.machines.reference.EnumMachineSize; +import net.minecraft.advancements.CriteriaTriggers; + +public class AdvancementTriggers { + + public static final HowDidYouGetHereTrigger HOW_DID_YOU_GET_HERE = CriteriaTriggers.register(new HowDidYouGetHereTrigger()); + + public static final ClaimedMachineTrigger CLAIMED_TINY = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_TINY_MACHINE)); + public static final ClaimedMachineTrigger CLAIMED_SMALL = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_SMALL_MACHINE)); + public static final ClaimedMachineTrigger CLAIMED_NORMAL = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_NORMAL_MACHINE)); + public static final ClaimedMachineTrigger CLAIMED_LARGE = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_LARGE_MACHINE)); + public static final ClaimedMachineTrigger CLAIMED_GIANT = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_GIANT_MACHINE)); + public static final ClaimedMachineTrigger CLAIMED_MAX = CriteriaTriggers.register(new ClaimedMachineTrigger(Advancements.CLAIMED_MAX_MACHINE)); + + public static void init() {} + + public static ClaimedMachineTrigger getTriggerForMachineClaim(EnumMachineSize machineSize) { + switch (machineSize) { + case TINY: return CLAIMED_TINY; + case SMALL: return CLAIMED_SMALL; + case NORMAL: return CLAIMED_NORMAL; + case LARGE: return CLAIMED_LARGE; + case GIANT: return CLAIMED_GIANT; + case MAXIMUM: return CLAIMED_MAX; + } + + return CLAIMED_TINY; + } +} diff --git a/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListener.java b/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListener.java new file mode 100644 index 00000000..9680727a --- /dev/null +++ b/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListener.java @@ -0,0 +1,33 @@ +package dev.compactmods.machines.advancement; + +import java.util.Set; +import com.google.common.collect.Sets; +import net.minecraft.advancements.ICriterionInstance; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; + +public class GenericAdvancementTriggerListener { + + private final PlayerAdvancements advancements; + private final Set> listeners = Sets.newHashSet(); + + public GenericAdvancementTriggerListener(PlayerAdvancements advancements) { + this.advancements = advancements; + } + + public void add(ICriterionTrigger.Listener listener) { + listeners.add(listener); + } + + public void remove(ICriterionTrigger.Listener listener) { + listeners.remove(listener); + } + + public boolean empty() { + return listeners.isEmpty(); + } + + public void trigger() { + listeners.forEach(a -> a.run(advancements)); + } +} diff --git a/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListenerList.java b/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListenerList.java new file mode 100644 index 00000000..006fd488 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/advancement/GenericAdvancementTriggerListenerList.java @@ -0,0 +1,38 @@ +package dev.compactmods.machines.advancement; + +import javax.annotation.Nullable; +import java.util.Map; +import com.google.common.collect.Maps; +import net.minecraft.advancements.ICriterionInstance; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.entity.player.ServerPlayerEntity; + +public class GenericAdvancementTriggerListenerList { + private final Map> listeners = Maps.newHashMap(); + + + public void addPlayerListener(PlayerAdvancements advancements, ICriterionTrigger.Listener listener) { + GenericAdvancementTriggerListener listeners = this.listeners.computeIfAbsent(advancements, GenericAdvancementTriggerListener::new); + listeners.add(listener); + } + + public void removePlayerListener(PlayerAdvancements advancements, ICriterionTrigger.Listener listener) { + GenericAdvancementTriggerListener listeners = this.listeners.get(advancements); + if (listeners != null) { + listeners.remove(listener); + if (listeners.empty()) { + this.listeners.remove(advancements); + } + } + } + + public void removePlayerListeners(PlayerAdvancements advancements) { + this.listeners.remove(advancements); + } + + @Nullable + public GenericAdvancementTriggerListener getListeners(ServerPlayerEntity player) { + return listeners.get(player.getAdvancements()); + } +} diff --git a/src/main/java/dev/compactmods/machines/advancement/trigger/ClaimedMachineTrigger.java b/src/main/java/dev/compactmods/machines/advancement/trigger/ClaimedMachineTrigger.java new file mode 100644 index 00000000..b34620ad --- /dev/null +++ b/src/main/java/dev/compactmods/machines/advancement/trigger/ClaimedMachineTrigger.java @@ -0,0 +1,67 @@ +package dev.compactmods.machines.advancement.trigger; + +import com.google.gson.JsonObject; +import dev.compactmods.machines.advancement.GenericAdvancementTriggerListener; +import dev.compactmods.machines.advancement.GenericAdvancementTriggerListenerList; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.criterion.CriterionInstance; +import net.minecraft.advancements.criterion.EntityPredicate; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.loot.ConditionArrayParser; +import net.minecraft.util.ResourceLocation; + +public class ClaimedMachineTrigger implements ICriterionTrigger { + + private final GenericAdvancementTriggerListenerList listeners = new GenericAdvancementTriggerListenerList<>(); + private final ResourceLocation advancementId; + + public ClaimedMachineTrigger(ResourceLocation advancementId) { + this.advancementId = advancementId; + } + + @Override + public ResourceLocation getId() { + return advancementId; + } + + @Override + public void addPlayerListener(PlayerAdvancements advancements, Listener list) { + listeners.addPlayerListener(advancements, list); + } + + @Override + public void removePlayerListener(PlayerAdvancements advancements, Listener list) { + listeners.removePlayerListener(advancements, list); + } + + @Override + public void removePlayerListeners(PlayerAdvancements advancements) { + listeners.removePlayerListeners(advancements); + } + + @Override + public Instance createInstance(JsonObject json, ConditionArrayParser conditions) { + return new Instance(this.advancementId, EntityPredicate.AndPredicate.fromJson(json, "player", conditions)); + } + + public void trigger(ServerPlayerEntity player) { + final GenericAdvancementTriggerListener listeners = this.listeners.getListeners(player); + if(listeners != null) + listeners.trigger(); + } + + public static class Instance extends CriterionInstance { + + private final ResourceLocation advId; + + public Instance(ResourceLocation advId, EntityPredicate.AndPredicate player) { + super(advId, player); + this.advId = advId; + } + + public static Instance create(ResourceLocation advancement) { + return new Instance(advancement, EntityPredicate.AndPredicate.ANY); + } + } +} diff --git a/src/main/java/dev/compactmods/machines/advancement/trigger/HowDidYouGetHereTrigger.java b/src/main/java/dev/compactmods/machines/advancement/trigger/HowDidYouGetHereTrigger.java new file mode 100644 index 00000000..934de959 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/advancement/trigger/HowDidYouGetHereTrigger.java @@ -0,0 +1,60 @@ +package dev.compactmods.machines.advancement.trigger; + +import com.google.gson.JsonObject; +import dev.compactmods.machines.advancement.GenericAdvancementTriggerListener; +import dev.compactmods.machines.advancement.GenericAdvancementTriggerListenerList; +import dev.compactmods.machines.api.core.Advancements; +import net.minecraft.advancements.ICriterionTrigger; +import net.minecraft.advancements.PlayerAdvancements; +import net.minecraft.advancements.criterion.CriterionInstance; +import net.minecraft.advancements.criterion.EntityPredicate; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.loot.ConditionArrayParser; +import net.minecraft.util.ResourceLocation; + +public class HowDidYouGetHereTrigger implements ICriterionTrigger { + + private final GenericAdvancementTriggerListenerList listeners = new GenericAdvancementTriggerListenerList<>(); + + @Override + public ResourceLocation getId() { + return Advancements.HOW_DID_YOU_GET_HERE; + } + + @Override + public void addPlayerListener(PlayerAdvancements advancements, Listener list) { + listeners.addPlayerListener(advancements, list); + } + + @Override + public void removePlayerListener(PlayerAdvancements advancements, Listener list) { + listeners.removePlayerListener(advancements, list); + } + + @Override + public void removePlayerListeners(PlayerAdvancements advancements) { + listeners.removePlayerListeners(advancements); + } + + @Override + public Instance createInstance(JsonObject json, ConditionArrayParser conditions) { + return new Instance(EntityPredicate.AndPredicate.fromJson(json, "player", conditions)); + } + + public void trigger(ServerPlayerEntity player) { + final GenericAdvancementTriggerListener listeners = this.listeners.getListeners(player); + if(listeners != null) + listeners.trigger(); + } + + public static class Instance extends CriterionInstance { + + public Instance(EntityPredicate.AndPredicate player) { + super(Advancements.HOW_DID_YOU_GET_HERE, player); + } + + public static Instance create() { + return new Instance(EntityPredicate.AndPredicate.ANY); + } + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/block/BlockCompactMachine.java b/src/main/java/dev/compactmods/machines/block/BlockCompactMachine.java similarity index 60% rename from src/main/java/com/robotgryphon/compactmachines/block/BlockCompactMachine.java rename to src/main/java/dev/compactmods/machines/block/BlockCompactMachine.java index db86f52a..6b3cbd20 100644 --- a/src/main/java/com/robotgryphon/compactmachines/block/BlockCompactMachine.java +++ b/src/main/java/dev/compactmods/machines/block/BlockCompactMachine.java @@ -1,27 +1,26 @@ -package com.robotgryphon.compactmachines.block; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneReaderTunnel; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneTunnel; -import com.robotgryphon.compactmachines.block.tiles.CompactMachineTile; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.compat.theoneprobe.providers.CompactMachineProvider; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeData; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeDataProvider; -import com.robotgryphon.compactmachines.config.CommonConfig; -import com.robotgryphon.compactmachines.config.ServerConfig; -import com.robotgryphon.compactmachines.core.EnumMachinePlayersBreakHandling; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; -import com.robotgryphon.compactmachines.reference.Reference; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; -import com.robotgryphon.compactmachines.util.CompactMachineUtil; +package dev.compactmods.machines.block; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.api.tunnels.redstone.IRedstoneReaderTunnel; +import dev.compactmods.machines.block.tiles.CompactMachineTile; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.compat.theoneprobe.IProbeData; +import dev.compactmods.machines.compat.theoneprobe.IProbeDataProvider; +import dev.compactmods.machines.compat.theoneprobe.providers.CompactMachineProvider; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.core.EnumMachinePlayersBreakHandling; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.tunnels.TunnelHelper; +import dev.compactmods.machines.util.PlayerUtil; +import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.LivingEntity; 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.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -32,8 +31,6 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorld; -import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; @@ -43,8 +40,6 @@ import java.util.Set; import java.util.UUID; -import net.minecraft.block.AbstractBlock; - public class BlockCompactMachine extends Block implements IProbeDataProvider { private final EnumMachineSize size; @@ -94,7 +89,7 @@ public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos @Override public int getSignal(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) { -// TODO Tile Entity +// TODO Redstone out tunnels // if(!(blockAccess.getTileEntity(pos) instanceof TileEntityMachine)) { // return 0; // } @@ -156,29 +151,86 @@ public void neighborChanged(BlockState state, World world, BlockPos pos, Block c }); } + + public static EnumMachineSize getMachineSizeFromNBT(@Nullable CompoundNBT tag) { + try { + if (tag == null) + return EnumMachineSize.TINY; + + if (!tag.contains("size")) + return EnumMachineSize.TINY; + + String sizeFromTag = tag.getString("size"); + return EnumMachineSize.getFromSize(sizeFromTag); + } catch (Exception ex) { + return EnumMachineSize.TINY; + } + } + + public static Block getBySize(EnumMachineSize size) { + switch (size) { + case TINY: + return Registration.MACHINE_BLOCK_TINY.get(); + + case SMALL: + return Registration.MACHINE_BLOCK_SMALL.get(); + + case NORMAL: + return Registration.MACHINE_BLOCK_NORMAL.get(); + + case LARGE: + return Registration.MACHINE_BLOCK_LARGE.get(); + + case GIANT: + return Registration.MACHINE_BLOCK_GIANT.get(); + + case MAXIMUM: + return Registration.MACHINE_BLOCK_MAXIMUM.get(); + } + + return Registration.MACHINE_BLOCK_NORMAL.get(); + } + + public static Item getItemBySize(EnumMachineSize size) { + switch (size) { + case TINY: + return Registration.MACHINE_BLOCK_ITEM_TINY.get(); + + case SMALL: + return Registration.MACHINE_BLOCK_ITEM_SMALL.get(); + + case NORMAL: + return Registration.MACHINE_BLOCK_ITEM_NORMAL.get(); + + case LARGE: + return Registration.MACHINE_BLOCK_ITEM_LARGE.get(); + + case GIANT: + return Registration.MACHINE_BLOCK_ITEM_GIANT.get(); + + case MAXIMUM: + return Registration.MACHINE_BLOCK_ITEM_MAXIMUM.get(); + } + + return Registration.MACHINE_BLOCK_ITEM_NORMAL.get(); + } + @Override public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player) { - Block given = CompactMachineUtil.getMachineBlockBySize(this.size); + Block given = getBySize(this.size); ItemStack stack = new ItemStack(given, 1); CompoundNBT nbt = stack.getOrCreateTagElement("cm"); nbt.putString("size", this.size.getName()); CompactMachineTile tileEntity = (CompactMachineTile) world.getBlockEntity(pos); - if (tileEntity != null) { + if (tileEntity != null && tileEntity.mapped()) { nbt.putInt("coords", tileEntity.machineId); } return stack; } - -// @Override -// public String getSpecialName(ItemStack stack) { -// return this.getStateFromMeta(stack.getItemDamage()).getValue(SIZE).getName(); -// } - - @Override public boolean hasTileEntity(BlockState state) { return true; @@ -190,27 +242,6 @@ public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new CompactMachineTile(); } - @Override - public void destroy(IWorld world, BlockPos pos, BlockState state) { - if (world.isClientSide()) { - super.destroy(world, pos, state); - return; - } - - if (!(world.getBlockEntity(pos) instanceof CompactMachineTile)) { - return; - } - - CompactMachineTile te = (CompactMachineTile) world.getBlockEntity(pos); -// WorldSavedDataMachines.INSTANCE.removeMachinePosition(te.coords); -// -// BlockMachine.spawnItemWithNBT(world, pos, state.get(BlockMachine.SIZE), te); -// -// ChunkLoadingMachines.unforceChunk(te.coords); - - super.destroy(world, pos, state); - } - @Override public void setPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { @@ -233,56 +264,24 @@ public void setPlacedBy(World worldIn, BlockPos pos, BlockState state, @Nullable // tile.setCustomName(stack.getDisplayName()); // } - CompoundNBT nbt = stack.getOrCreateTag(); - - if (nbt.contains(Reference.CompactMachines.OWNER_NBT)) { - tile.setOwner(nbt.getUUID(Reference.CompactMachines.OWNER_NBT)); - } + if(!stack.hasTag()) + return; - if (!tile.getOwnerUUID().isPresent() && placer instanceof PlayerEntity) { - tile.setOwner(placer.getUUID()); - } + CompoundNBT nbt = stack.getTag(); + if(nbt == null) + return; if (nbt.contains("cm")) { CompoundNBT machineData = nbt.getCompound("cm"); if (machineData.contains("coords")) { int machineID = machineData.getInt("coords"); tile.setMachineId(machineID); - - CompactMachineUtil.updateMachineInWorldPosition(serverWorld, machineID, pos); } } tile.doPostPlaced(); - tile.setChanged(); } -// // TODO: Allow storing of schemas in machines -// if(stack.hasTag()) { -// if(stack.getTag().contains("coords")) { -// int coords = stack.getTag().getInt("coords"); -// if (coords != -1) { -// tileEntityMachine.coords = coords; -// if(!world.isRemote) { -// WorldSavedDataMachines.INSTANCE.addMachinePosition(tileEntityMachine.coords, pos, world.provider.getDimension(), tileEntityMachine.getSize()); -// StructureTools.setBiomeForCoords(coords, world.getBiome(pos)); -// } -// } -// } -// -// if(stack.getTag().contains("schema")) { -// tileEntityMachine.setSchema(stack.getTag().getString("schema")); -// } -// - -// } -// - -// -// tileEntityMachine.markDirty(); -// } - - @Override public ActionResultType use(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (worldIn.isClientSide()) @@ -293,16 +292,14 @@ public ActionResultType use(BlockState state, World worldIn, BlockPos pos, Playe ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; - TileEntity te = worldIn.getBlockEntity(pos); - CompactMachineTile tile = (CompactMachineTile) te; - ItemStack mainItem = player.getMainHandItem(); if (mainItem.isEmpty()) return ActionResultType.PASS; + // TODO - Item tags instead of direct item reference here if (mainItem.getItem() == Registration.PERSONAL_SHRINKING_DEVICE.get()) { // Try teleport to compact machine dimension - CompactMachineUtil.teleportInto(serverPlayer, pos, size); + PlayerUtil.teleportPlayerIntoMachine(serverPlayer, pos, size); } } @@ -315,48 +312,6 @@ public EnumMachineSize getSize() { @Override public void addProbeData(IProbeData data, PlayerEntity player, World world, BlockState state) { - CompactMachineProvider.exec(data, player, world, state); + CompactMachineProvider.exec(data, world); } - - // 1.12.1 code -// @Override -// public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { -// if(player.isSneaking()) { -// return false; -// } -// -// if(world.isRemote || !(player instanceof EntityPlayerMP)) { -// return true; -// } -// -// if(!(world.getTileEntity(pos) instanceof TileEntityMachine)) { -// return false; -// } -// -// TileEntityMachine machine = (TileEntityMachine)world.getTileEntity(pos); -// ItemStack playerStack = player.getHeldItemMainhand(); -// if(ShrinkingDeviceUtils.isShrinkingDevice(playerStack)) { -// TeleportationTools.tryToEnterMachine(player, machine); -// return true; -// } -// -// player.openGui(compactmachines.instance, GuiIds.MACHINE_VIEW.ordinal(), world, pos.getX(), pos.getY(), pos.getZ()); -// PackageHandler.instance.sendTo(new MessageMachineContent(machine.coords), (EntityPlayerMP)player); -// PackageHandler.instance.sendTo(new MessageMachineChunk(machine.coords), (EntityPlayerMP)player); -// -// return true; -// } - -// TOP code -// @Override -// public String getID() { -// return CompactMachines.MODID + ":" + "machine"; -// } -// -// @Override -// public void addProbeInfo(ProbeMode mode, IProbeInfo probeInfo, PlayerEntity player, World world, BlockState blockState, IProbeHitData data) { -// String size = this.size.getName(); -// probeInfo.text(new TranslationTextComponent("machines.sizes." + size)); -// - // } } diff --git a/src/main/java/dev/compactmods/machines/block/tiles/CompactMachineTile.java b/src/main/java/dev/compactmods/machines/block/tiles/CompactMachineTile.java new file mode 100644 index 00000000..313d9083 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/block/tiles/CompactMachineTile.java @@ -0,0 +1,322 @@ +package dev.compactmods.machines.block.tiles; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.tunnels.ICapableTunnel; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.CompactRoomData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import dev.compactmods.machines.reference.Reference; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.tunnels.TunnelHelper; +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.concurrent.TickDelayedTask; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; + +public class CompactMachineTile extends TileEntity implements ICapabilityProvider, ITickableTileEntity { + public int machineId = -1; + private final boolean initialized = false; + public boolean alreadyNotifiedOnTick = false; + public long nextSpawnTick = 0; + + protected UUID owner; + protected String schema; + protected boolean locked = false; + + public CompactMachineTile() { + super(Registration.MACHINE_TILE_ENTITY.get()); + } + + @Override + public void clearRemoved() { + super.clearRemoved(); + } + + @Override + public void load(BlockState state, CompoundNBT nbt) { + super.load(state, nbt); + + machineId = nbt.getInt("coords"); + // TODO customName = nbt.getString("CustomName"); + if (nbt.contains(Reference.CompactMachines.OWNER_NBT)) { + owner = nbt.getUUID(Reference.CompactMachines.OWNER_NBT); + } else { + owner = null; + } + + nextSpawnTick = nbt.getLong("spawntick"); + if (nbt.contains("schema")) { + schema = nbt.getString("schema"); + } else { + schema = null; + } + + if (nbt.contains("locked")) { + locked = nbt.getBoolean("locked"); + } else { + locked = false; + } + } + + @Override + public CompoundNBT save(CompoundNBT nbt) { + nbt = super.save(nbt); + + nbt.putInt("coords", machineId); + // nbt.putString("CustomName", customName.getString()); + + if (owner != null) { + nbt.putUUID(Reference.CompactMachines.OWNER_NBT, this.owner); + } + + nbt.putLong("spawntick", nextSpawnTick); + if (schema != null) { + nbt.putString("schema", schema); + } + + nbt.putBoolean("locked", locked); + + return nbt; + } + + @Nullable + @Override + public SUpdateTileEntityPacket getUpdatePacket() { + return new SUpdateTileEntityPacket(worldPosition, 1, getUpdateTag()); + } + + @Override + public CompoundNBT getUpdateTag() { + CompoundNBT base = super.getUpdateTag(); + base.putInt("machine", this.machineId); + + if (level instanceof ServerWorld) { + // TODO - Internal player list +// Optional playerData = Optional.empty(); +// try { +// CompactMachinePlayerData psd = CompactMachinePlayerData.get(level.getServer()); +// // psd = psd.getPlayersInside(this.machineId); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// playerData.ifPresent(data -> { +// CompoundNBT playerNbt = data.serializeNBT(); +// base.put("players", playerNbt); +// }); + + if (this.owner != null) + base.putUUID("owner", this.owner); + } + + return base; + } + + public Optional getInternalChunkPos() { + if (level instanceof ServerWorld) { + MinecraftServer serv = level.getServer(); + if (serv == null) + return Optional.empty(); + + MachineConnections connections = MachineConnections.get(serv); + if (connections == null) + return Optional.empty(); + + return connections.graph.getConnectedRoom(this.machineId); + } + + return Optional.empty(); + } + + @Override + public void handleUpdateTag(BlockState state, CompoundNBT tag) { + super.handleUpdateTag(state, tag); + + this.machineId = tag.getInt("machine"); + if (tag.contains("players")) { + CompoundNBT players = tag.getCompound("players"); + // playerData = CompactMachinePlayerData.fromNBT(players); + + } + + if (tag.contains("owner")) + owner = tag.getUUID("owner"); + } + + @Override + public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) { + BlockState state = null; + if (this.level != null) { + state = this.level.getBlockState(worldPosition); + } + + load(state, pkt.getTag()); + } + + @Override + public void tick() { + + } + + public Optional getOwnerUUID() { + return Optional.ofNullable(this.owner); + } + + public void setOwner(UUID owner) { + this.owner = owner; + } + + public void setMachineId(int id) { + this.machineId = id; + this.setChanged(); + } + + public boolean hasPlayersInside() { + return false; + // TODO +// return CompactMachineCommonData +// .getInstance() +// .getPlayerData(machineId) +// .map(CompactMachinePlayerData::hasPlayers) +// .orElse(false); + } + + public void doPostPlaced() { + if (this.level == null || this.level.isClientSide) { + return; + } + + MinecraftServer serv = this.level.getServer(); + if (serv == null) + return; + + DimensionalPosition dp = new DimensionalPosition( + this.level.dimension(), + this.worldPosition + ); + + CompactMachineData extern = CompactMachineData.get(serv); + extern.setMachineLocation(this.machineId, dp); + + this.setChanged(); + } + + public void handlePlayerLeft(UUID playerID) { + // TODO + } + + public void handlePlayerEntered(UUID playerID) { + // TODO + } + + public boolean mapped() { + return getInternalChunkPos().isPresent(); + } + + public Optional getSpawn() { + if (level instanceof ServerWorld) { + ServerWorld serverWorld = (ServerWorld) level; + MinecraftServer serv = serverWorld.getServer(); + + MachineConnections connections = MachineConnections.get(serv); + if (connections == null) + return Optional.empty(); + + Optional connectedRoom = connections.graph.getConnectedRoom(machineId); + + if (!connectedRoom.isPresent()) + return Optional.empty(); + + CompactRoomData roomData = CompactRoomData.get(serv); + if (roomData == null) + return Optional.empty(); + + ChunkPos chunk = connectedRoom.get(); + return Optional.ofNullable(roomData.getSpawn(chunk)); + } + + return Optional.empty(); + } + +// @Override +// public void update() { +// if (!this.initialized && !this.isInvalid() && this.coords != -1) { +// initialize(); +// this.initialized = true; +// } +// +// this.alreadyNotifiedOnTick = false; +// +// if (nextSpawnTick == 0) { +// nextSpawnTick = this.getWorld().getTotalWorldTime() + ConfigurationHandler.MachineSettings.spawnRate; +// } +// +// if (!this.getWorld().isRemote && this.coords != -1 && isInsideItself()) { +// if (this.getWorld().getTotalWorldTime() % 20 == 0) { +// world.playSound(null, getPos(), +// SoundEvent.REGISTRY.getObject(new ResourceLocation("entity.wither.spawn")), +// SoundCategory.MASTER, +// 1.0f, +// 1.0f +// ); +// } +// } +// +// if (!this.getWorld().isRemote && this.coords != -1 && this.getWorld().getTotalWorldTime() > nextSpawnTick) { +// if (ConfigurationHandler.MachineSettings.allowPeacefulSpawns || ConfigurationHandler.MachineSettings.allowHostileSpawns) { +// SpawnTools.spawnEntitiesInMachine(coords); +// } +// +// nextSpawnTick = this.getWorld().getTotalWorldTime() + ConfigurationHandler.MachineSettings.spawnRate; +// this.markDirty(); +// } +// +// /* +// // Use this once we render in world or use the proxy world to determine client side capabilities. +// if(!this.getWorld().isRemote && this.getWorld().getTotalWorldTime() % 20 == 0 && this.coords != -1) { +// PackageHandler.instance.sendToAllAround(new MessageMachineChunk(this.coords), new NetworkRegistry.TargetPoint(this.world.provider.getDimension(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ(), 32.0f)); +// } +// */ +// } + +// @Override +// public void onChunkUnload() { +// super.onChunkUnload(); +// if (this.getWorld().isRemote) { +// return; +// } +// +// if (ConfigurationHandler.Settings.forceLoadChunks) { +// return; +// } +// +// ChunkLoadingMachines.unforceChunk(this.coords); +// } +// +// public boolean isInsideItself() { +// if (this.getWorld().provider.getDimension() != ConfigurationHandler.Settings.dimensionId) { +// return false; +// } +// +// return StructureTools.getCoordsForPos(this.getPos()) == this.coords; +// } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/block/tiles/MachineWhitelisting.txt b/src/main/java/dev/compactmods/machines/block/tiles/MachineWhitelisting.txt similarity index 100% rename from src/main/java/com/robotgryphon/compactmachines/block/tiles/MachineWhitelisting.txt rename to src/main/java/dev/compactmods/machines/block/tiles/MachineWhitelisting.txt diff --git a/src/main/java/dev/compactmods/machines/block/tiles/TunnelWallTile.java b/src/main/java/dev/compactmods/machines/block/tiles/TunnelWallTile.java new file mode 100644 index 00000000..21a9fd1e --- /dev/null +++ b/src/main/java/dev/compactmods/machines/block/tiles/TunnelWallTile.java @@ -0,0 +1,176 @@ +package dev.compactmods.machines.block.tiles; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.api.tunnels.ICapableTunnel; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import dev.compactmods.machines.network.NetworkHandler; +import dev.compactmods.machines.network.TunnelAddedPacket; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.tunnels.TunnelHelper; +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.fml.network.PacketDistributor; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemStackHandler; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class TunnelWallTile extends TileEntity implements ITickableTileEntity { + + private int connectedMachine; + private ResourceLocation tunnelType; + + private final HashMap, LazyOptional> capabilityCache; + + public TunnelWallTile() { + super(Registration.TUNNEL_WALL_TILE.get()); + this.capabilityCache = new HashMap<>(); + } + + @Override + public void load(BlockState state, CompoundNBT nbt) { + super.load(state, nbt); + + if (nbt.contains("tunnel_type")) { + ResourceLocation type = new ResourceLocation(nbt.getString("tunnel_type")); + this.tunnelType = type; + } + + if (nbt.contains("machine")) { + this.connectedMachine = nbt.getInt("machine"); + } + } + + @Override + public CompoundNBT save(CompoundNBT compound) { + compound = super.save(compound); + compound.putString("tunnel_type", tunnelType.toString()); + compound.putInt("machine", connectedMachine); + return compound; + } + + @Override + public CompoundNBT getUpdateTag() { + CompoundNBT nbt = super.getUpdateTag(); + nbt.putString("tunnel_type", tunnelType.toString()); + nbt.putInt("machine", connectedMachine); + return nbt; + } + + @Override + public void handleUpdateTag(BlockState state, CompoundNBT tag) { + super.handleUpdateTag(state, tag); + + if (tag.contains("tunnel_type")) { + this.tunnelType = new ResourceLocation(tag.getString("tunnel_type")); + } + + if (tag.contains("machine")) { + this.connectedMachine = tag.getInt("machine"); + } + } + + public Optional getConnectedPosition() { + return Optional.empty(); + } + + private Optional tryFindExternalMachineByChunkPos(MachineConnections connections) { + ChunkPos thisMachineChunk = new ChunkPos(worldPosition); + Collection externalMachineIDs = connections.graph.getMachinesFor(thisMachineChunk); + + // This shouldn't happen - there should always be at least one machine attached externally + // If this DOES happen, it's probably a migration failure or the block was destroyed without notification + if (externalMachineIDs.isEmpty()) { + CompactMachines.LOGGER.warn("Warning: Tunnel applied to a machine but no external machine data found."); + CompactMachines.LOGGER.warn("Please validate the tunnel at: " + worldPosition.toShortString()); + return Optional.empty(); + } + + int first = externalMachineIDs.stream().findFirst().orElse(-1); + // sanity - makes compiler happier, we already did a check above for empty state + if (first == -1) return Optional.empty(); + + // In theory, we can re-attach the tunnel to the first found external machine, if the saved data + // does not actually contain an attached external id + return Optional.of(first); + } + + /** + * Gets the side the tunnel is placed on (the wall inside the machine) + * + * @return + */ + public Direction getTunnelSide() { + BlockState state = getBlockState(); + return state.getValue(TunnelWallBlock.TUNNEL_SIDE); + } + + /** + * Gets the side the tunnel connects to externally (the machine side) + * + * @return + */ + public Direction getConnectedSide() { + BlockState blockState = getBlockState(); + return blockState.getValue(TunnelWallBlock.CONNECTED_SIDE); + } + + public Optional getTunnelDefinitionId() { + return Optional.ofNullable(this.tunnelType); + } + + public Optional getTunnelDefinition() { + if (tunnelType == null) + return Optional.empty(); + + TunnelDefinition definition = GameRegistry + .findRegistry(TunnelDefinition.class) + .getValue(tunnelType); + + return Optional.ofNullable(definition); + } + + public void setTunnelType(ResourceLocation registryName) { + this.tunnelType = registryName; + + if (level != null && !level.isClientSide()) { + setChanged(); + + TunnelAddedPacket pkt = new TunnelAddedPacket(worldPosition, registryName); + + Chunk chunkAt = level.getChunkAt(worldPosition); + NetworkHandler.MAIN_CHANNEL + .send(PacketDistributor.TRACKING_CHUNK.with(() -> chunkAt), pkt); + } + } + + @Override + public void tick() { + // first tick - unset this block, tunnels will be reimplemented in 1.17 + level.setBlockAndUpdate(worldPosition, Registration.BLOCK_SOLID_WALL.get().defaultBlockState()); + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/block/walls/BreakableWallBlock.java b/src/main/java/dev/compactmods/machines/block/walls/BreakableWallBlock.java similarity index 80% rename from src/main/java/com/robotgryphon/compactmachines/block/walls/BreakableWallBlock.java rename to src/main/java/dev/compactmods/machines/block/walls/BreakableWallBlock.java index 3f2564a3..a6789f7a 100644 --- a/src/main/java/com/robotgryphon/compactmachines/block/walls/BreakableWallBlock.java +++ b/src/main/java/dev/compactmods/machines/block/walls/BreakableWallBlock.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.block.walls; +package dev.compactmods.machines.block.walls; import net.minecraft.block.Block; diff --git a/src/main/java/com/robotgryphon/compactmachines/block/walls/ProtectedWallBlock.java b/src/main/java/dev/compactmods/machines/block/walls/ProtectedWallBlock.java similarity index 96% rename from src/main/java/com/robotgryphon/compactmachines/block/walls/ProtectedWallBlock.java rename to src/main/java/dev/compactmods/machines/block/walls/ProtectedWallBlock.java index ed252e60..50300d42 100644 --- a/src/main/java/com/robotgryphon/compactmachines/block/walls/ProtectedWallBlock.java +++ b/src/main/java/dev/compactmods/machines/block/walls/ProtectedWallBlock.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.block.walls; +package dev.compactmods.machines.block.walls; import net.minecraft.block.Block; import net.minecraft.block.BlockState; diff --git a/src/main/java/com/robotgryphon/compactmachines/block/walls/SolidWallBlock.java b/src/main/java/dev/compactmods/machines/block/walls/SolidWallBlock.java similarity index 79% rename from src/main/java/com/robotgryphon/compactmachines/block/walls/SolidWallBlock.java rename to src/main/java/dev/compactmods/machines/block/walls/SolidWallBlock.java index 5101b500..34206517 100644 --- a/src/main/java/com/robotgryphon/compactmachines/block/walls/SolidWallBlock.java +++ b/src/main/java/dev/compactmods/machines/block/walls/SolidWallBlock.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.block.walls; +package dev.compactmods.machines.block.walls; -import com.robotgryphon.compactmachines.config.ServerConfig; +import dev.compactmods.machines.config.ServerConfig; import net.minecraft.block.BlockState; import net.minecraft.entity.EntitySpawnPlacementRegistry; import net.minecraft.entity.EntityType; @@ -9,8 +9,6 @@ import javax.annotation.Nullable; -import net.minecraft.block.AbstractBlock.Properties; - public class SolidWallBlock extends ProtectedWallBlock { public SolidWallBlock(Properties props) { super(props); diff --git a/src/main/java/com/robotgryphon/compactmachines/block/walls/TunnelWallBlock.java b/src/main/java/dev/compactmods/machines/block/walls/TunnelWallBlock.java similarity index 54% rename from src/main/java/com/robotgryphon/compactmachines/block/walls/TunnelWallBlock.java rename to src/main/java/dev/compactmods/machines/block/walls/TunnelWallBlock.java index e886adb0..d7eaf154 100644 --- a/src/main/java/com/robotgryphon/compactmachines/block/walls/TunnelWallBlock.java +++ b/src/main/java/dev/compactmods/machines/block/walls/TunnelWallBlock.java @@ -1,14 +1,14 @@ -package com.robotgryphon.compactmachines.block.walls; - -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeData; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeDataProvider; -import com.robotgryphon.compactmachines.compat.theoneprobe.providers.TunnelProvider; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneReaderTunnel; +package dev.compactmods.machines.block.walls; + +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.compat.theoneprobe.IProbeData; +import dev.compactmods.machines.compat.theoneprobe.IProbeDataProvider; +import dev.compactmods.machines.compat.theoneprobe.providers.TunnelProvider; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.tunnels.TunnelHelper; +import dev.compactmods.machines.api.tunnels.redstone.IRedstoneReaderTunnel; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; @@ -26,12 +26,11 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nullable; import java.util.Optional; -import net.minecraft.block.AbstractBlock.Properties; - public class TunnelWallBlock extends ProtectedWallBlock implements IProbeDataProvider { public static DirectionProperty TUNNEL_SIDE = DirectionProperty.create("tunnel_side", Direction.values()); public static DirectionProperty CONNECTED_SIDE = DirectionProperty.create("connected_side", Direction.values()); @@ -57,22 +56,12 @@ public Optional getTunnelInfo(IBlockReader world, BlockPos pos @Override public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos pos, @Nullable Direction side) { - Optional tunnelInfo = getTunnelInfo(world, pos); - if (!tunnelInfo.isPresent()) - return false; - - TunnelDefinition definition = tunnelInfo.get(); - if (definition instanceof IRedstoneReaderTunnel) { - ITunnelConnectionInfo conn = TunnelHelper.generateConnectionInfo(world, pos); - return ((IRedstoneReaderTunnel) definition).canConnectRedstone(conn); - } - return false; } @Override public boolean isSignalSource(BlockState state) { - return state.getValue(REDSTONE); + return false; } @Override @@ -96,44 +85,6 @@ public int getSignal(BlockState state, IBlockReader world, BlockPos pos, Directi return 0; } - @Override - public ActionResultType use(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { - if (worldIn.isClientSide()) - return ActionResultType.SUCCESS; - - - if (player.isShiftKeyDown()) { - Optional tunnelDef = getTunnelInfo(worldIn, pos); - - if (!tunnelDef.isPresent()) - return ActionResultType.FAIL; - - BlockState solidWall = Registration.BLOCK_SOLID_WALL.get().defaultBlockState(); - - worldIn.setBlockAndUpdate(pos, solidWall); - - TunnelDefinition tunnelRegistration = tunnelDef.get(); - ItemStack stack = new ItemStack(Registration.ITEM_TUNNEL.get(), 1); - CompoundNBT defTag = stack.getOrCreateTagElement("definition"); - defTag.putString("id", tunnelRegistration.getRegistryName().toString()); - - ItemEntity ie = new ItemEntity(worldIn, player.getX(), player.getY(), player.getZ(), stack); - worldIn.addFreshEntity(ie); - -// IFormattableTextComponent t = new StringTextComponent(tunnelRegistration.getRegistryName().toString()) -// .mergeStyle(TextFormatting.GRAY); -// -// player.sendStatusMessage(t, true); - } else { - // Rotate tunnel - Direction dir = state.getValue(CONNECTED_SIDE); - Direction nextDir = TunnelHelper.getNextDirection(dir); - - worldIn.setBlockAndUpdate(pos, state.setValue(CONNECTED_SIDE, nextDir)); - } - return ActionResultType.SUCCESS; - } - @Override protected void createBlockStateDefinition(StateContainer.Builder builder) { builder.add(TUNNEL_SIDE).add(CONNECTED_SIDE).add(REDSTONE); diff --git a/src/main/java/com/robotgryphon/compactmachines/client/ClientEventHandler.java b/src/main/java/dev/compactmods/machines/client/ClientEventHandler.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/client/ClientEventHandler.java rename to src/main/java/dev/compactmods/machines/client/ClientEventHandler.java index ed5b8bfe..81a7b054 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/ClientEventHandler.java +++ b/src/main/java/dev/compactmods/machines/client/ClientEventHandler.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.client; +package dev.compactmods.machines.client; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.core.Registration; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.core.Registration; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraftforge.api.distmarker.Dist; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/ClientTunnelHandler.java b/src/main/java/dev/compactmods/machines/client/ClientTunnelHandler.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/client/ClientTunnelHandler.java rename to src/main/java/dev/compactmods/machines/client/ClientTunnelHandler.java index ae4169f4..c855731b 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/ClientTunnelHandler.java +++ b/src/main/java/dev/compactmods/machines/client/ClientTunnelHandler.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.client; +package dev.compactmods.machines.client; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.block.tiles.TunnelWallTile; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.world.ClientWorld; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/TunnelColors.java b/src/main/java/dev/compactmods/machines/client/TunnelColors.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/client/TunnelColors.java rename to src/main/java/dev/compactmods/machines/client/TunnelColors.java index e339f50b..1042febd 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/TunnelColors.java +++ b/src/main/java/dev/compactmods/machines/client/TunnelColors.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.client; +package dev.compactmods.machines.client; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.color.IBlockColor; import net.minecraft.tileentity.TileEntity; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/TunnelItemColor.java b/src/main/java/dev/compactmods/machines/client/TunnelItemColor.java similarity index 77% rename from src/main/java/com/robotgryphon/compactmachines/client/TunnelItemColor.java rename to src/main/java/dev/compactmods/machines/client/TunnelItemColor.java index 84db4885..6239d604 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/TunnelItemColor.java +++ b/src/main/java/dev/compactmods/machines/client/TunnelItemColor.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.client; +package dev.compactmods.machines.client; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.item.TunnelItem; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.item.TunnelItem; import net.minecraft.client.renderer.color.IItemColor; import net.minecraft.item.ItemStack; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/gui/PersonalShrinkingDeviceScreen.java b/src/main/java/dev/compactmods/machines/client/gui/PersonalShrinkingDeviceScreen.java similarity index 93% rename from src/main/java/com/robotgryphon/compactmachines/client/gui/PersonalShrinkingDeviceScreen.java rename to src/main/java/dev/compactmods/machines/client/gui/PersonalShrinkingDeviceScreen.java index 3124b660..0de7fddc 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/gui/PersonalShrinkingDeviceScreen.java +++ b/src/main/java/dev/compactmods/machines/client/gui/PersonalShrinkingDeviceScreen.java @@ -1,9 +1,9 @@ -package com.robotgryphon.compactmachines.client.gui; +package dev.compactmods.machines.client.gui; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.client.gui.guide.GuideSection; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.client.gui.guide.GuideSection; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.Screen; import net.minecraft.util.ResourceLocation; @@ -22,7 +22,7 @@ public class PersonalShrinkingDeviceScreen extends Screen { private final ResourceLocation emptySection = new ResourceLocation(CompactMachines.MOD_ID, "empty"); @Nullable - private GuideSection currentSection; + private final GuideSection currentSection; protected PersonalShrinkingDeviceScreen() { super(new TranslationTextComponent(CompactMachines.MOD_ID + ".gui.psd.title")); diff --git a/src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuidePage.java b/src/main/java/dev/compactmods/machines/client/gui/guide/GuidePage.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuidePage.java rename to src/main/java/dev/compactmods/machines/client/gui/guide/GuidePage.java index 87cc7ba5..32835a05 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuidePage.java +++ b/src/main/java/dev/compactmods/machines/client/gui/guide/GuidePage.java @@ -1,9 +1,9 @@ -package com.robotgryphon.compactmachines.client.gui.guide; +package dev.compactmods.machines.client.gui.guide; import com.mojang.blaze3d.matrix.MatrixStack; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.client.gui.widget.AbstractCMGuiWidget; -import com.robotgryphon.compactmachines.client.gui.widget.ScrollableWrappedTextWidget; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.client.gui.widget.AbstractCMGuiWidget; +import dev.compactmods.machines.client.gui.widget.ScrollableWrappedTextWidget; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; import net.minecraft.client.gui.FontRenderer; @@ -11,7 +11,6 @@ import net.minecraft.client.gui.IRenderable; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; -import net.minecraftforge.common.util.Constants; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuideSection.java b/src/main/java/dev/compactmods/machines/client/gui/guide/GuideSection.java similarity index 90% rename from src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuideSection.java rename to src/main/java/dev/compactmods/machines/client/gui/guide/GuideSection.java index 489fb100..6e131073 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/gui/guide/GuideSection.java +++ b/src/main/java/dev/compactmods/machines/client/gui/guide/GuideSection.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.client.gui.guide; +package dev.compactmods.machines.client.gui.guide; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.IGuiEventListener; @@ -9,8 +9,8 @@ public class GuideSection implements IRenderable, IGuiEventListener { private final List pages; - private int currentPageIndex = 0; - private GuidePage currentPage; + private final int currentPageIndex = 0; + private final GuidePage currentPage; public GuideSection() { this.pages = new ArrayList<>(); diff --git a/src/main/java/com/robotgryphon/compactmachines/client/gui/widget/AbstractCMGuiWidget.java b/src/main/java/dev/compactmods/machines/client/gui/widget/AbstractCMGuiWidget.java similarity index 92% rename from src/main/java/com/robotgryphon/compactmachines/client/gui/widget/AbstractCMGuiWidget.java rename to src/main/java/dev/compactmods/machines/client/gui/widget/AbstractCMGuiWidget.java index 644e83a4..d9fc6451 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/gui/widget/AbstractCMGuiWidget.java +++ b/src/main/java/dev/compactmods/machines/client/gui/widget/AbstractCMGuiWidget.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.client.gui.widget; +package dev.compactmods.machines.client.gui.widget; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.IGuiEventListener; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/gui/widget/ScrollableWrappedTextWidget.java b/src/main/java/dev/compactmods/machines/client/gui/widget/ScrollableWrappedTextWidget.java similarity index 88% rename from src/main/java/com/robotgryphon/compactmachines/client/gui/widget/ScrollableWrappedTextWidget.java rename to src/main/java/dev/compactmods/machines/client/gui/widget/ScrollableWrappedTextWidget.java index 6a674868..6d464c34 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/gui/widget/ScrollableWrappedTextWidget.java +++ b/src/main/java/dev/compactmods/machines/client/gui/widget/ScrollableWrappedTextWidget.java @@ -1,23 +1,20 @@ -package com.robotgryphon.compactmachines.client.gui.widget; +package dev.compactmods.machines.client.gui.widget; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.AbstractGui; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.resources.I18n; import net.minecraft.util.IReorderingProcessor; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.StringTextComponent; -import net.minecraft.util.text.TextFormatting; -import net.minecraft.util.text.TranslationTextComponent; import java.util.List; public class ScrollableWrappedTextWidget extends AbstractCMGuiWidget { - private String localeKey; + private final String localeKey; private double yScroll = 0; - private FontRenderer fontRenderer; + private final FontRenderer fontRenderer; private int maxLinesToShow; private int lineIndexStart; diff --git a/src/main/java/com/robotgryphon/compactmachines/client/machine/MachinePlayerEventHandler.java b/src/main/java/dev/compactmods/machines/client/machine/MachinePlayerEventHandler.java similarity index 64% rename from src/main/java/com/robotgryphon/compactmachines/client/machine/MachinePlayerEventHandler.java rename to src/main/java/dev/compactmods/machines/client/machine/MachinePlayerEventHandler.java index 912302ff..898d8f3a 100644 --- a/src/main/java/com/robotgryphon/compactmachines/client/machine/MachinePlayerEventHandler.java +++ b/src/main/java/dev/compactmods/machines/client/machine/MachinePlayerEventHandler.java @@ -1,8 +1,8 @@ -package com.robotgryphon.compactmachines.client.machine; +package dev.compactmods.machines.client.machine; -import com.robotgryphon.compactmachines.block.tiles.CompactMachineTile; -import com.robotgryphon.compactmachines.network.MachinePlayersChangedPacket; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; +import dev.compactmods.machines.block.tiles.CompactMachineTile; +import dev.compactmods.machines.network.MachinePlayersChangedPacket; +import dev.compactmods.machines.teleportation.DimensionalPosition; import net.minecraft.client.Minecraft; import net.minecraft.client.world.ClientWorld; @@ -14,10 +14,17 @@ public static void handlePlayerMachineChanged(UUID playerID, MachinePlayersChangedPacket.EnumPlayerChangeType changeType, DimensionalPosition pos) { ClientWorld w = Minecraft.getInstance().level; + if(w == null) + return; + // Early exit if machine in another dimension if (w.dimension() != pos.getDimension()) return; + // Early exit if machine isn't in range of the player - the block sync will handle those + if(!w.isLoaded(pos.getBlockPosition())) + return; + CompactMachineTile tile = (CompactMachineTile) w.getBlockEntity(pos.getBlockPosition()); if (tile == null) return; diff --git a/src/main/java/dev/compactmods/machines/command/CMCommandRoot.java b/src/main/java/dev/compactmods/machines/command/CMCommandRoot.java new file mode 100644 index 00000000..4dac5d96 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/command/CMCommandRoot.java @@ -0,0 +1,16 @@ +package dev.compactmods.machines.command; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import dev.compactmods.machines.CompactMachines; +import net.minecraft.command.CommandSource; + +public class CMCommandRoot { + + public static void register(CommandDispatcher dispatcher) { + final LiteralArgumentBuilder root = LiteralArgumentBuilder.literal(CompactMachines.MOD_ID); + root.then(CMEjectSubcommand.register()); + root.then(CMFixBiomeSubcommand.register()); + dispatcher.register(root); + } +} diff --git a/src/main/java/dev/compactmods/machines/command/CMEjectSubcommand.java b/src/main/java/dev/compactmods/machines/command/CMEjectSubcommand.java new file mode 100644 index 00000000..badf36aa --- /dev/null +++ b/src/main/java/dev/compactmods/machines/command/CMEjectSubcommand.java @@ -0,0 +1,42 @@ +package dev.compactmods.machines.command; + +import java.util.Collection; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.compactmods.machines.rooms.capability.CapabilityRoomHistory; +import dev.compactmods.machines.rooms.capability.IRoomHistory; +import dev.compactmods.machines.util.PlayerUtil; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.EntityArgument; +import net.minecraft.entity.player.ServerPlayerEntity; + +public class CMEjectSubcommand { + public static ArgumentBuilder register() { + return Commands.literal("eject") + .requires(cs -> cs.hasPermission(2)) + .executes(CMEjectSubcommand::execExecutingPlayer) + .then(Commands.argument("player", EntityArgument.player()) + .executes(CMEjectSubcommand::execSpecificPlayer)); + } + + private static int execSpecificPlayer(CommandContext ctx) throws CommandSyntaxException { + Collection ent = EntityArgument.getPlayers(ctx, "player"); + ent.forEach(player -> { + player.getCapability(CapabilityRoomHistory.HISTORY_CAPABILITY).ifPresent(IRoomHistory::clear); + PlayerUtil.teleportPlayerToRespawnOrOverworld(ctx.getSource().getServer(), player); + }); + + return 0; + } + + private static int execExecutingPlayer(CommandContext ctx) throws CommandSyntaxException { + final ServerPlayerEntity player = ctx.getSource().getPlayerOrException(); + + player.getCapability(CapabilityRoomHistory.HISTORY_CAPABILITY).ifPresent(IRoomHistory::clear); + PlayerUtil.teleportPlayerToRespawnOrOverworld(ctx.getSource().getServer(), player); + + return 0; + } +} diff --git a/src/main/java/dev/compactmods/machines/command/CMFixBiomeSubcommand.java b/src/main/java/dev/compactmods/machines/command/CMFixBiomeSubcommand.java new file mode 100644 index 00000000..38000592 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/command/CMFixBiomeSubcommand.java @@ -0,0 +1,92 @@ +package dev.compactmods.machines.command; + +import java.util.Arrays; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.core.Messages; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.util.TranslationUtil; +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.command.arguments.ResourceLocationArgument; +import net.minecraft.command.arguments.SuggestionProviders; +import net.minecraft.network.play.server.SChunkDataPacket; +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.registry.Registry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.biome.Biomes; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.fml.network.PacketDistributor; + +public class CMFixBiomeSubcommand { + public static ArgumentBuilder register() { + return Commands.literal("fixbiome") + .executes(CMFixBiomeSubcommand::fixBiomeDefault) + .then( + Commands.argument("biome", ResourceLocationArgument.id()) + .suggests(SuggestionProviders.AVAILABLE_BIOMES) + .executes(CMFixBiomeSubcommand::specificBiome) + ); + } + + + private static int specificBiome(CommandContext ctx) { + if(!ctx.getSource().getLevel().dimension().equals(Registration.COMPACT_DIMENSION)) { + ctx.getSource().sendFailure(TranslationUtil.message(Messages.FIXBIOME_IN_BAD_DIMENSION)); + return -1; + } + + final ResourceLocation biomeId = ResourceLocationArgument.getId(ctx, "biome"); + updateBiomeData(ctx, biomeId); + return 0; + } + + + private static int fixBiomeDefault(CommandContext ctx) { + if(!ctx.getSource().getLevel().dimension().equals(Registration.COMPACT_DIMENSION)) { + ctx.getSource().sendFailure(TranslationUtil.message(Messages.FIXBIOME_IN_BAD_DIMENSION)); + return -1; + } + + final ResourceLocation biomeId = Biomes.PLAINS.location(); + updateBiomeData(ctx, biomeId); + return 0; + } + + private static void updateBiomeData(CommandContext ctx, ResourceLocation biomeId) { + final MinecraftServer server = ctx.getSource().getServer(); + final ServerWorld level = server.getLevel(Registration.COMPACT_DIMENSION); + if (level == null) { + CompactMachines.LOGGER.error("Error: Compact dimension not registered."); + return; + } + + final Vector3d position = ctx.getSource().getPosition(); + final BlockPos excAt = new BlockPos(position.x, position.y, position.z); + final Chunk chunkAt = level.getChunkAt(excAt); + + final BiomeContainer biomes = chunkAt.getBiomes(); + if (biomes != null) { + final Biome newBiome = server.registryAccess() + .registryOrThrow(Registry.BIOME_REGISTRY) + .get(RegistryKey.create(Registry.BIOME_REGISTRY, biomeId)); + + Arrays.fill(biomes.biomes, newBiome); + + chunkAt.setUnsaved(true); + + SChunkDataPacket pkt = new SChunkDataPacket(chunkAt, 65535); + + PacketDistributor.TRACKING_CHUNK + .with(() -> level.getChunkAt(excAt)) + .send(pkt); + } + } +} diff --git a/src/main/java/dev/compactmods/machines/compat/jei/CompactMachinesJeiPlugin.java b/src/main/java/dev/compactmods/machines/compat/jei/CompactMachinesJeiPlugin.java new file mode 100644 index 00000000..c3bed33b --- /dev/null +++ b/src/main/java/dev/compactmods/machines/compat/jei/CompactMachinesJeiPlugin.java @@ -0,0 +1,51 @@ +package dev.compactmods.machines.compat.jei; + +import java.util.Arrays; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.core.JeiInfo; +import dev.compactmods.machines.api.core.Messages; +import dev.compactmods.machines.block.BlockCompactMachine; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.util.TranslationUtil; +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.registration.IRecipeRegistration; +import mezz.jei.api.registration.ISubtypeRegistration; +import mezz.jei.api.runtime.IJeiRuntime; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +@JeiPlugin +public class CompactMachinesJeiPlugin implements IModPlugin { + @Override + public ResourceLocation getPluginUid() { + return new ResourceLocation(CompactMachines.MOD_ID, "main"); + } + + @Override + public void registerRecipes(IRecipeRegistration registration) { + Arrays.stream(EnumMachineSize.values()) + .map(BlockCompactMachine::getItemBySize) + .forEach(i -> registration.addIngredientInfo( + new ItemStack(i), + VanillaTypes.ITEM, + TranslationUtil.jeiInfo(JeiInfo.MACHINE))); + + + registration.addIngredientInfo( + new ItemStack(Registration.PERSONAL_SHRINKING_DEVICE.get()), + VanillaTypes.ITEM, + TranslationUtil.jeiInfo(JeiInfo.SHRINKING_DEVICE)); + } + + @Override + public void registerItemSubtypes(ISubtypeRegistration registration) { + registration.useNbtForSubtypes(Registration.ITEM_TUNNEL.get()); + } + + @Override + public void onRuntimeAvailable(IJeiRuntime jeiRuntime) { + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeData.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeData.java similarity index 79% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeData.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeData.java index 61ade6b9..f21b3176 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeData.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeData.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; import mcjty.theoneprobe.api.IProbeHitData; import mcjty.theoneprobe.api.IProbeInfo; diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeDataProvider.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeDataProvider.java similarity index 80% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeDataProvider.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeDataProvider.java index 5a6cd563..203e313d 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/IProbeDataProvider.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/IProbeDataProvider.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/ProbeData.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/ProbeData.java similarity index 78% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/ProbeData.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/ProbeData.java index ea8fbacc..0dc0bcdf 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/ProbeData.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/ProbeData.java @@ -1,13 +1,13 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; import mcjty.theoneprobe.api.IProbeHitData; import mcjty.theoneprobe.api.IProbeInfo; import mcjty.theoneprobe.api.ProbeMode; public class ProbeData implements IProbeData { - private IProbeInfo info; - private ProbeMode mode; - private IProbeHitData hitData; + private final IProbeInfo info; + private final ProbeMode mode; + private final IProbeHitData hitData; public ProbeData(IProbeInfo info, ProbeMode mode, IProbeHitData hitData) { this.info = info; diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeCompat.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeCompat.java similarity index 77% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeCompat.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeCompat.java index debc078a..841c3ed7 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeCompat.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeCompat.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; import net.minecraftforge.fml.InterModComms; diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeMain.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeMain.java similarity index 85% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeMain.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeMain.java index 960eed4c..14b1774d 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeMain.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeMain.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; import mcjty.theoneprobe.api.ITheOneProbe; diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeProvider.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeProvider.java similarity index 89% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeProvider.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeProvider.java index c65f84ef..abe14905 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/TheOneProbeProvider.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/TheOneProbeProvider.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe; +package dev.compactmods.machines.compat.theoneprobe; -import com.robotgryphon.compactmachines.CompactMachines; +import dev.compactmods.machines.CompactMachines; import mcjty.theoneprobe.api.IProbeHitData; import mcjty.theoneprobe.api.IProbeInfo; import mcjty.theoneprobe.api.IProbeInfoProvider; diff --git a/src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/CompactMachineProvider.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/CompactMachineProvider.java new file mode 100644 index 00000000..d713f5af --- /dev/null +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/CompactMachineProvider.java @@ -0,0 +1,86 @@ +package dev.compactmods.machines.compat.theoneprobe.providers; + +import com.mojang.authlib.GameProfile; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.core.Tooltips; +import dev.compactmods.machines.block.tiles.CompactMachineTile; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.compat.theoneprobe.IProbeData; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.tunnels.TunnelHelper; +import dev.compactmods.machines.util.TranslationUtil; +import mcjty.theoneprobe.api.IProbeHitData; +import mcjty.theoneprobe.api.IProbeInfo; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +import java.util.Set; + +public class CompactMachineProvider { + + public static void exec(IProbeData data, World world) { + IProbeInfo info = data.getInfo(); + IProbeHitData hitData = data.getHitData(); + + addProbeInfo(info, world, hitData); + } + + private static void addProbeInfo(IProbeInfo info, World world, IProbeHitData hitData) { + TileEntity te = world.getBlockEntity(hitData.getPos()); + if (te instanceof CompactMachineTile) { + CompactMachineTile machine = (CompactMachineTile) te; + + if(machine.mapped()) { + IFormattableTextComponent id = TranslationUtil + .tooltip(Tooltips.Machines.ID, machine.machineId) + .withStyle(TextFormatting.GREEN); + + info.text(id); + } else { + IFormattableTextComponent newMachine = TranslationUtil + .message(new ResourceLocation(CompactMachines.MOD_ID, "new_machine")) + .withStyle(TextFormatting.GREEN); + + info.text(newMachine); + } + + machine.getOwnerUUID().ifPresent(ownerID -> { + // Owner Name + PlayerEntity owner = world.getPlayerByUUID(ownerID); + if (owner != null) { + GameProfile ownerProfile = owner.getGameProfile(); + IFormattableTextComponent ownerText = TranslationUtil + .tooltip(Tooltips.Machines.OWNER, ownerProfile.getName()) + .withStyle(TextFormatting.GRAY); + + info.text(ownerText); + } + }); + + Set tunnelsForMachineSide = TunnelHelper.getTunnelsForMachineSide(machine.machineId, + (ServerWorld) world, hitData.getSideHit()); + + IProbeInfo vertical = info.vertical(info.defaultLayoutStyle().spacing(0)); + + ServerWorld cm = world.getServer().getLevel(Registration.COMPACT_DIMENSION); + tunnelsForMachineSide.forEach(pos -> { + TunnelWallTile tile = (TunnelWallTile) cm.getBlockEntity(pos); + if (tile == null) + return; + + tile.getTunnelDefinition().ifPresent(tunnelDef -> { + vertical.text( + new StringTextComponent(pos + ": " + tunnelDef.getRegistryName().toString()) + ); + }); + }); + } + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/TunnelProvider.java b/src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/TunnelProvider.java similarity index 84% rename from src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/TunnelProvider.java rename to src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/TunnelProvider.java index ee4034a5..c00eab10 100644 --- a/src/main/java/com/robotgryphon/compactmachines/compat/theoneprobe/providers/TunnelProvider.java +++ b/src/main/java/dev/compactmods/machines/compat/theoneprobe/providers/TunnelProvider.java @@ -1,14 +1,15 @@ -package com.robotgryphon.compactmachines.compat.theoneprobe.providers; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.compat.theoneprobe.IProbeData; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import com.robotgryphon.compactmachines.api.tunnels.EnumTunnelSide; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; +package dev.compactmods.machines.compat.theoneprobe.providers; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.compat.theoneprobe.IProbeData; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.tunnels.TunnelHelper; import mcjty.theoneprobe.api.*; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -49,7 +50,7 @@ private static void addProbeInfo(ProbeMode probeMode, IProbeInfo info, PlayerEnt if (tile == null) return; - Optional outside = TunnelHelper.getTunnelConnectedPosition(tile, EnumTunnelSide.OUTSIDE); + Optional outside = TunnelHelper.getTunnelConnectedPosition(tile, EnumTunnelSide.OUTSIDE); Optional connected = TunnelHelper.getConnectedState(tile, EnumTunnelSide.OUTSIDE); if (probeMode == ProbeMode.EXTENDED) { @@ -92,7 +93,7 @@ private static void addProbeInfo(ProbeMode probeMode, IProbeInfo info, PlayerEnt if (!outside.isPresent()) return; - DimensionalPosition outPos = outside.get(); + IDimensionalPosition outPos = outside.get(); ServerWorld connectedWorld = (ServerWorld) world; BlockPos outPosBlock = outPos.getBlockPosition(); diff --git a/src/main/java/com/robotgryphon/compactmachines/config/CommonConfig.java b/src/main/java/dev/compactmods/machines/config/CommonConfig.java similarity index 76% rename from src/main/java/com/robotgryphon/compactmachines/config/CommonConfig.java rename to src/main/java/dev/compactmods/machines/config/CommonConfig.java index fe18e28f..eb05ef6b 100644 --- a/src/main/java/com/robotgryphon/compactmachines/config/CommonConfig.java +++ b/src/main/java/dev/compactmods/machines/config/CommonConfig.java @@ -1,17 +1,11 @@ -package com.robotgryphon.compactmachines.config; +package dev.compactmods.machines.config; -import com.electronwill.nightconfig.core.EnumGetMethod; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.core.EnumMachinePlayersBreakHandling; +import dev.compactmods.machines.CompactMachines; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - @Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class CommonConfig { diff --git a/src/main/java/com/robotgryphon/compactmachines/config/EnableVanillaRecipesConfigCondition.java b/src/main/java/dev/compactmods/machines/config/EnableVanillaRecipesConfigCondition.java similarity index 91% rename from src/main/java/com/robotgryphon/compactmachines/config/EnableVanillaRecipesConfigCondition.java rename to src/main/java/dev/compactmods/machines/config/EnableVanillaRecipesConfigCondition.java index b5d3da8a..cfdf509d 100644 --- a/src/main/java/com/robotgryphon/compactmachines/config/EnableVanillaRecipesConfigCondition.java +++ b/src/main/java/dev/compactmods/machines/config/EnableVanillaRecipesConfigCondition.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.config; +package dev.compactmods.machines.config; import com.google.gson.JsonObject; -import com.robotgryphon.compactmachines.CompactMachines; +import dev.compactmods.machines.CompactMachines; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.crafting.conditions.ICondition; import net.minecraftforge.common.crafting.conditions.IConditionSerializer; diff --git a/src/main/java/com/robotgryphon/compactmachines/config/ServerConfig.java b/src/main/java/dev/compactmods/machines/config/ServerConfig.java similarity index 80% rename from src/main/java/com/robotgryphon/compactmachines/config/ServerConfig.java rename to src/main/java/dev/compactmods/machines/config/ServerConfig.java index c077eb97..75159948 100644 --- a/src/main/java/com/robotgryphon/compactmachines/config/ServerConfig.java +++ b/src/main/java/dev/compactmods/machines/config/ServerConfig.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.config; +package dev.compactmods.machines.config; import com.electronwill.nightconfig.core.EnumGetMethod; -import com.robotgryphon.compactmachines.core.EnumMachinePlayersBreakHandling; +import dev.compactmods.machines.core.EnumMachinePlayersBreakHandling; import net.minecraftforge.common.ForgeConfigSpec; import java.util.Arrays; @@ -12,7 +12,6 @@ public class ServerConfig { public static ForgeConfigSpec CONFIG; public static ForgeConfigSpec.EnumValue MACHINE_PLAYER_BREAK_HANDLING; - public static ForgeConfigSpec.BooleanValue MACHINE_CHUNKLOADING; public static ForgeConfigSpec.IntValue MACHINE_FLOOR_Y; @@ -41,10 +40,6 @@ private static void generateConfig() { EnumMachinePlayersBreakHandling.UNBREAKABLE, EnumGetMethod.NAME_IGNORECASE); - MACHINE_CHUNKLOADING = builder - .comment("Allow machines to chunkload their insides when the machines are loaded.") - .define("chunkloading", true); - MACHINE_FLOOR_Y = builder .comment("The Y-level to spawn machine floors at.") .defineInRange("floor", 40, 10, 200); diff --git a/src/main/java/com/robotgryphon/compactmachines/core/EnumMachinePlayersBreakHandling.java b/src/main/java/dev/compactmods/machines/core/EnumMachinePlayersBreakHandling.java similarity index 93% rename from src/main/java/com/robotgryphon/compactmachines/core/EnumMachinePlayersBreakHandling.java rename to src/main/java/dev/compactmods/machines/core/EnumMachinePlayersBreakHandling.java index d1b89ad1..5fa7bec6 100644 --- a/src/main/java/com/robotgryphon/compactmachines/core/EnumMachinePlayersBreakHandling.java +++ b/src/main/java/dev/compactmods/machines/core/EnumMachinePlayersBreakHandling.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.core; +package dev.compactmods.machines.core; public enum EnumMachinePlayersBreakHandling { UNBREAKABLE("unbreakable", "Nobody can break while players are inside."), diff --git a/src/main/java/dev/compactmods/machines/core/ModBusEvents.java b/src/main/java/dev/compactmods/machines/core/ModBusEvents.java new file mode 100644 index 00000000..4cd69cf0 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/core/ModBusEvents.java @@ -0,0 +1,35 @@ +package dev.compactmods.machines.core; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.advancement.AdvancementTriggers; +import dev.compactmods.machines.compat.theoneprobe.TheOneProbeCompat; +import dev.compactmods.machines.network.NetworkHandler; +import dev.compactmods.machines.rooms.capability.CapabilityRoomHistory; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; + +@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +public class ModBusEvents { + + @SubscribeEvent + public static void setup(final FMLCommonSetupEvent event) { + CompactMachines.LOGGER.trace("Initializing network handler."); + NetworkHandler.initialize(); + + CompactMachines.LOGGER.trace("Registering advancement triggers."); + AdvancementTriggers.init(); + + CompactMachines.LOGGER.trace("Registering capabilities."); + CapabilityRoomHistory.register(); + } + + @SubscribeEvent + public static void enqueueIMC(final InterModEnqueueEvent event) { + CompactMachines.LOGGER.trace("Sending IMC setup to TOP and other mods."); + if (ModList.get().isLoaded("theoneprobe")) + TheOneProbeCompat.sendIMC(); + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/core/Registration.java b/src/main/java/dev/compactmods/machines/core/Registration.java similarity index 87% rename from src/main/java/com/robotgryphon/compactmachines/core/Registration.java rename to src/main/java/dev/compactmods/machines/core/Registration.java index bd7ce05d..6bb33947 100644 --- a/src/main/java/com/robotgryphon/compactmachines/core/Registration.java +++ b/src/main/java/dev/compactmods/machines/core/Registration.java @@ -1,21 +1,20 @@ -package com.robotgryphon.compactmachines.core; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.block.BlockCompactMachine; -import com.robotgryphon.compactmachines.block.tiles.CompactMachineTile; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.block.walls.BreakableWallBlock; -import com.robotgryphon.compactmachines.block.walls.SolidWallBlock; -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.item.ItemBlockMachine; -import com.robotgryphon.compactmachines.item.ItemBlockWall; -import com.robotgryphon.compactmachines.item.ItemPersonalShrinkingDevice; -import com.robotgryphon.compactmachines.item.TunnelItem; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; -import com.robotgryphon.compactmachines.tunnels.definitions.ItemTunnelDefinition; -import com.robotgryphon.compactmachines.tunnels.definitions.RedstoneInTunnelDefinition; -import com.robotgryphon.compactmachines.tunnels.definitions.RedstoneOutTunnelDefinition; +package dev.compactmods.machines.core; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.BlockCompactMachine; +import dev.compactmods.machines.block.tiles.CompactMachineTile; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.block.walls.BreakableWallBlock; +import dev.compactmods.machines.block.walls.SolidWallBlock; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.item.ItemBlockMachine; +import dev.compactmods.machines.item.ItemBlockWall; +import dev.compactmods.machines.item.ItemPersonalShrinkingDevice; +import dev.compactmods.machines.item.TunnelItem; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.tunnels.definitions.ItemTunnelDefinition; +import dev.compactmods.machines.tunnels.definitions.RedstoneInTunnelDefinition; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.SoundType; @@ -38,7 +37,7 @@ import java.util.function.Supplier; -import static com.robotgryphon.compactmachines.CompactMachines.MOD_ID; +import static dev.compactmods.machines.CompactMachines.MOD_ID; @Mod.EventBusSubscriber(modid = MOD_ID) public class Registration { @@ -60,14 +59,14 @@ public class Registration { // ================================================================================================================ // PROPERTIES // ================================================================================================================ - private static AbstractBlock.Properties MACHINE_BLOCK_PROPS = AbstractBlock.Properties + private static final AbstractBlock.Properties MACHINE_BLOCK_PROPS = AbstractBlock.Properties .of(Material.METAL) .strength(8.0F, 20.0F) .harvestLevel(1) .harvestTool(ToolType.PICKAXE) .requiresCorrectToolForDrops(); - private static Supplier BASIC_ITEM_PROPS = () -> new Item.Properties() + private static final Supplier BASIC_ITEM_PROPS = () -> new Item.Properties() .tab(CompactMachines.COMPACT_MACHINES_ITEMS); // ================================================================================================================ diff --git a/src/main/java/dev/compactmods/machines/core/ServerEventHandler.java b/src/main/java/dev/compactmods/machines/core/ServerEventHandler.java new file mode 100644 index 00000000..48cfbcc7 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/core/ServerEventHandler.java @@ -0,0 +1,27 @@ +package dev.compactmods.machines.core; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.command.CMCommandRoot; +import dev.compactmods.machines.rooms.chunkloading.CMRoomChunkloadingManager; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; + +@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID) +public class ServerEventHandler { + + @SubscribeEvent + public static void onServerStarting(final FMLServerStartingEvent evt) { + MinecraftServer server = evt.getServer(); + + CompactMachines.CHUNKLOAD_MANAGER = new CMRoomChunkloadingManager(server); + // SavedMachineDataMigrator.migrate(server); + } + + @SubscribeEvent + public static void onCommandsRegister(final RegisterCommandsEvent event) { + CMCommandRoot.register(event.getDispatcher()); + } +} diff --git a/src/main/java/dev/compactmods/machines/data/codec/CodecExtensions.java b/src/main/java/dev/compactmods/machines/data/codec/CodecExtensions.java new file mode 100644 index 00000000..ecf7d0ad --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/codec/CodecExtensions.java @@ -0,0 +1,37 @@ +package dev.compactmods.machines.data.codec; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Util; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; + +import java.util.UUID; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; + +public abstract class CodecExtensions { + public static final Codec UUID_CODEC = Codec.STRING + .comapFlatMap((s) -> { + try { + return DataResult.success(UUID.fromString(s)); + } catch (Exception ex) { + return DataResult.error("Not a valid UUID: " + s + " (" + ex.getMessage() + ")"); + } + }, UUID::toString).stable(); + + public static final Codec> WORLD_REGISTRY_KEY = ResourceLocation.CODEC + .xmap(RegistryKey.elementKey(Registry.DIMENSION_REGISTRY), RegistryKey::location); + + public static final Codec VECTOR3D = DoubleStreamExtensions.CODEC + .comapFlatMap(i -> DoubleStreamExtensions.fixedDoubleSize(i, 3) + .map(out -> new Vector3d(out[0], out[1], out[2])), vec -> DoubleStream.of(vec.x, vec.y, vec.z)); + + public static final Codec CHUNKPOS = Codec.INT_STREAM + .comapFlatMap(i -> Util.fixedSize(i, 2) + .map(arr -> new ChunkPos(arr[0], arr[1])), pos -> IntStream.of(pos.x, pos.z)); +} diff --git a/src/main/java/dev/compactmods/machines/data/codec/DoubleStreamExtensions.java b/src/main/java/dev/compactmods/machines/data/codec/DoubleStreamExtensions.java new file mode 100644 index 00000000..0486762b --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/codec/DoubleStreamExtensions.java @@ -0,0 +1,50 @@ +package dev.compactmods.machines.data.codec; + +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.codecs.PrimitiveCodec; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.DoubleStream; + +public class DoubleStreamExtensions { + + public static final PrimitiveCodec CODEC = new PrimitiveCodec() { + @Override + public DataResult read(final DynamicOps ops, final T input) { + return getDoubleStream(ops, input); + } + + @Override + public T write(final DynamicOps ops, final DoubleStream value) { + return ops.createList(value.mapToObj(ops::createDouble)); + } + + @Override + public String toString() { + return "DoubleStream"; + } + }; + + public static DataResult fixedDoubleSize(DoubleStream stream, int limit) { + double[] limited = stream.limit(limit + 1).toArray(); + if (limited.length != limit) { + String s = "Input is not a list of " + limit + " doubles"; + return limited.length >= limit ? DataResult.error(s, Arrays.copyOf(limited, limit)) : DataResult.error(s); + } else { + return DataResult.success(limited); + } + } + + public static DataResult getDoubleStream(final DynamicOps ops, final T input) { + return ops.getStream(input).flatMap(stream -> { + final List list = stream.collect(Collectors.toList()); + if (list.stream().allMatch(element -> ops.getNumberValue(element).result().isPresent())) { + return DataResult.success(list.stream().mapToDouble(element -> ops.getNumberValue(element).result().get().doubleValue())); + } + return DataResult.error("Some elements are not doubles: " + input); + }); + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/data/NbtListCollector.java b/src/main/java/dev/compactmods/machines/data/codec/NbtListCollector.java similarity index 93% rename from src/main/java/com/robotgryphon/compactmachines/data/NbtListCollector.java rename to src/main/java/dev/compactmods/machines/data/codec/NbtListCollector.java index c34181f2..d8ee8084 100644 --- a/src/main/java/com/robotgryphon/compactmachines/data/NbtListCollector.java +++ b/src/main/java/dev/compactmods/machines/data/codec/NbtListCollector.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.data; +package dev.compactmods.machines.data.codec; import com.google.common.collect.ImmutableSet; import net.minecraft.nbt.INBT; @@ -13,8 +13,6 @@ import java.util.function.Supplier; import java.util.stream.Collector; -import java.util.stream.Collector.Characteristics; - public class NbtListCollector implements Collector, ListNBT> { @Override diff --git a/src/main/java/dev/compactmods/machines/data/graph/CompactMachineConnectionGraph.java b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineConnectionGraph.java new file mode 100644 index 00000000..a3fabe47 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineConnectionGraph.java @@ -0,0 +1,156 @@ +package dev.compactmods.machines.data.graph; + +import com.google.common.collect.ImmutableList; +import com.google.common.graph.*; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.data.codec.CodecExtensions; +import net.minecraft.util.math.ChunkPos; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Stores information on how external machines connect to the rooms in the compact machine + * dimension. + */ +public class CompactMachineConnectionGraph { + + private final MutableValueGraph graph; + private final Map machines; + private final Map rooms; + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + CompactMachineConnectionInfo.CODEC.listOf() + .fieldOf("connections") + .forGetter(CompactMachineConnectionGraph::buildConnections) + ).apply(i, CompactMachineConnectionGraph::new)); + + + + public CompactMachineConnectionGraph() { + graph = ValueGraphBuilder + .directed() + .nodeOrder(ElementOrder.sorted(Comparator.comparing(IMachineGraphNode::getId))) + .build(); + + machines = new HashMap<>(); + rooms = new HashMap<>(); + } + + private CompactMachineConnectionGraph(List connections) { + this(); + + for(CompactMachineConnectionInfo i : connections) { + addRoom(i.roomChunk); + for(int connectedMachine : i.machines()) { + addMachine(connectedMachine); + connectMachineToRoom(connectedMachine, i.roomChunk); + } + } + } + + private List buildConnections() { + List result = new ArrayList<>(); + this.rooms.forEach((chunk, node) -> { + Collection machines = this.getMachinesFor(chunk); + CompactMachineConnectionInfo roomInfo = new CompactMachineConnectionInfo(chunk, machines); + result.add(roomInfo); + }); + + return result; + } + + public void addMachine(int machine) { + if(this.machines.containsKey(machine)) + return; + + CompactMachineNode node = new CompactMachineNode(machine); + graph.addNode(node); + machines.put(machine, node); + } + + public void addRoom(ChunkPos roomChunk) { + if(this.rooms.containsKey(roomChunk)) + return; + + CompactMachineRoomNode node = new CompactMachineRoomNode(roomChunk); + graph.addNode(node); + rooms.put(roomChunk, node); + } + + public void connectMachineToRoom(int machine, ChunkPos room) { + if(!machines.containsKey(machine)) + return; + + if(!rooms.containsKey(room)) + return; + + CompactMachineNode machineNode = machines.get(machine); + CompactMachineRoomNode roomNode = rooms.get(room); + + graph.putEdgeValue(machineNode, roomNode, DefaultEdges.MACHINE_LINK); + } + + public Collection getMachinesFor(ChunkPos machineChunk) { + CompactMachineRoomNode node = this.rooms.get(machineChunk); + if(node == null) + return Collections.emptySet(); + + Set inbound = graph.predecessors(node); + return inbound.stream() + .filter(ibn -> ibn instanceof CompactMachineNode) + .map(ibn -> (CompactMachineNode) ibn) + .map(CompactMachineNode::getMachineId) + .collect(Collectors.toSet()); + } + + public Optional getConnectedRoom(int machine) { + if(!this.machines.containsKey(machine)) + return Optional.empty(); + + CompactMachineNode node = this.machines.get(machine); + Set connected = this.graph.successors(node); + return connected.stream() + .filter(n -> n instanceof CompactMachineRoomNode) + .map(n -> (CompactMachineRoomNode) n) + .map(CompactMachineRoomNode::getChunk) + .findFirst(); + } + + public Stream getMachines() { + return this.machines.values().stream(); + } + + /** + * Data structure for serialization. Do not use directly. + */ + private static class CompactMachineConnectionInfo { + private final ChunkPos roomChunk; + private final List connectedMachines; + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + CodecExtensions.CHUNKPOS + .fieldOf("machine") + .forGetter(CompactMachineConnectionInfo::room), + + Codec.INT.listOf() + .fieldOf("connections") + .forGetter(CompactMachineConnectionInfo::machines) + ).apply(i, CompactMachineConnectionInfo::new)); + + public CompactMachineConnectionInfo(ChunkPos roomChunk, Collection connections) { + this.roomChunk = roomChunk; + this.connectedMachines = ImmutableList.copyOf(connections); + } + + public ChunkPos room() { + return this.roomChunk; + } + + public List machines() { + return this.connectedMachines; + } + } +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/CompactMachineNode.java b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineNode.java new file mode 100644 index 00000000..8215aa64 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineNode.java @@ -0,0 +1,39 @@ +package dev.compactmods.machines.data.graph; + +import java.util.Objects; + +/** + * Represents a machine's external point. This can be either inside a machine or in a dimension somewhere. + */ +public class CompactMachineNode implements IMachineGraphNode { + private final int machineId; + + public CompactMachineNode(int machine) { + this.machineId = machine; + } + + @Override + public String label() { + return "Compact Machine #" + machineId; + } + + @Override + public String getId() { + return "machine" + machineId; + } + + public int getMachineId() { return machineId; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CompactMachineNode that = (CompactMachineNode) o; + return machineId == that.machineId; + } + + @Override + public int hashCode() { + return Objects.hash(machineId); + } +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/CompactMachineRoomNode.java b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineRoomNode.java new file mode 100644 index 00000000..07a34c32 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/CompactMachineRoomNode.java @@ -0,0 +1,49 @@ +package dev.compactmods.machines.data.graph; + +import net.minecraft.util.math.ChunkPos; + +import java.util.Objects; + +/** + * Represents the inside of a Compact Machine. + */ +public class CompactMachineRoomNode implements IMachineGraphNode { + + private final ChunkPos pos; + + public CompactMachineRoomNode(ChunkPos pos) { + this.pos = pos; + } + + @Override + public String getId() { + return getIdFor(this.pos); + } + + @Override + public String label() { + return String.format("Compact Machine {%s,%s}", pos.x, pos.z); + } + + public static String getIdFor(ChunkPos pos) { + long v = pos.toLong(); + return "internal_" + (v < 0 ? "N" : "") + Math.abs(v); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CompactMachineRoomNode that = (CompactMachineRoomNode) o; + return pos.equals(that.pos); + } + + @Override + public int hashCode() { + return Objects.hash(pos); + } + + public ChunkPos getChunk() { + return pos; + } +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/DefaultEdges.java b/src/main/java/dev/compactmods/machines/data/graph/DefaultEdges.java new file mode 100644 index 00000000..9821d0ab --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/DefaultEdges.java @@ -0,0 +1,6 @@ +package dev.compactmods.machines.data.graph; + +public class DefaultEdges { + + public static final IGraphEdge MACHINE_LINK = new MachineLinkEdge(); +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/IGraphEdge.java b/src/main/java/dev/compactmods/machines/data/graph/IGraphEdge.java new file mode 100644 index 00000000..60ebd373 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/IGraphEdge.java @@ -0,0 +1,4 @@ +package dev.compactmods.machines.data.graph; + +public interface IGraphEdge { +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/IMachineGraphNode.java b/src/main/java/dev/compactmods/machines/data/graph/IMachineGraphNode.java new file mode 100644 index 00000000..20b4d749 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/IMachineGraphNode.java @@ -0,0 +1,6 @@ +package dev.compactmods.machines.data.graph; + +public interface IMachineGraphNode { + String label(); + String getId(); +} diff --git a/src/main/java/dev/compactmods/machines/data/graph/MachineLinkEdge.java b/src/main/java/dev/compactmods/machines/data/graph/MachineLinkEdge.java new file mode 100644 index 00000000..dfba881f --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/graph/MachineLinkEdge.java @@ -0,0 +1,4 @@ +package dev.compactmods.machines.data.graph; + +public class MachineLinkEdge implements IGraphEdge { +} diff --git a/src/main/java/dev/compactmods/machines/data/persistent/CompactMachineData.java b/src/main/java/dev/compactmods/machines/data/persistent/CompactMachineData.java new file mode 100644 index 00000000..97e9f994 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/persistent/CompactMachineData.java @@ -0,0 +1,142 @@ +package dev.compactmods.machines.data.persistent; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.codec.NbtListCollector; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.DimensionSavedDataManager; +import net.minecraft.world.storage.WorldSavedData; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; + +/** + * Holds information on the external points of a machine, ie the actual machine blocks. + */ +public class CompactMachineData extends WorldSavedData { + + /** + * File storage name. + */ + public final static String DATA_NAME = CompactMachines.MOD_ID + "_machines"; + + /** + * Specifies locations of machines in-world, outside of the compact world. + * This is used for things like spawn lookups, tunnel handling, and forced ejections. + */ + public Map data; + + public CompactMachineData() { + super(DATA_NAME); + data = new HashMap<>(); + } + + @Nullable + public static CompactMachineData get(MinecraftServer server) { + ServerWorld compactWorld = server.getLevel(Registration.COMPACT_DIMENSION); + if (compactWorld == null) { + CompactMachines.LOGGER.error("No compact dimension found. Report this."); + return null; + } + + DimensionSavedDataManager sd = compactWorld.getDataStorage(); + return sd.computeIfAbsent(CompactMachineData::new, DATA_NAME); + } + + @Override + public void load(CompoundNBT nbt) { + if(nbt.contains("locations")) { + ListNBT nbtLocations = nbt.getList("locations", Constants.NBT.TAG_COMPOUND); + nbtLocations.forEach(nbtLoc -> { + DataResult res = MachineData.CODEC.parse(NBTDynamicOps.INSTANCE, nbtLoc); + res.resultOrPartial(err -> { + CompactMachines.LOGGER.error("Error while processing machine data: " + err); + }).ifPresent(machineInfo -> this.data.put(machineInfo.machineId, machineInfo)); + }); + } + } + + @Override + @Nonnull + public CompoundNBT save(@Nonnull CompoundNBT nbt) { + if(!data.isEmpty()) { + ListNBT nbtLocations = data.values() + .stream() + .map(entry -> { + DataResult nbtRes = MachineData.CODEC.encodeStart(NBTDynamicOps.INSTANCE, entry); + return nbtRes + .resultOrPartial(err -> CompactMachines.LOGGER.error("Error serializing machine data: " + err)); + + }) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(NbtListCollector.toNbtList()); + + nbt.put("locations", nbtLocations); + } + + return nbt; + } + + public boolean isPlaced(Integer machineId) { + return data.containsKey(machineId); + } + + public void setMachineLocation(int machineId, DimensionalPosition position) { + // TODO - Packet/Event for machine changing external location (tunnels) + if(data.containsKey(machineId)) { + data.get(machineId).setLocation(position); + } else { + data.put(machineId, new MachineData(machineId, position)); + } + + this.setDirty(); + } + + public Optional getMachineLocation(int machineId) { + if(!data.containsKey(machineId)) + return Optional.empty(); + + MachineData machineData = this.data.get(machineId); + return Optional.ofNullable(machineData.location); + } + + public static class MachineData { + private final int machineId; + public DimensionalPosition location; + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + Codec.INT.fieldOf("machine").forGetter(MachineData::getMachineId), + DimensionalPosition.CODEC.fieldOf("location").forGetter(MachineData::getLocation) + ).apply(i, MachineData::new)); + + public MachineData(int machineId, DimensionalPosition location) { + this.machineId = machineId; + this.location = location; + } + + public int getMachineId() { + return this.machineId; + } + + public DimensionalPosition getLocation() { + return this.location; + } + + public MachineData setLocation(DimensionalPosition position) { + this.location = position; + return this; + } + } +} diff --git a/src/main/java/dev/compactmods/machines/data/persistent/CompactRoomData.java b/src/main/java/dev/compactmods/machines/data/persistent/CompactRoomData.java new file mode 100644 index 00000000..12cb1580 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/persistent/CompactRoomData.java @@ -0,0 +1,257 @@ +package dev.compactmods.machines.data.persistent; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.codec.CodecExtensions; +import dev.compactmods.machines.data.codec.NbtListCollector; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.util.MathUtil; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.DimensionSavedDataManager; +import net.minecraft.world.storage.WorldSavedData; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.naming.OperationNotSupportedException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class CompactRoomData extends WorldSavedData { + public static final String DATA_NAME = CompactMachines.MOD_ID + "_rooms"; + + private final Map machineData; + + public CompactRoomData() { + super(DATA_NAME); + machineData = new HashMap<>(); + } + + @Nullable + public static CompactRoomData get(MinecraftServer server) { + ServerWorld compactWorld = server.getLevel(Registration.COMPACT_DIMENSION); + if (compactWorld == null) { + CompactMachines.LOGGER.error("No compact dimension found. Report this."); + return null; + } + + DimensionSavedDataManager sd = compactWorld.getDataStorage(); + return sd.computeIfAbsent(CompactRoomData::new, DATA_NAME); + } + + @Override + public void load(CompoundNBT nbt) { + if (nbt.contains("machines")) { + ListNBT machines = nbt.getList("machines", Constants.NBT.TAG_COMPOUND); + machines.forEach(machNbt -> { + DataResult result = + RoomData.CODEC.parse(NBTDynamicOps.INSTANCE, machNbt); + + result + .resultOrPartial((err) -> CompactMachines.LOGGER.error("Error loading machine data from file: {}", err)) + .ifPresent(imd -> { + ChunkPos chunk = new ChunkPos(imd.getCenter()); + this.machineData.put(chunk, imd); + }); + }); + } + } + + @Override + @Nonnull + public CompoundNBT save(@Nonnull CompoundNBT nbt) { + if (!machineData.isEmpty()) { + ListNBT collect = machineData.values() + .stream() + .map(data -> { + DataResult n = RoomData.CODEC.encodeStart(NBTDynamicOps.INSTANCE, data); + return n.result(); + }) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(NbtListCollector.toNbtList()); + + nbt.put("machines", collect); + } + + return nbt; + } + + public boolean isRegistered(ChunkPos chunkPos) { + return machineData.containsKey(chunkPos); + } + + private void register(ChunkPos pos, RoomData data) throws OperationNotSupportedException { + if (isRegistered(pos)) + throw new OperationNotSupportedException("Machine already registered."); + + machineData.put(pos, data); + setDirty(); + } + + @Nullable + public DimensionalPosition getSpawn(ChunkPos roomChunk) { + RoomData roomData = machineData.get(roomChunk); + if (roomData == null) + return null; + + return new DimensionalPosition( + Registration.COMPACT_DIMENSION, + roomData.getSpawn() + ); + } + + public int getNextId() { + return this.machineData.size() + 1; + } + + public void setSpawn(ChunkPos roomChunk, Vector3d position) { + if (!machineData.containsKey(roomChunk)) + return; + + RoomData roomData = machineData.get(roomChunk); + roomData.setSpawn(position); + + setDirty(); + } + + public Optional getInnerBounds(ChunkPos roomChunk) { + if (!machineData.containsKey(roomChunk)) + return Optional.empty(); + + AxisAlignedBB bounds = machineData.get(roomChunk).getMachineBounds(); + return Optional.of(bounds); + } + + public NewRoomRegistration createNew() { + return new NewRoomRegistration(this); + } + + public static class NewRoomRegistration { + + private final CompactRoomData storage; + private Vector3d spawn; + private ChunkPos chunk = new ChunkPos(0, 0); + private EnumMachineSize size = EnumMachineSize.TINY; + private BlockPos center = BlockPos.ZERO; + private UUID owner; + + public NewRoomRegistration(CompactRoomData storage) { + this.storage = storage; + } + + private void recalculateSize() { + BlockPos centerAtFloor = MathUtil.getCenterWithY(chunk, ServerConfig.MACHINE_FLOOR_Y.get()); + BlockPos centerSized = centerAtFloor.above(size.getInternalSize() / 2); + + this.spawn = new Vector3d(centerAtFloor.getX(), centerAtFloor.getY(), centerAtFloor.getZ()); + this.center = centerSized; + } + + public NewRoomRegistration owner(UUID owner) { + this.owner = owner; + return this; + } + + public NewRoomRegistration size(EnumMachineSize size) { + this.size = size; + recalculateSize(); + return this; + } + + public NewRoomRegistration spawn(BlockPos spawn) { + Vector3d spawnTest = new Vector3d(spawn.getX(), spawn.getY(), spawn.getZ()); + + // Make sure the spawn is inside the new room bounds + if(size.getBounds(this.center).contains(spawnTest)) + this.spawn = spawnTest; + + return this; + } + + public NewRoomRegistration chunk(ChunkPos chunk) { + this.chunk = chunk; + recalculateSize(); + return this; + } + + public void register() throws OperationNotSupportedException { + RoomData data = new RoomData(owner, center, spawn, size); + storage.register(chunk, data); + } + } + + private static class RoomData { + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + CodecExtensions.UUID_CODEC.fieldOf("owner").forGetter(RoomData::getOwner), + BlockPos.CODEC.fieldOf("center").forGetter(RoomData::getCenter), + CodecExtensions.VECTOR3D.fieldOf("spawn").forGetter(RoomData::getSpawn), + EnumMachineSize.CODEC.fieldOf("size").forGetter(RoomData::getSize) + ).apply(i, RoomData::new)); + + private final UUID owner; + private final BlockPos center; + private Vector3d spawn; + private final EnumMachineSize size; + + public RoomData(UUID owner, BlockPos center, Vector3d spawn, EnumMachineSize size) { + this.owner = owner; + this.center = center; + this.spawn = spawn; + this.size = size; + } + + private EnumMachineSize getSize() { + return this.size; + } + + public UUID getOwner() { + return this.owner; + } + + public Vector3d getSpawn() { + if (this.spawn != null) + return this.spawn; + + Vector3d newSpawn = new Vector3d( + center.getX(), + center.getY(), + center.getZ() + ); + + double offset = size.getInternalSize() / 2.0d; + + this.spawn = newSpawn.subtract(0, offset, 0); + return this.spawn; + } + + public BlockPos getCenter() { + return this.center; + } + + public void setSpawn(Vector3d newSpawn) { + this.spawn = newSpawn; + } + + public AxisAlignedBB getMachineBounds() { + return size.getBounds(this.center); + } + } +} diff --git a/src/main/java/dev/compactmods/machines/data/persistent/MachineConnections.java b/src/main/java/dev/compactmods/machines/data/persistent/MachineConnections.java new file mode 100644 index 00000000..3a61b120 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/data/persistent/MachineConnections.java @@ -0,0 +1,61 @@ +package dev.compactmods.machines.data.persistent; + +import com.mojang.serialization.DataResult; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.graph.CompactMachineConnectionGraph; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.DimensionSavedDataManager; +import net.minecraft.world.storage.WorldSavedData; + +public class MachineConnections extends WorldSavedData { + public static final String DATA_NAME = CompactMachines.MOD_ID + "_connections"; + + public CompactMachineConnectionGraph graph; + + public MachineConnections() { + super(DATA_NAME); + graph = new CompactMachineConnectionGraph(); + } + + public static MachineConnections get(MinecraftServer server) { + ServerWorld compactWorld = server.getLevel(Registration.COMPACT_DIMENSION); + if (compactWorld == null) { + CompactMachines.LOGGER.error("No compact dimension found. Report this."); + return null; + } + + DimensionSavedDataManager sd = compactWorld.getDataStorage(); + return sd.computeIfAbsent(MachineConnections::new, DATA_NAME); + } + + @Override + public void load(CompoundNBT nbt) { + if (nbt.contains("graph")) { + CompoundNBT graphNbt = nbt.getCompound("graph"); + DataResult graphParseResult = CompactMachineConnectionGraph.CODEC.parse(NBTDynamicOps.INSTANCE, graphNbt); + + graphParseResult + .resultOrPartial(CompactMachines.LOGGER::error) + .ifPresent(g -> this.graph = g); + } + } + + @Override + public CompoundNBT save(CompoundNBT nbt) { + if(graph != null) { + DataResult dataResult = CompactMachineConnectionGraph.CODEC.encodeStart(NBTDynamicOps.INSTANCE, graph); + dataResult + .resultOrPartial(CompactMachines.LOGGER::error) + .ifPresent(gNbt -> { + nbt.put("graph", gNbt); + }); + } + + return nbt; + } +} diff --git a/src/main/java/dev/compactmods/machines/datagen/AdvancementGenerator.java b/src/main/java/dev/compactmods/machines/datagen/AdvancementGenerator.java new file mode 100644 index 00000000..45f2e1ca --- /dev/null +++ b/src/main/java/dev/compactmods/machines/datagen/AdvancementGenerator.java @@ -0,0 +1,188 @@ +package dev.compactmods.machines.datagen; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.advancement.trigger.ClaimedMachineTrigger; +import dev.compactmods.machines.advancement.trigger.HowDidYouGetHereTrigger; +import dev.compactmods.machines.api.core.Advancements; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.util.TranslationUtil; +import net.minecraft.advancements.*; +import net.minecraft.advancements.criterion.ImpossibleTrigger; +import net.minecraft.advancements.criterion.InventoryChangeTrigger; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DirectoryCache; +import net.minecraft.data.IDataProvider; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +public class AdvancementGenerator implements IDataProvider { + + private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create(); + private final DataGenerator generator; + + public AdvancementGenerator(DataGenerator gen) { + this.generator = gen; + } + + @Override + public void run(DirectoryCache cache) { + Path path = this.generator.getOutputFolder(); + Set set = Sets.newHashSet(); + Consumer consumer = (adv) -> { + if (!set.add(adv.getId())) { + throw new IllegalStateException("Duplicate advancement " + adv.getId()); + } else { + Path path1 = path.resolve("data/" + adv.getId().getNamespace() + "/advancements/" + adv.getId().getPath() + ".json"); + + try { + IDataProvider.save(GSON, cache, adv.deconstruct().serializeToJson(), path1); + } catch (IOException ioexception) { + CompactMachines.LOGGER.error("Couldn't save advancement {}", path1, ioexception); + } + + } + }; + + generateAdvancements(consumer); + } + + private ResourceLocation modLoc(String i) { + return new ResourceLocation(CompactMachines.MOD_ID, i); + } + + private void generateAdvancements(Consumer consumer) { + + final Advancement root = Advancement.Builder.advancement() + .addCriterion("root", new ImpossibleTrigger.Instance()) + .display(new DisplayBuilder() + .frame(FrameType.TASK) + .background(modLoc("textures/block/wall.png")) + .item(new ItemStack(Registration.MACHINE_BLOCK_ITEM_NORMAL.get())) + .id(Advancements.ROOT) + .toast(false).hidden(false).chat(false) + .build()) + .save(consumer, modLoc("root").toString()); + + Advancement.Builder.advancement() + .parent(root) + .addCriterion("got_stuck", HowDidYouGetHereTrigger.Instance.create()) + .display(new DisplayBuilder() + .frame(FrameType.CHALLENGE) + .item(new ItemStack(Registration.PERSONAL_SHRINKING_DEVICE.get())) + .id(Advancements.HOW_DID_YOU_GET_HERE) + .toast(false).hidden(true) + .build()) + .save(consumer, Advancements.HOW_DID_YOU_GET_HERE.toString()); + + final Advancement wall = Advancement.Builder.advancement() + .parent(root) + .addCriterion("obtained_wall", InventoryChangeTrigger.Instance.hasItems(Registration.BLOCK_BREAKABLE_WALL.get())) + .display(new DisplayBuilder() + .frame(FrameType.TASK) + .item(new ItemStack(Registration.BLOCK_BREAKABLE_WALL.get())) + .id(Advancements.FOUNDATIONS) + .build()) + .save(consumer, Advancements.FOUNDATIONS.toString()); + + final Advancement psd = Advancement.Builder.advancement() + .parent(root) + .addCriterion("obtained_psd", InventoryChangeTrigger.Instance.hasItems(Registration.PERSONAL_SHRINKING_DEVICE.get())) + .display(new DisplayBuilder() + .frame(FrameType.TASK) + .item(new ItemStack(Registration.PERSONAL_SHRINKING_DEVICE.get())) + .id(Advancements.GOT_SHRINKING_DEVICE) + .build()) + .save(consumer, Advancements.GOT_SHRINKING_DEVICE.toString()); + + final Advancement tiny = machineAdvancement(consumer, psd, Advancements.CLAIMED_TINY_MACHINE, Registration.MACHINE_BLOCK_ITEM_TINY); + final Advancement small = machineAdvancement(consumer, psd, Advancements.CLAIMED_SMALL_MACHINE, Registration.MACHINE_BLOCK_ITEM_SMALL); + final Advancement normal = machineAdvancement(consumer, psd, Advancements.CLAIMED_NORMAL_MACHINE, Registration.MACHINE_BLOCK_ITEM_NORMAL); + final Advancement large = machineAdvancement(consumer, psd, Advancements.CLAIMED_LARGE_MACHINE, Registration.MACHINE_BLOCK_ITEM_LARGE); + final Advancement giant = machineAdvancement(consumer, psd, Advancements.CLAIMED_GIANT_MACHINE, Registration.MACHINE_BLOCK_ITEM_GIANT); + final Advancement max = machineAdvancement(consumer, psd, Advancements.CLAIMED_MAX_MACHINE, Registration.MACHINE_BLOCK_ITEM_MAXIMUM); + } + + private Advancement machineAdvancement(Consumer consumer, Advancement root, ResourceLocation advancement, Supplier item) { + return Advancement.Builder.advancement() + .parent(root) + .addCriterion("claimed_machine", ClaimedMachineTrigger.Instance.create(advancement)) + .display(new DisplayBuilder() + .frame(FrameType.TASK) + .item(new ItemStack(item.get())) + .id(advancement) + .build()) + .save(consumer, advancement.toString()); + } + + @Override + public String getName() { + return "CompactMachinesAdvancements"; + } + + private static class DisplayBuilder { + + private ItemStack stack; + private ResourceLocation translationId; + private boolean showToast = true; + private boolean showInChat = true; + private boolean isHidden = false; + private ResourceLocation background = null; + private FrameType frame = FrameType.TASK; + + public DisplayBuilder() { + } + + public DisplayInfo build() { + return new DisplayInfo(stack, + TranslationUtil.advancementTitle(translationId), + TranslationUtil.advancementDesc(translationId), + background, + frame, + showToast, showInChat, isHidden); + } + + public DisplayBuilder item(ItemStack item) { + stack = item; + return this; + } + + public DisplayBuilder id(ResourceLocation transId) { + translationId = transId; + return this; + } + + public DisplayBuilder toast(boolean toast) { + this.showToast = toast; + return this; + } + + public DisplayBuilder chat(boolean chat) { + this.showInChat = chat; + return this; + } + + public DisplayBuilder hidden(boolean hidden) { + this.isHidden = hidden; + return this; + } + + public DisplayBuilder background(ResourceLocation resource) { + this.background = resource; + return this; + } + + public DisplayBuilder frame(FrameType frame) { + this.frame = frame; + return this; + } + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/datagen/BlockLootGenerator.java b/src/main/java/dev/compactmods/machines/datagen/BlockLootGenerator.java similarity index 94% rename from src/main/java/com/robotgryphon/compactmachines/datagen/BlockLootGenerator.java rename to src/main/java/dev/compactmods/machines/datagen/BlockLootGenerator.java index 75bc022d..41b8f341 100644 --- a/src/main/java/com/robotgryphon/compactmachines/datagen/BlockLootGenerator.java +++ b/src/main/java/dev/compactmods/machines/datagen/BlockLootGenerator.java @@ -1,9 +1,9 @@ -package com.robotgryphon.compactmachines.datagen; +package dev.compactmods.machines.datagen; import com.google.common.collect.ImmutableList; import com.mojang.datafixers.util.Pair; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.reference.Reference; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.reference.Reference; import net.minecraft.block.Block; import net.minecraft.data.DataGenerator; import net.minecraft.data.LootTableProvider; @@ -63,7 +63,7 @@ private LootPool.Builder registerSelfDroppedBlock(RegistryObject block, R return builder; } - private ILootFunction.IBuilder CopyOwnerAndReferenceFunction = CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY) + private final ILootFunction.IBuilder CopyOwnerAndReferenceFunction = CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY) .copy(Reference.CompactMachines.OWNER_NBT, Reference.CompactMachines.OWNER_NBT) .copy("coords", "cm.coords"); diff --git a/src/main/java/com/robotgryphon/compactmachines/datagen/DataGeneration.java b/src/main/java/dev/compactmods/machines/datagen/DataGeneration.java similarity index 88% rename from src/main/java/com/robotgryphon/compactmachines/datagen/DataGeneration.java rename to src/main/java/dev/compactmods/machines/datagen/DataGeneration.java index 7c0250f2..a44f6ed5 100644 --- a/src/main/java/com/robotgryphon/compactmachines/datagen/DataGeneration.java +++ b/src/main/java/dev/compactmods/machines/datagen/DataGeneration.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.datagen; +package dev.compactmods.machines.datagen; -import com.robotgryphon.compactmachines.CompactMachines; +import dev.compactmods.machines.CompactMachines; import net.minecraft.data.DataGenerator; import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -22,6 +22,8 @@ public static void gatherData(GatherDataEvent event) { private static void registerServerProviders(DataGenerator generator, GatherDataEvent event) { generator.addProvider(new BlockLootGenerator(generator)); generator.addProvider(new RecipeGenerator(generator)); + + generator.addProvider(new AdvancementGenerator(generator)); } private static void registerClientProviders(DataGenerator generator, GatherDataEvent event) { diff --git a/src/main/java/com/robotgryphon/compactmachines/datagen/RecipeGenerator.java b/src/main/java/dev/compactmods/machines/datagen/RecipeGenerator.java similarity index 83% rename from src/main/java/com/robotgryphon/compactmachines/datagen/RecipeGenerator.java rename to src/main/java/dev/compactmods/machines/datagen/RecipeGenerator.java index 7a026f25..8e568bac 100644 --- a/src/main/java/com/robotgryphon/compactmachines/datagen/RecipeGenerator.java +++ b/src/main/java/dev/compactmods/machines/datagen/RecipeGenerator.java @@ -1,13 +1,9 @@ -package com.robotgryphon.compactmachines.datagen; +package dev.compactmods.machines.datagen; -import com.robotgryphon.compactmachines.config.EnableVanillaRecipesConfigCondition; -import com.robotgryphon.compactmachines.core.Registration; -import net.minecraft.data.DataGenerator; -import net.minecraft.data.IFinishedRecipe; -import net.minecraft.data.RecipeProvider; -import net.minecraft.data.ShapedRecipeBuilder; +import dev.compactmods.machines.config.EnableVanillaRecipesConfigCondition; +import dev.compactmods.machines.core.Registration; +import net.minecraft.data.*; import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.tags.ITag; import net.minecraft.tags.ItemTags; @@ -30,7 +26,7 @@ protected void buildShapelessRecipes(Consumer consumer) { .pattern(" I ") .define('R', Tags.Items.DUSTS_REDSTONE) .define('I', Tags.Items.STORAGE_BLOCKS_IRON) - .unlockedBy("has_recipe", has(Tags.Items.STORAGE_BLOCKS_IRON)) + .unlockedBy("picked_up_iron", has(Tags.Items.STORAGE_BLOCKS_IRON)) .save(consumer); ShapedRecipeBuilder.shaped(Registration.PERSONAL_SHRINKING_DEVICE.get()) @@ -41,9 +37,13 @@ protected void buildShapelessRecipes(Consumer consumer) { .define('E', Items.ENDER_EYE) .define('B', Items.BOOK) .define('I', Tags.Items.INGOTS_IRON) - .unlockedBy("has_recipe", has(Items.ENDER_EYE)) + .unlockedBy("picked_up_ender_eye", has(Items.ENDER_EYE)) .save(consumer); + addMachineRecipes(consumer); + } + + private void addMachineRecipes(Consumer consumer) { registerMachineRecipe(consumer, Registration.MACHINE_BLOCK_ITEM_TINY.get(), ItemTags.PLANKS); registerMachineRecipe(consumer, Registration.MACHINE_BLOCK_ITEM_SMALL.get(), Tags.Items.STORAGE_BLOCKS_IRON); registerMachineRecipe(consumer, Registration.MACHINE_BLOCK_ITEM_NORMAL.get(), Tags.Items.STORAGE_BLOCKS_GOLD); diff --git a/src/main/java/com/robotgryphon/compactmachines/datagen/StateGenerator.java b/src/main/java/dev/compactmods/machines/datagen/StateGenerator.java similarity index 75% rename from src/main/java/com/robotgryphon/compactmachines/datagen/StateGenerator.java rename to src/main/java/dev/compactmods/machines/datagen/StateGenerator.java index 443b4b79..47834120 100644 --- a/src/main/java/com/robotgryphon/compactmachines/datagen/StateGenerator.java +++ b/src/main/java/dev/compactmods/machines/datagen/StateGenerator.java @@ -1,15 +1,11 @@ -package com.robotgryphon.compactmachines.datagen; +package dev.compactmods.machines.datagen; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.reference.EnumMachineSize; import net.minecraft.data.DataGenerator; import net.minecraftforge.client.model.generators.BlockStateProvider; import net.minecraftforge.common.data.ExistingFileHelper; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - public class StateGenerator extends BlockStateProvider { public StateGenerator(DataGenerator gen, ExistingFileHelper exFileHelper) { super(gen, CompactMachines.MOD_ID, exFileHelper); diff --git a/src/main/java/com/robotgryphon/compactmachines/datagen/TunnelWallStateGenerator.java b/src/main/java/dev/compactmods/machines/datagen/TunnelWallStateGenerator.java similarity index 88% rename from src/main/java/com/robotgryphon/compactmachines/datagen/TunnelWallStateGenerator.java rename to src/main/java/dev/compactmods/machines/datagen/TunnelWallStateGenerator.java index 2782eae2..70eb49c9 100644 --- a/src/main/java/com/robotgryphon/compactmachines/datagen/TunnelWallStateGenerator.java +++ b/src/main/java/dev/compactmods/machines/datagen/TunnelWallStateGenerator.java @@ -1,9 +1,9 @@ -package com.robotgryphon.compactmachines.datagen; +package dev.compactmods.machines.datagen; -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.core.Registration; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.core.Registration; import net.minecraft.block.Block; import net.minecraft.data.DataGenerator; import net.minecraft.util.Direction; @@ -14,9 +14,6 @@ import net.minecraftforge.client.model.generators.ModelBuilder; import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.client.model.generators.ModelBuilder.ElementBuilder; -import net.minecraftforge.client.model.generators.ModelBuilder.ElementBuilder.FaceBuilder; - public class TunnelWallStateGenerator extends BlockStateProvider { public TunnelWallStateGenerator(DataGenerator gen, ExistingFileHelper exFileHelper) { super(gen, CompactMachines.MOD_ID, exFileHelper); diff --git a/src/main/java/dev/compactmods/machines/item/ItemBlockMachine.java b/src/main/java/dev/compactmods/machines/item/ItemBlockMachine.java new file mode 100644 index 00000000..349f98fd --- /dev/null +++ b/src/main/java/dev/compactmods/machines/item/ItemBlockMachine.java @@ -0,0 +1,102 @@ +package dev.compactmods.machines.item; + +import com.mojang.authlib.GameProfile; +import dev.compactmods.machines.api.core.Tooltips; +import dev.compactmods.machines.block.BlockCompactMachine; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.reference.Reference; +import dev.compactmods.machines.util.PlayerUtil; +import dev.compactmods.machines.util.TranslationUtil; +import net.minecraft.block.Block; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.NonNullList; +import net.minecraft.util.text.*; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public class ItemBlockMachine extends BlockItem { + + public ItemBlockMachine(Block blockIn, EnumMachineSize size, Properties builder) { + super(blockIn, builder); + } + + @Override + public void fillItemCategory(ItemGroup group, NonNullList items) { + super.fillItemCategory(group, items); + } + + public static Optional getMachineId(ItemStack stack) { + if (!stack.hasTag()) + return Optional.empty(); + + CompoundNBT machineData = stack.getTagElement("cm"); + if (machineData == null) + return Optional.empty(); + + if (machineData.contains("coords")) { + int c = machineData.getInt("coords"); + return c > -1 ? Optional.of(c) : Optional.empty(); + } + + return Optional.empty(); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { + super.appendHoverText(stack, worldIn, tooltip, flagIn); + + // We need NBT data for the rest of this + if (stack.hasTag()) { + + CompoundNBT nbt = stack.getTag(); + assert nbt != null; + + getMachineId(stack).ifPresent(id -> { + tooltip.add(TranslationUtil.tooltip(Tooltips.Machines.ID, id)); + }); + + if (nbt.contains(Reference.CompactMachines.OWNER_NBT)) { + UUID owner = nbt.getUUID(Reference.CompactMachines.OWNER_NBT); + Optional playerProfile = PlayerUtil.getProfileByUUID(worldIn, owner); + + IFormattableTextComponent player = playerProfile + .map(p -> (IFormattableTextComponent) new StringTextComponent(p.getName())) + .orElse(TranslationUtil.tooltip(Tooltips.UNKNOWN_PLAYER_NAME)); + + IFormattableTextComponent ownerText = TranslationUtil.tooltip(Tooltips.Machines.OWNER) + .append(player); + + tooltip.add(ownerText); + } + + } + + if (Screen.hasShiftDown()) { + Block b = Block.byItem(stack.getItem()); + if (b instanceof BlockCompactMachine) { + EnumMachineSize size = ((BlockCompactMachine) b).getSize(); + int internalSize = size.getInternalSize(); + + IFormattableTextComponent text = TranslationUtil.tooltip(Tooltips.Machines.SIZE, internalSize) + .withStyle(TextFormatting.YELLOW); + + tooltip.add(text); + } + } else { + IFormattableTextComponent text = TranslationUtil.tooltip(Tooltips.HINT_HOLD_SHIFT) + .withStyle(TextFormatting.DARK_GRAY) + .withStyle(TextFormatting.ITALIC); + + tooltip.add(text); + } + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/item/ItemBlockWall.java b/src/main/java/dev/compactmods/machines/item/ItemBlockWall.java similarity index 52% rename from src/main/java/com/robotgryphon/compactmachines/item/ItemBlockWall.java rename to src/main/java/dev/compactmods/machines/item/ItemBlockWall.java index decaf84f..54ae84a2 100644 --- a/src/main/java/com/robotgryphon/compactmachines/item/ItemBlockWall.java +++ b/src/main/java/dev/compactmods/machines/item/ItemBlockWall.java @@ -1,7 +1,10 @@ -package com.robotgryphon.compactmachines.item; +package dev.compactmods.machines.item; -import com.robotgryphon.compactmachines.core.Registration; +import dev.compactmods.machines.api.core.Tooltips; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.util.TranslationUtil; import net.minecraft.block.Block; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -11,8 +14,6 @@ import javax.annotation.Nullable; import java.util.List; -import net.minecraft.item.Item.Properties; - public class ItemBlockWall extends BlockItem { public ItemBlockWall(Block blockIn, Properties builder) { @@ -24,9 +25,16 @@ public void appendHoverText(ItemStack stack, @Nullable World worldIn, List tooltip, ITooltipFlag flagIn) { super.appendHoverText(stack, worldIn, tooltip, flagIn); if (Screen.hasShiftDown()) { - tooltip.add( - new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".psd.hint") - .withStyle(TextFormatting.YELLOW)); + tooltip.add(TranslationUtil.tooltip(Tooltips.Details.PERSONAL_SHRINKING_DEVICE) + .withStyle(TextFormatting.YELLOW)); } else { - tooltip.add( - new TranslationTextComponent("tooltip." + CompactMachines.MOD_ID + ".hold_shift.hint") - .withStyle(TextFormatting.GRAY)); + tooltip.add(TranslationUtil.tooltip(Tooltips.HINT_HOLD_SHIFT) + .withStyle(TextFormatting.DARK_GRAY) + .withStyle(TextFormatting.ITALIC)); } } @@ -68,7 +55,7 @@ public ActionResult use(World world, PlayerEntity player, Hand hand) // If we aren't in the compact dimension, allow PSD guide usage // Prevents misfiring if a player is trying to leave a machine or set their spawn - if(world.isClientSide && world.dimension() != Registration.COMPACT_DIMENSION) { + if (world.isClientSide && world.dimension() != Registration.COMPACT_DIMENSION) { PersonalShrinkingDeviceScreen.show(); return ActionResult.success(stack); } @@ -77,14 +64,20 @@ public ActionResult use(World world, PlayerEntity player, Hand hand) ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; if (serverPlayer.level.dimension() == Registration.COMPACT_DIMENSION) { - ServerWorld serverWorld = serverPlayer.getLevel(); + ServerWorld serverWorld = serverPlayer.getLevel(); if (player.isShiftKeyDown()) { - CompactMachineUtil.setMachineSpawn(serverWorld.getServer(), player.blockPosition()); + ChunkPos machineChunk = new ChunkPos(player.blockPosition()); + + CompactRoomData intern = CompactRoomData.get(serverWorld.getServer()); + if (intern != null) { + // Use internal data to set new spawn point + intern.setSpawn(machineChunk, player.position()); - IFormattableTextComponent tc = new TranslationTextComponent("messages.compactmachines.psd.spawnpoint_set") - .withStyle(TextFormatting.GREEN); + IFormattableTextComponent tc = TranslationUtil.message(Messages.MACHINE_SPAWNPOINT_SET) + .withStyle(TextFormatting.GREEN); - player.displayClientMessage(tc, true); + player.displayClientMessage(tc, true); + } } else { PlayerUtil.teleportPlayerOutOfMachine(serverWorld, serverPlayer); } @@ -93,5 +86,4 @@ public ActionResult use(World world, PlayerEntity player, Hand hand) return ActionResult.success(stack); } - } diff --git a/src/main/java/com/robotgryphon/compactmachines/item/TunnelItem.java b/src/main/java/dev/compactmods/machines/item/TunnelItem.java similarity index 50% rename from src/main/java/com/robotgryphon/compactmachines/item/TunnelItem.java rename to src/main/java/dev/compactmods/machines/item/TunnelItem.java index ea28c2d4..ba5f2166 100644 --- a/src/main/java/com/robotgryphon/compactmachines/item/TunnelItem.java +++ b/src/main/java/dev/compactmods/machines/item/TunnelItem.java @@ -1,11 +1,14 @@ -package com.robotgryphon.compactmachines.item; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.block.walls.TunnelWallBlock; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneReaderTunnel; +package dev.compactmods.machines.item; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.core.Tooltips; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.block.walls.SolidWallBlock; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.api.tunnels.redstone.IRedstoneReaderTunnel; +import dev.compactmods.machines.util.TranslationUtil; import net.minecraft.block.BlockState; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.ITooltipFlag; @@ -19,7 +22,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; import net.minecraft.util.text.*; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; @@ -31,8 +33,6 @@ import java.util.List; import java.util.Optional; -import net.minecraft.item.Item.Properties; - public class TunnelItem extends Item { public TunnelItem(Properties properties) { super(properties); @@ -59,6 +59,10 @@ public void appendHoverText(@Nonnull ItemStack stack, @Nullable World worldIn, L .withStyle(TextFormatting.ITALIC); tooltip.add(type); + } else { + tooltip.add(TranslationUtil.tooltip(Tooltips.HINT_HOLD_SHIFT) + .withStyle(TextFormatting.DARK_GRAY) + .withStyle(TextFormatting.ITALIC)); } }); } @@ -93,76 +97,16 @@ public static Optional getDefinition(ItemStack stack) { @Override public ActionResultType useOn(ItemUseContext context) { - World w = context.getLevel(); - if (w.isClientSide()) - return ActionResultType.SUCCESS; - - BlockPos pos = context.getClickedPos(); - BlockState blockState = w.getBlockState(pos); - - if (blockState.getBlock() != Registration.BLOCK_SOLID_WALL.get()) - return ActionResultType.FAIL; - - if (context.getPlayer() instanceof ServerPlayerEntity) { - ItemStack is = context.getItemInHand(); - Item i = is.getItem(); - - TunnelItem ti = ((TunnelItem) i); - Optional definition = ti.getDefinition(context.getItemInHand()); - - definition.ifPresent(def -> { - BlockState tunnelState = Registration.BLOCK_TUNNEL_WALL.get() - .defaultBlockState() - .setValue(TunnelWallBlock.TUNNEL_SIDE, context.getClickedFace()); - - // Redstone Support - boolean redstone = (def instanceof IRedstoneReaderTunnel); - tunnelState = tunnelState.setValue(TunnelWallBlock.REDSTONE, redstone); - w.setBlock(pos, tunnelState, 3); - - // Get the server and add a deferred task - allows the tile to be created on the client first - MinecraftServer server = ((ServerWorld) context.getLevel()).getServer(); - server.submitAsync(() -> { - TunnelWallTile tile = (TunnelWallTile) context.getLevel().getBlockEntity(context.getClickedPos()); - tile.setTunnelType(def.getRegistryName()); - }); + final World level = context.getLevel(); + if(!level.isClientSide) { + final PlayerEntity player = context.getPlayer(); + final BlockState state = level.getBlockState(context.getClickedPos()); - is.shrink(1); - }); - - return ActionResultType.CONSUME; - } - - return ActionResultType.FAIL; - } - - /** - * Implementation for easily swapping a tunnel type for another. - * - * @param type - * @param player - * @param hand - * @return - */ - protected ActionResult swapTunnelType(Item type, PlayerEntity player, Hand hand) { - if (player instanceof ServerPlayerEntity) { - if (player.isShiftKeyDown()) { - ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; - ItemStack stack = serverPlayer.getItemInHand(hand); - ItemStack newStack = new ItemStack(type, stack.getCount()); - - serverPlayer.setItemInHand(hand, newStack); - - IFormattableTextComponent msg = new StringTextComponent("switch state") - .withStyle(TextFormatting.GOLD); - - serverPlayer.displayClientMessage(msg, true); - return ActionResult.consume(newStack); + if(state.getBlock() instanceof SolidWallBlock && player != null) { + player.displayClientMessage(TranslationUtil.message(new ResourceLocation(CompactMachines.MOD_ID, "tunnels_nyi")), true); } } - return ActionResult.pass(player.getItemInHand(hand)); + return ActionResultType.sidedSuccess(level.isClientSide); } - - } diff --git a/src/main/java/dev/compactmods/machines/level/BiomeHelper.java b/src/main/java/dev/compactmods/machines/level/BiomeHelper.java new file mode 100644 index 00000000..7dd349de --- /dev/null +++ b/src/main/java/dev/compactmods/machines/level/BiomeHelper.java @@ -0,0 +1,18 @@ +package dev.compactmods.machines.level; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.biome.BiomeContainer; + +public class BiomeHelper { + private static final int WIDTH_BITS = (int)Math.round(Math.log(16.0D) / Math.log(2.0D)) - 2; + + public static int biomeIndex(BlockPos pos) { + int l = (pos.getX() >> 2) & BiomeContainer.HORIZONTAL_MASK; + int m = MathHelper.clamp(pos.getY() >> 2, 0, BiomeContainer.VERTICAL_MASK); + int n = (pos.getZ() >> 2) & BiomeContainer.HORIZONTAL_MASK; + return m << WIDTH_BITS + WIDTH_BITS + | n << WIDTH_BITS + | l; + } +} diff --git a/src/main/java/dev/compactmods/machines/network/CMPacketTargets.java b/src/main/java/dev/compactmods/machines/network/CMPacketTargets.java new file mode 100644 index 00000000..394d6781 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/network/CMPacketTargets.java @@ -0,0 +1,58 @@ +package dev.compactmods.machines.network; + +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import net.minecraft.network.IPacket; +import net.minecraft.network.play.ServerPlayNetHandler; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.fml.network.NetworkDirection; +import net.minecraftforge.fml.network.PacketDistributor; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class CMPacketTargets { + + public static final PacketDistributor TRACKING_ROOM = new PacketDistributor<>( + CMPacketTargets::trackingRoom, NetworkDirection.PLAY_TO_CLIENT); + + private static Consumer> trackingRoom(PacketDistributor dist, Supplier supplier) { + Chunk roomChunk = supplier.get(); + World level = roomChunk.getLevel(); + + HashMap trackingPlayersGlobal = new HashMap<>(); + + if (level instanceof ServerWorld) { + ServerWorld serverWorld = (ServerWorld) level; + MinecraftServer server = serverWorld.getServer(); + + MachineConnections connections = MachineConnections.get(server); + CompactMachineData machines = CompactMachineData.get(server); + + Collection linked = connections.graph.getMachinesFor(roomChunk.getPos()); + + for (int machine : linked) { + machines.getMachineLocation(machine).ifPresent(loc -> { + Optional machineWorld = loc.getWorld(server); + BlockPos machineWorldLocation = loc.getBlockPosition(); + ChunkPos machineWorldChunk = new ChunkPos(machineWorldLocation); + + machineWorld.ifPresent(mw -> { + mw.getChunkSource().chunkMap.getPlayers(machineWorldChunk, false).forEach(player -> { + if (!trackingPlayersGlobal.containsKey(player.getUUID())) + trackingPlayersGlobal.put(player.getUUID(), player.connection); + }); + }); + }); + } + } + + return pack -> trackingPlayersGlobal.values().forEach(conn -> conn.send(pack)); + } +} diff --git a/src/main/java/dev/compactmods/machines/network/MachinePlayersChangedPacket.java b/src/main/java/dev/compactmods/machines/network/MachinePlayersChangedPacket.java new file mode 100644 index 00000000..50c578c8 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/network/MachinePlayersChangedPacket.java @@ -0,0 +1,152 @@ +package dev.compactmods.machines.network; + +import com.google.common.collect.ImmutableSet; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.client.machine.MachinePlayerEventHandler; +import dev.compactmods.machines.data.codec.CodecExtensions; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.ChunkPos; +import net.minecraftforge.fml.network.NetworkEvent; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.*; +import java.util.function.Supplier; + +public class MachinePlayersChangedPacket { + + public ChunkPos machine; + public UUID playerID; + public ImmutableSet machinePositions; + public EnumPlayerChangeType type; + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + CodecExtensions.CHUNKPOS.fieldOf("machine").forGetter(MachinePlayersChangedPacket::getChunkPos), + CodecExtensions.UUID_CODEC.fieldOf("player").forGetter(MachinePlayersChangedPacket::getPlayer), + Codec.STRING.fieldOf("type").forGetter((p) -> p.type.name()), + DimensionalPosition.CODEC.listOf().fieldOf("positions").forGetter(p -> p.machinePositions.asList()) + ).apply(i, MachinePlayersChangedPacket::new)); + + public MachinePlayersChangedPacket(PacketBuffer buf) { + try { + MachinePlayersChangedPacket pkt = buf.readWithCodec(MachinePlayersChangedPacket.CODEC); + + machine = pkt.machine; + playerID = pkt.playerID; + machinePositions = pkt.machinePositions; + type = pkt.type; + } catch (IOException e) { + CompactMachines.LOGGER.error(e); + } + } + + private MachinePlayersChangedPacket(ChunkPos chunkPos, UUID player, String type, Collection positions) { + this.machine = chunkPos; + this.playerID = player; + this.type = EnumPlayerChangeType.valueOf(type); + this.machinePositions = ImmutableSet.copyOf(positions); + } + + public static void handle(MachinePlayersChangedPacket message, Supplier context) { + NetworkEvent.Context ctx = context.get(); + + message.machinePositions.forEach(machinePos -> { + CompactMachines.LOGGER.debug("Player {} machine {} via {}", message.type, message.machine, machinePos); + MachinePlayerEventHandler.handlePlayerMachineChanged(message.playerID, message.type, machinePos); + }); + + ctx.setPacketHandled(true); + } + + public static void encode(MachinePlayersChangedPacket pkt, PacketBuffer buf) { + try { + buf.writeWithCodec(CODEC, pkt); + } catch (IOException e) { + CompactMachines.LOGGER.error(e); + } + } + + private UUID getPlayer() { + return playerID; + } + + private ChunkPos getChunkPos() { + return machine; + } + + public enum EnumPlayerChangeType { + ENTERED, + EXITED + } + + public static class Builder { + + private final MinecraftServer server; + private EnumPlayerChangeType change; + private ChunkPos chunk; + private UUID player; + private int entryPoint; + + private Builder(MinecraftServer server) { + this.server = server; + this.change = EnumPlayerChangeType.EXITED; + } + + public static Builder create(MinecraftServer server) { + return new Builder(server); + } + + @Nullable + public MachinePlayersChangedPacket build() { + MachineConnections connections = MachineConnections.get(server); + CompactMachineData extern = CompactMachineData.get(server); + if(connections == null || extern == null) + { + CompactMachines.LOGGER.fatal("Could not load external machine data from server."); + return null; + } + + Collection externalMachineIDs = connections.graph.getMachinesFor(chunk); + HashSet externalLocations = new HashSet<>(); + for(int eid : externalMachineIDs) { + final Optional loc = extern.getMachineLocation(eid); + loc.ifPresent(externalLocations::add); + } + + return new MachinePlayersChangedPacket(chunk, player, change.name(), externalLocations); + } + + public Builder forMachine(ChunkPos insideChunk) { + this.chunk = insideChunk; + return this; + } + + public Builder forPlayer(ServerPlayerEntity player) { + this.player = player.getUUID(); + return this; + } + + public Builder forPlayer(UUID player) { + this.player = player; + return this; + } + + public Builder enteredFrom(int machineId) { + this.entryPoint = machineId; + this.change = EnumPlayerChangeType.ENTERED; + return this; + } + + public Builder exited() { + this.change = EnumPlayerChangeType.EXITED; + return this; + } + } +} diff --git a/src/main/java/dev/compactmods/machines/network/NetworkHandler.java b/src/main/java/dev/compactmods/machines/network/NetworkHandler.java new file mode 100644 index 00000000..a093d0e2 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/network/NetworkHandler.java @@ -0,0 +1,32 @@ +package dev.compactmods.machines.network; + +import dev.compactmods.machines.CompactMachines; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkDirection; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; + +public class NetworkHandler { + private static int index = 0; + private static final String PROTOCOL_VERSION = "1"; + public static final SimpleChannel MAIN_CHANNEL = NetworkRegistry.newSimpleChannel( + new ResourceLocation(CompactMachines.MOD_ID, "main"), + () -> PROTOCOL_VERSION, + PROTOCOL_VERSION::equals, + PROTOCOL_VERSION::equals + ); + + public static void initialize() { + MAIN_CHANNEL.messageBuilder(MachinePlayersChangedPacket.class, index++, NetworkDirection.PLAY_TO_CLIENT) + .encoder(MachinePlayersChangedPacket::encode) + .decoder(MachinePlayersChangedPacket::new) + .consumer(MachinePlayersChangedPacket::handle) + .add(); + + MAIN_CHANNEL.messageBuilder(TunnelAddedPacket.class, index++, NetworkDirection.PLAY_TO_CLIENT) + .encoder(TunnelAddedPacket::encode) + .decoder(TunnelAddedPacket::new) + .consumer(TunnelAddedPacket::handle) + .add(); + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/network/TunnelAddedPacket.java b/src/main/java/dev/compactmods/machines/network/TunnelAddedPacket.java similarity index 70% rename from src/main/java/com/robotgryphon/compactmachines/network/TunnelAddedPacket.java rename to src/main/java/dev/compactmods/machines/network/TunnelAddedPacket.java index cd0c19bd..f674b648 100644 --- a/src/main/java/com/robotgryphon/compactmachines/network/TunnelAddedPacket.java +++ b/src/main/java/dev/compactmods/machines/network/TunnelAddedPacket.java @@ -1,6 +1,6 @@ -package com.robotgryphon.compactmachines.network; +package dev.compactmods.machines.network; -import com.robotgryphon.compactmachines.client.ClientTunnelHandler; +import dev.compactmods.machines.client.ClientTunnelHandler; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -12,17 +12,19 @@ public class TunnelAddedPacket { - private BlockPos position; - private ResourceLocation type; - - private TunnelAddedPacket() { - } + private final BlockPos position; + private final ResourceLocation type; public TunnelAddedPacket(BlockPos tunnelPos, ResourceLocation tunnelType) { this.position = tunnelPos; this.type = tunnelType; } + public TunnelAddedPacket(PacketBuffer buf) { + position = buf.readBlockPos(); + type = buf.readResourceLocation(); + } + public static void handle(TunnelAddedPacket message, Supplier context) { NetworkEvent.Context ctx = context.get(); @@ -40,12 +42,4 @@ public static void encode(TunnelAddedPacket pkt, PacketBuffer buf) { buf.writeBlockPos(pkt.position); buf.writeResourceLocation(pkt.type); } - - public static TunnelAddedPacket decode(PacketBuffer buf) { - TunnelAddedPacket pkt = new TunnelAddedPacket(); - pkt.position = buf.readBlockPos(); - pkt.type = buf.readResourceLocation(); - - return pkt; - } } diff --git a/src/main/java/com/robotgryphon/compactmachines/reference/EnumMachineSize.java b/src/main/java/dev/compactmods/machines/reference/EnumMachineSize.java similarity index 65% rename from src/main/java/com/robotgryphon/compactmachines/reference/EnumMachineSize.java rename to src/main/java/dev/compactmods/machines/reference/EnumMachineSize.java index 6e9ec66b..96c004fa 100644 --- a/src/main/java/com/robotgryphon/compactmachines/reference/EnumMachineSize.java +++ b/src/main/java/dev/compactmods/machines/reference/EnumMachineSize.java @@ -1,6 +1,9 @@ -package com.robotgryphon.compactmachines.reference; +package dev.compactmods.machines.reference; +import com.mojang.serialization.Codec; import net.minecraft.util.IStringSerializable; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; public enum EnumMachineSize implements IStringSerializable { TINY ("tiny", 3), @@ -10,8 +13,11 @@ public enum EnumMachineSize implements IStringSerializable { GIANT ("giant", 11), MAXIMUM ("maximum", 13); - private String name; - private int internalSize; + private final String name; + private final int internalSize; + + public static final Codec CODEC = IStringSerializable.fromEnum( + EnumMachineSize::values, EnumMachineSize::getFromSize); EnumMachineSize(String name, int internalSize) { this.name = name; @@ -26,6 +32,11 @@ public String getName() { return this.name; } + public AxisAlignedBB getBounds(BlockPos center) { + AxisAlignedBB bounds = new AxisAlignedBB(center); + return bounds.inflate(Math.floorDiv(internalSize, 2)); + } + public int getInternalSize() { return this.internalSize; } diff --git a/src/main/java/com/robotgryphon/compactmachines/reference/GuiIds.java b/src/main/java/dev/compactmods/machines/reference/GuiIds.java similarity index 59% rename from src/main/java/com/robotgryphon/compactmachines/reference/GuiIds.java rename to src/main/java/dev/compactmods/machines/reference/GuiIds.java index 720d407a..fcb887ec 100644 --- a/src/main/java/com/robotgryphon/compactmachines/reference/GuiIds.java +++ b/src/main/java/dev/compactmods/machines/reference/GuiIds.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.reference; +package dev.compactmods.machines.reference; public enum GuiIds { PSD_GUIDE, diff --git a/src/main/java/com/robotgryphon/compactmachines/reference/Reference.java b/src/main/java/dev/compactmods/machines/reference/Reference.java similarity index 80% rename from src/main/java/com/robotgryphon/compactmachines/reference/Reference.java rename to src/main/java/dev/compactmods/machines/reference/Reference.java index beb869be..c9c2085f 100644 --- a/src/main/java/com/robotgryphon/compactmachines/reference/Reference.java +++ b/src/main/java/dev/compactmods/machines/reference/Reference.java @@ -1,4 +1,4 @@ -package com.robotgryphon.compactmachines.reference; +package dev.compactmods.machines.reference; public abstract class Reference { public static class CompactMachines { diff --git a/src/main/java/com/robotgryphon/compactmachines/reference/Resources.java b/src/main/java/dev/compactmods/machines/reference/Resources.java similarity index 73% rename from src/main/java/com/robotgryphon/compactmachines/reference/Resources.java rename to src/main/java/dev/compactmods/machines/reference/Resources.java index 2372ac2e..a9e73c82 100644 --- a/src/main/java/com/robotgryphon/compactmachines/reference/Resources.java +++ b/src/main/java/dev/compactmods/machines/reference/Resources.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.reference; +package dev.compactmods.machines.reference; import net.minecraft.util.ResourceLocation; -import com.robotgryphon.compactmachines.CompactMachines; +import dev.compactmods.machines.CompactMachines; public class Resources { public static final class Gui { diff --git a/src/main/java/dev/compactmods/machines/rooms/capability/CMRoomHistory.java b/src/main/java/dev/compactmods/machines/rooms/capability/CMRoomHistory.java new file mode 100644 index 00000000..d6d655bb --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/capability/CMRoomHistory.java @@ -0,0 +1,67 @@ +package dev.compactmods.machines.rooms.capability; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Optional; +import com.mojang.serialization.DataResult; +import dev.compactmods.machines.data.codec.NbtListCollector; +import dev.compactmods.machines.rooms.history.IRoomHistoryItem; +import dev.compactmods.machines.rooms.history.PlayerRoomHistoryItem; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTDynamicOps; + +public class CMRoomHistory implements IRoomHistory { + + private final Deque history; + + public CMRoomHistory() { + history = new ArrayDeque<>(10); + } + + @Override + public void clear() { + history.clear(); + } + + @Override + public boolean hasHistory() { + return !history.isEmpty(); + } + + @Override + public IRoomHistoryItem peek() { + return history.peekLast(); + } + + @Override + public IRoomHistoryItem pop() { + return history.removeLast(); + } + + @Override + public void addHistory(IRoomHistoryItem item) { + history.add(item); + } + + @Override + public ListNBT serializeNBT() { + return history.stream() + .map(hi -> PlayerRoomHistoryItem.CODEC.encodeStart(NBTDynamicOps.INSTANCE, hi)) + .map(DataResult::result) + .filter(Optional::isPresent) + .map(Optional::get) + .map(x -> x) + .collect(NbtListCollector.toNbtList()); + } + + @Override + public void deserializeNBT(ListNBT nbt) { + nbt.stream() + .map(it -> PlayerRoomHistoryItem.CODEC.parse(NBTDynamicOps.INSTANCE, it)) + .map(DataResult::result) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(history::addLast); + } +} diff --git a/src/main/java/dev/compactmods/machines/rooms/capability/CapabilityRoomHistory.java b/src/main/java/dev/compactmods/machines/rooms/capability/CapabilityRoomHistory.java new file mode 100644 index 00000000..06859dc6 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/capability/CapabilityRoomHistory.java @@ -0,0 +1,33 @@ +package dev.compactmods.machines.rooms.capability; + +import javax.annotation.Nullable; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityInject; +import net.minecraftforge.common.capabilities.CapabilityManager; + +public class CapabilityRoomHistory { + + @CapabilityInject(IRoomHistory.class) + public static Capability HISTORY_CAPABILITY = null; + + public static class CapabilityRoomHistoryStorage implements Capability.IStorage { + @Nullable + @Override + public INBT writeNBT(Capability capability, IRoomHistory instance, Direction side) { + return instance.serializeNBT(); + } + + @Override + public void readNBT(Capability capability, IRoomHistory instance, Direction side, INBT nbt) { + if(nbt instanceof ListNBT) + instance.deserializeNBT((ListNBT) nbt); + } + } + + public static void register() { + CapabilityManager.INSTANCE.register(IRoomHistory.class, new CapabilityRoomHistoryStorage(), CMRoomHistory::new); + } +} diff --git a/src/main/java/dev/compactmods/machines/rooms/capability/IRoomHistory.java b/src/main/java/dev/compactmods/machines/rooms/capability/IRoomHistory.java new file mode 100644 index 00000000..1cce5672 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/capability/IRoomHistory.java @@ -0,0 +1,15 @@ +package dev.compactmods.machines.rooms.capability; + +import dev.compactmods.machines.rooms.history.IRoomHistoryItem; +import net.minecraft.nbt.ListNBT; +import net.minecraftforge.common.util.INBTSerializable; + +public interface IRoomHistory extends INBTSerializable { + + void clear(); + boolean hasHistory(); + IRoomHistoryItem peek(); + IRoomHistoryItem pop(); + + void addHistory(IRoomHistoryItem item); +} diff --git a/src/main/java/dev/compactmods/machines/rooms/capability/PlayerRoomHistoryCapProvider.java b/src/main/java/dev/compactmods/machines/rooms/capability/PlayerRoomHistoryCapProvider.java new file mode 100644 index 00000000..ea2227c1 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/capability/PlayerRoomHistoryCapProvider.java @@ -0,0 +1,49 @@ +package dev.compactmods.machines.rooms.capability; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.common.util.LazyOptional; + +public class PlayerRoomHistoryCapProvider implements ICapabilityProvider, INBTSerializable { + + private final PlayerEntity player; + private final CMRoomHistory history; + private LazyOptional opt = LazyOptional.empty(); + + public PlayerRoomHistoryCapProvider(PlayerEntity player) { + this.player = player; + this.history = new CMRoomHistory(); + this.opt = LazyOptional.of(() -> this.history); + } + + @Nonnull + @Override + public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction side) { + if(cap == CapabilityRoomHistory.HISTORY_CAPABILITY) + return opt.cast(); + + return LazyOptional.empty(); + } + + @Override + public CompoundNBT serializeNBT() { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("history", history.serializeNBT()); + return nbt; + } + + @Override + public void deserializeNBT(CompoundNBT nbt) { + if(nbt.contains("history")) { + history.clear(); + history.deserializeNBT(nbt.getList("history", Constants.NBT.TAG_COMPOUND)); + } + } +} diff --git a/src/main/java/dev/compactmods/machines/rooms/capability/RoomCapEventHandler.java b/src/main/java/dev/compactmods/machines/rooms/capability/RoomCapEventHandler.java new file mode 100644 index 00000000..4b15c93e --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/capability/RoomCapEventHandler.java @@ -0,0 +1,24 @@ +package dev.compactmods.machines.rooms.capability; + +import dev.compactmods.machines.CompactMachines; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class RoomCapEventHandler { + + @SubscribeEvent + public static void onCapPlayerAttach(final AttachCapabilitiesEvent event) { + if(!(event.getObject() instanceof ServerPlayerEntity)) + return; + + ServerPlayerEntity player = (ServerPlayerEntity) event.getObject(); + event.addCapability( + new ResourceLocation(CompactMachines.MOD_ID, "room_history"), + new PlayerRoomHistoryCapProvider(player)); + } +} diff --git a/src/main/java/dev/compactmods/machines/rooms/chunkloading/CMRoomChunkloadingManager.java b/src/main/java/dev/compactmods/machines/rooms/chunkloading/CMRoomChunkloadingManager.java new file mode 100644 index 00000000..70a845eb --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/chunkloading/CMRoomChunkloadingManager.java @@ -0,0 +1,153 @@ +package dev.compactmods.machines.rooms.chunkloading; + +import java.util.*; +import com.google.common.collect.ImmutableList; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.graph.CompactMachineConnectionGraph; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.world.ForgeChunkManager; + +public class CMRoomChunkloadingManager implements IRoomChunkloadingManager { + + private final MinecraftServer server; + private final Map tickets; + + // TODO - Finish and serialize data + // see ForcedChunksSaveData + + public CMRoomChunkloadingManager(MinecraftServer server) { + this.server = server; + this.tickets = new HashMap<>(); + } + + @Override + public boolean roomIsLoaded(ChunkPos room) { + return tickets.containsKey(room); + } + + @Override + public boolean hasAnyMachinesLoaded() { + return !tickets.isEmpty(); + } + + @Override + public void onMachineChunkUnload(int machine) { + final Optional attachedRoom = getConnectedRoom(machine); + attachedRoom.ifPresent(room -> { + final Collection machines = getConnectedMachines(room); + switch (machines.size()) { + case 0: + case 1: + // No siblings or this is the only machine connected - unload the room + setChunkForced(room, false); + break; + + default: + // More than one machine attached to the room + // Need to see if any other machine is still loaded before decision + final CompactMachineData machData = CompactMachineData.get(server); + if (machData == null) { + // ohshi- + return; + } + + // true if any connected machine is loaded; false otherwise + boolean anyRoomMachineLoaded = machines.stream() + .map(machData::getMachineLocation) + .anyMatch(machLocation -> machLocation.map(d -> d.isLoaded(server)).orElse(false)); + + if(!anyRoomMachineLoaded) { + setChunkForced(room, false); + } + break; + } + }); + } + + @Override + public void onMachineChunkLoad(int machine) { + final Optional attachedRoom = getConnectedRoom(machine); + attachedRoom.ifPresent(room -> { + // If there's already a ticket for the room, early exit - another machine has it loaded + if (tickets.containsKey(room)) + return; + + setChunkForced(room, true); + }); + } + + private Optional getGraph() { + final MachineConnections conns = MachineConnections.get(server); + if (conns == null) + return Optional.empty(); + + return Optional.of(conns.graph); + } + + private Optional getConnectedRoom(int machine) { + return getGraph().flatMap(graph -> graph.getConnectedRoom(machine)); + } + + + private Collection getConnectedMachines(ChunkPos room) { + return getGraph().map(graph -> graph.getMachinesFor(room)) + .map(connectedMachines -> { + switch (connectedMachines.size()) { + case 0: + case 1: + // release ticket + return Collections.emptySet(); + + default: + // scan connected machines, if at least one is loaded then do not release + return ImmutableList.copyOf(connectedMachines); + } + }).orElse(Collections.emptySet()); + } + + private Collection getRoomConnectedMachines(int machine) { + final CompactMachineConnectionGraph graph = getGraph().orElse(null); + if (graph == null) + return Collections.emptySet(); + + return getConnectedRoom(machine) + .map(this::getConnectedMachines) + .orElse(Collections.emptySet()); + } + + private void setChunkForced(ChunkPos room, boolean force) { + // If trying to force and room was not previously set up + if (force && !tickets.containsKey(room)) { + UUID newTicket = UUID.randomUUID(); + tickets.put(room, newTicket); + } + + UUID ticket = tickets.get(room); + + ServerWorld compact = server.getLevel(Registration.COMPACT_DIMENSION); + + if (compact != null) { + boolean alreadyForced = compact.getForcedChunks().stream() + .anyMatch(chunkLong -> chunkLong.equals(room.toLong())); + + // if force status requires change + if(alreadyForced != force) { + // prevent deadlock? + compact.getChunk(room.x, room.z); + + boolean changed = ForgeChunkManager.forceChunk(compact, CompactMachines.MOD_ID, + ticket, room.x, room.z, force, true); + + if (!force && changed) { + tickets.remove(room); + } + } + } + + } +} diff --git a/src/main/java/dev/compactmods/machines/rooms/chunkloading/IRoomChunkloadingManager.java b/src/main/java/dev/compactmods/machines/rooms/chunkloading/IRoomChunkloadingManager.java new file mode 100644 index 00000000..06d5241a --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/chunkloading/IRoomChunkloadingManager.java @@ -0,0 +1,15 @@ +package dev.compactmods.machines.rooms.chunkloading; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.ChunkPos; + +public interface IRoomChunkloadingManager { + + boolean roomIsLoaded(ChunkPos room); + + boolean hasAnyMachinesLoaded(); + + void onMachineChunkUnload(int machine); + + void onMachineChunkLoad(int machine); +} diff --git a/src/main/java/dev/compactmods/machines/rooms/history/IRoomHistoryItem.java b/src/main/java/dev/compactmods/machines/rooms/history/IRoomHistoryItem.java new file mode 100644 index 00000000..1b583cdc --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/history/IRoomHistoryItem.java @@ -0,0 +1,10 @@ +package dev.compactmods.machines.rooms.history; + +import dev.compactmods.machines.teleportation.DimensionalPosition; + +public interface IRoomHistoryItem { + + DimensionalPosition getEntryLocation(); + + int getMachine(); +} diff --git a/src/main/java/dev/compactmods/machines/rooms/history/PlayerRoomHistoryItem.java b/src/main/java/dev/compactmods/machines/rooms/history/PlayerRoomHistoryItem.java new file mode 100644 index 00000000..3248d716 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/rooms/history/PlayerRoomHistoryItem.java @@ -0,0 +1,31 @@ +package dev.compactmods.machines.rooms.history; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.teleportation.DimensionalPosition; + +public class PlayerRoomHistoryItem implements IRoomHistoryItem { + + private final DimensionalPosition entry; + private final int machine; + + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + DimensionalPosition.CODEC.fieldOf("position").forGetter(IRoomHistoryItem::getEntryLocation), + Codec.INT.fieldOf("machine").forGetter(IRoomHistoryItem::getMachine) + ).apply(i, PlayerRoomHistoryItem::new)); + + public PlayerRoomHistoryItem(DimensionalPosition entry, int machine) { + this.entry = entry; + this.machine = machine; + } + + @Override + public DimensionalPosition getEntryLocation() { + return entry; + } + + @Override + public int getMachine() { + return machine; + } +} diff --git a/src/main/java/dev/compactmods/machines/teleportation/DimensionalPosition.java b/src/main/java/dev/compactmods/machines/teleportation/DimensionalPosition.java new file mode 100644 index 00000000..0b159a1c --- /dev/null +++ b/src/main/java/dev/compactmods/machines/teleportation/DimensionalPosition.java @@ -0,0 +1,142 @@ +package dev.compactmods.machines.teleportation; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.data.codec.CodecExtensions; +import dev.compactmods.machines.util.LocationUtil; +import net.minecraft.entity.LivingEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.INBTSerializable; + +import javax.annotation.Nonnull; +import java.util.Objects; +import java.util.Optional; + +public class DimensionalPosition implements INBTSerializable, IDimensionalPosition { + + private RegistryKey dimension; + private Vector3d position; + private Vector3d rotation; + + /* + Note: We'd use the actual world registry key here, but it static loads the world and does a bunch + of initialization, making it impossible to unit test without booting a whole server up. + */ + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + CodecExtensions.WORLD_REGISTRY_KEY.fieldOf("dim").forGetter(DimensionalPosition::getDimension), + CodecExtensions.VECTOR3D.fieldOf("pos").forGetter(DimensionalPosition::getPosition), + CodecExtensions.VECTOR3D.optionalFieldOf("rot", Vector3d.ZERO).forGetter(DimensionalPosition::getRotation) + ).apply(i, DimensionalPosition::new)); + + private DimensionalPosition() { + } + + public DimensionalPosition(RegistryKey world, BlockPos positionBlock) { + this(world, Vector3d.ZERO, Vector3d.ZERO); + this.position = new Vector3d(positionBlock.getX(), positionBlock.getY(), positionBlock.getZ()); + } + + public DimensionalPosition(RegistryKey world, Vector3d positionBlock) { + this(world, positionBlock, Vector3d.ZERO); + this.dimension = world; + + this.rotation = Vector3d.ZERO; + } + + public DimensionalPosition(RegistryKey dim, Vector3d pos, Vector3d rotation) { + this.dimension = dim; + this.position = pos; + this.rotation = rotation; + } + + public static DimensionalPosition fromEntity(LivingEntity entity) { + return new DimensionalPosition(entity.level.dimension(), entity.position()); + } + + public Optional getWorld(@Nonnull MinecraftServer server) { + return Optional.ofNullable(server.getLevel(this.dimension)); + } + + public boolean isLoaded(MinecraftServer server) { + return getWorld(server) + .map(w -> w.isLoaded(LocationUtil.vectorToBlockPos(position))) + .orElse(false); + } + + public static DimensionalPosition fromNBT(CompoundNBT nbt) { + DimensionalPosition dp = new DimensionalPosition(); + dp.deserializeNBT(nbt); + + return dp; + } + + @Override + public CompoundNBT serializeNBT() { + DataResult nbt = CODEC.encodeStart(NBTDynamicOps.INSTANCE, this); + return (CompoundNBT) nbt.result().orElse(null); + } + + @Override + public void deserializeNBT(CompoundNBT nbt) { + Optional dimensionalPosition = CODEC + .parse(NBTDynamicOps.INSTANCE, nbt) + .resultOrPartial(CompactMachines.LOGGER::error); + + dimensionalPosition.ifPresent(dp -> { + this.dimension = dp.dimension; + this.position = dp.position; + this.rotation = dp.rotation; + }); + } + + public RegistryKey getDimension() { + return this.dimension; + } + + public Vector3d getPosition() { + return this.position; + } + + public Vector3d getRotation() { + return this.rotation; + } + + public BlockPos getBlockPosition() { + return new BlockPos(position.x, position.y, position.z); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DimensionalPosition that = (DimensionalPosition) o; + return Objects.equals(dimension, that.dimension) && + Objects.equals(position, that.position) && + Objects.equals(rotation, rotation); + } + + @Override + public int hashCode() { + return Objects.hash(dimension, position, rotation); + } + + @Override + public String toString() { + return "DimensionalPosition{" + + "d=" + dimension + + ", p=" + position + + ", r=" + rotation + + '}'; + } +} diff --git a/src/main/java/dev/compactmods/machines/teleportation/TeleportationEventHandler.java b/src/main/java/dev/compactmods/machines/teleportation/TeleportationEventHandler.java new file mode 100644 index 00000000..74d91672 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/teleportation/TeleportationEventHandler.java @@ -0,0 +1,85 @@ +package dev.compactmods.machines.teleportation; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.core.Messages; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.persistent.CompactRoomData; +import dev.compactmods.machines.util.TranslationUtil; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.event.entity.EntityEvent; +import net.minecraftforge.event.entity.living.EnderTeleportEvent; +import net.minecraftforge.event.entity.living.EntityTeleportEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod.EventBusSubscriber(modid = CompactMachines.MOD_ID) +public class TeleportationEventHandler { + + @SubscribeEvent + public static void onEnderTeleport(final EnderTeleportEvent evt) { + Vector3d target = new Vector3d( + evt.getTargetX(), + evt.getTargetY(), + evt.getTargetZ() + ); + + Entity ent = evt.getEntity(); + doEntityTeleportHandle(evt, target, ent); + } + + @SubscribeEvent + public static void onEntityTeleport(final EntityTeleportEvent evt) { + // Allow teleport commands, we don't want to trap people anywhere + if (evt instanceof EntityTeleportEvent.TeleportCommand) + return; + + Entity ent = evt.getEntity(); + doEntityTeleportHandle(evt, evt.getTarget(), ent); + } + + + /** + * Helper to determine if an event should be canceled, by determining if a target is outside + * a machine's bounds. + * + * @param entity Entity trying to teleport. + * @param target Teleportation target location. + * @return True if teleportation should be cancelled; false otherwise. + */ + private static boolean cancelOutOfBoxTeleport(Entity entity, Vector3d target) { + MinecraftServer serv = entity.getServer(); + if (serv == null) + return false; + + ChunkPos machineChunk = new ChunkPos(entity.xChunk, entity.zChunk); + + CompactRoomData intern = CompactRoomData.get(serv); + if (intern == null) + return false; + + return intern.getInnerBounds(machineChunk) + .map(bounds -> !bounds.contains(target)) + .orElse(false); + } + + private static void doEntityTeleportHandle(EntityEvent evt, Vector3d target, Entity ent) { + if (ent.level.dimension() == Registration.COMPACT_DIMENSION) { + if (cancelOutOfBoxTeleport(ent, target) && evt.isCancelable()) { + if (ent instanceof ServerPlayerEntity) { + ((ServerPlayerEntity) ent).displayClientMessage( + TranslationUtil.message(Messages.TELEPORT_OUT_OF_BOUNDS, ent.getName()) + .withStyle(TextFormatting.RED) + .withStyle(TextFormatting.ITALIC), + true + ); + } + evt.setCanceled(true); + } + } + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelConnectionInfo.java b/src/main/java/dev/compactmods/machines/tunnels/TunnelConnectionInfo.java similarity index 63% rename from src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelConnectionInfo.java rename to src/main/java/dev/compactmods/machines/tunnels/TunnelConnectionInfo.java index f4706b68..dbc25376 100644 --- a/src/main/java/com/robotgryphon/compactmachines/tunnels/TunnelConnectionInfo.java +++ b/src/main/java/dev/compactmods/machines/tunnels/TunnelConnectionInfo.java @@ -1,10 +1,13 @@ -package com.robotgryphon.compactmachines.tunnels; +package dev.compactmods.machines.tunnels; -import com.robotgryphon.compactmachines.api.tunnels.EnumTunnelSide; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.teleportation.DimensionalPosition; import net.minecraft.block.BlockState; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.Direction; import net.minecraft.world.IWorldReader; @@ -13,7 +16,7 @@ public class TunnelConnectionInfo implements ITunnelConnectionInfo { - private TunnelWallTile tunnel; + private final TunnelWallTile tunnel; TunnelConnectionInfo(TunnelWallTile tile) { this.tunnel = tile; @@ -21,7 +24,7 @@ public class TunnelConnectionInfo implements ITunnelConnectionInfo { @Nonnull @Override - public Optional getConnectedPosition(EnumTunnelSide side) { + public Optional getConnectedPosition(EnumTunnelSide side) { return TunnelHelper.getTunnelConnectedPosition(tunnel, side); } @@ -32,12 +35,16 @@ public Optional getConnectedState(EnumTunnelSide side) { @Override public Optional getConnectedWorld(EnumTunnelSide side) { + ServerPlayerEntity sp; switch(side) { case INSIDE: return Optional.ofNullable(tunnel.getLevel()); case OUTSIDE: - return tunnel.getConnectedWorld(); + return tunnel.getConnectedPosition().map(p -> { + MinecraftServer serv = tunnel.getLevel().getServer(); + return p.getWorld(serv).orElse(null); + }); } return Optional.empty(); diff --git a/src/main/java/dev/compactmods/machines/tunnels/TunnelHelper.java b/src/main/java/dev/compactmods/machines/tunnels/TunnelHelper.java new file mode 100644 index 00000000..ba39132b --- /dev/null +++ b/src/main/java/dev/compactmods/machines/tunnels/TunnelHelper.java @@ -0,0 +1,184 @@ +package dev.compactmods.machines.tunnels; + +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.block.walls.TunnelWallBlock; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.CompactRoomData; +import dev.compactmods.machines.data.persistent.MachineConnections; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.fml.RegistryObject; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TunnelHelper { + + public static ITunnelConnectionInfo generateConnectionInfo(TunnelWallTile tunnelTile) { + return new TunnelConnectionInfo(tunnelTile); + } + + public static ITunnelConnectionInfo generateConnectionInfo(@Nonnull IBlockReader tunnelWorld, @Nonnull BlockPos tunnelPos) { + TunnelWallTile tile = (TunnelWallTile) tunnelWorld.getBlockEntity(tunnelPos); + return generateConnectionInfo(tile); + } + + @Nonnull + public static Direction getNextDirection(Direction in) { + switch (in) { + case UP: + return Direction.DOWN; + + case DOWN: + return Direction.NORTH; + + case NORTH: + return Direction.SOUTH; + + case SOUTH: + return Direction.WEST; + + case WEST: + return Direction.EAST; + + case EAST: + return Direction.UP; + } + + return Direction.UP; + } + + @Nonnull + public static Optional getTunnelDefinitionFromType(ResourceLocation id) { + Optional> first = Registration.TUNNEL_DEFINITIONS.getEntries() + .stream() + .filter(t -> t.get().getRegistryName() == id) + .findFirst(); + + return first.map(RegistryObject::get); + + } + + public static Set getTunnelsForMachineSide(int machine, ServerWorld world, Direction machineSide) { + + ServerWorld compactWorld = world.getServer().getLevel(Registration.COMPACT_DIMENSION); + if (compactWorld == null) + return Collections.emptySet(); + + final MachineConnections machines = MachineConnections.get(world.getServer()); + final CompactRoomData rooms = CompactRoomData.get(world.getServer()); + if (machines == null || rooms == null) + return Collections.emptySet(); + + // TODO - Reimplement with capability - this is wasteful + return machines.graph.getConnectedRoom(machine).map(roomChunk -> { + return rooms.getInnerBounds(roomChunk) + .map(b -> b.inflate(1)) + .map(BlockPos::betweenClosedStream).orElse(Stream.empty()) + .filter(pos -> { + BlockState state = compactWorld.getBlockState(pos); + return state.getBlock() instanceof TunnelWallBlock; + }) + .map(BlockPos::immutable) + .collect(Collectors.toSet()); + }).orElse(Collections.emptySet()); + +// CompactMachineServerData data = SavedMachineData.getInstance(world.getServer()).getData(); +// +// Optional mData = data.getMachineData(machine); +// mData.ifPresent(machineData -> { +// BlockPos machineCenter = machineData.getCenter(); +// int internalSize = machineData.getSize().getInternalSize(); +// +// AxisAlignedBB allBlocksInMachine = new AxisAlignedBB(machineCenter, machineCenter) +// .inflate(internalSize); +// +// Set tunnelPositionsUnfiltered = BlockPos.betweenClosedStream(allBlocksInMachine) +// .filter(pos -> !compactWorld.isEmptyBlock(pos)) +// // .filter(pos -> world.getBlockState(pos).getBlock() instanceof TunnelWallBlock) +// .map(BlockPos::immutable) +// .collect(Collectors.toSet()); +// +// if(!tunnelPositionsUnfiltered.isEmpty()) { +// Set tunnelPositionsFiltered = tunnelPositionsUnfiltered +// .stream() +// .filter(pos -> { +// BlockState state = compactWorld.getBlockState(pos); +// +// boolean tunnel = state.getBlock() instanceof TunnelWallBlock; +// if(!tunnel) +// return false; +// +// Direction externalSide = state.getValue(TunnelWallBlock.CONNECTED_SIDE); +// return externalSide == machineSide; +// }) +// .map(BlockPos::immutable) +// .collect(Collectors.toSet()); +// +// tunnelPositions.addAll(tunnelPositionsFiltered); +// } +// }); + } + + @Nonnull + public static Optional getTunnelConnectedPosition(TunnelWallTile tunnel, EnumTunnelSide side) { + switch (side) { + case OUTSIDE: + return tunnel.getConnectedPosition(); + + case INSIDE: + RegistryKey world = Registration.COMPACT_DIMENSION; + BlockPos offsetInside = tunnel.getBlockPos().relative(tunnel.getTunnelSide()); + + DimensionalPosition pos = new DimensionalPosition(world, offsetInside); + return Optional.of(pos); + } + + return Optional.empty(); + } + + @Nonnull + public static Optional getConnectedState(TunnelWallTile twt, EnumTunnelSide side) { + IDimensionalPosition connectedPosition = getTunnelConnectedPosition(twt, side).orElse(null); + if (connectedPosition == null) + return Optional.empty(); + + // We need a server world to reach across dimensions to get information + if (twt.getLevel() instanceof ServerWorld) { + ServerWorld sw = (ServerWorld) twt.getLevel(); + + Optional connectedWorld = connectedPosition.getWorld(sw.getServer()); + if (!connectedWorld.isPresent()) + return Optional.empty(); + + ServerWorld csw = connectedWorld.get(); + BlockPos connectedPos = connectedPosition.getBlockPosition(); + + BlockState state = csw.getBlockState(connectedPos); + return Optional.of(state); + } + + return Optional.empty(); + } + + +} diff --git a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/ItemTunnelDefinition.java b/src/main/java/dev/compactmods/machines/tunnels/definitions/ItemTunnelDefinition.java similarity index 55% rename from src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/ItemTunnelDefinition.java rename to src/main/java/dev/compactmods/machines/tunnels/definitions/ItemTunnelDefinition.java index 28621867..76be90aa 100644 --- a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/ItemTunnelDefinition.java +++ b/src/main/java/dev/compactmods/machines/tunnels/definitions/ItemTunnelDefinition.java @@ -1,11 +1,12 @@ -package com.robotgryphon.compactmachines.tunnels.definitions; - -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import com.robotgryphon.compactmachines.api.tunnels.EnumTunnelSide; -import com.robotgryphon.compactmachines.tunnels.TunnelHelper; -import com.robotgryphon.compactmachines.api.tunnels.IItemTunnel; +package dev.compactmods.machines.tunnels.definitions; + +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.block.tiles.TunnelWallTile; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.tunnels.TunnelHelper; +import dev.compactmods.machines.api.tunnels.IItemTunnel; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; @@ -14,13 +15,15 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.registries.IForgeRegistryEntry; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.*; -import java.util.Optional; +import java.util.*; -public class ItemTunnelDefinition extends TunnelDefinition implements IItemTunnel { +public class ItemTunnelDefinition extends TunnelDefinition implements IItemTunnel, IForgeRegistryEntry { @Override public int getTunnelRingColor() { @@ -41,13 +44,13 @@ public LazyOptional getInternalCapability(ServerWorld compactWorld, Block if (!connectedState.isPresent()) return LazyOptional.empty(); - Optional tunnelConnectedPosition = TunnelHelper.getTunnelConnectedPosition(twt, EnumTunnelSide.INSIDE); + Optional tunnelConnectedPosition = TunnelHelper.getTunnelConnectedPosition(twt, EnumTunnelSide.INSIDE); if (!tunnelConnectedPosition.isPresent()) return LazyOptional.empty(); Direction tunnelSide = twt.getTunnelSide(); - DimensionalPosition connectedInsidePos = tunnelConnectedPosition.get(); + IDimensionalPosition connectedInsidePos = tunnelConnectedPosition.get(); if (connectedState.get().hasTileEntity()) { TileEntity connectedTile = compactWorld.getBlockEntity(connectedInsidePos.getBlockPosition()); if (connectedTile != null) { @@ -75,11 +78,11 @@ public LazyOptional getExternalCapability(ServerWorld world, BlockPos tun return LazyOptional.empty(); // link to external block capability - Optional connectedPosition = twt.getConnectedPosition(); + Optional connectedPosition = twt.getConnectedPosition(); if (!connectedPosition.isPresent()) return LazyOptional.empty(); - DimensionalPosition dimensionalPosition = connectedPosition.get(); + IDimensionalPosition dimensionalPosition = connectedPosition.get(); // CompactMachines.LOGGER.debug(String.format("[%s] %s %s", 0, dimensionalPosition.getDimension(), dimensionalPosition.getPosition())); Optional connectedWorld = dimensionalPosition.getWorld(world.getServer()); @@ -101,5 +104,35 @@ public LazyOptional getExternalCapability(ServerWorld world, BlockPos tun return LazyOptional.empty(); } - + @Override + public Map, LazyOptional> rebuildCapabilityCache(ServerWorld compactLevel, BlockPos tunnelPos, BlockPos inside, @Nullable IDimensionalPosition external) { + HashMap, LazyOptional> set = new HashMap<>(); + + BlockState innerState = compactLevel.getBlockState(inside); + if(!innerState.hasTileEntity()) + return Collections.emptyMap(); + + TileEntity innerTile = compactLevel.getBlockEntity(inside); + final LazyOptional items = innerTile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + if(items.isPresent()) + set.put(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, items); + +// final Optional connectedLevel = external.getWorld(compactLevel.getServer()); +// connectedLevel.ifPresent(externLevel -> { +// final BlockPos externPos = external.getBlockPosition(); +// if (externLevel.isLoaded(externPos)) { +// BlockState connectedState = externLevel.getBlockState(externPos); +// if(connectedState.hasTileEntity()) { +// TileEntity connectedTile = externLevel.getBlockEntity(externPos); +// final LazyOptional items = connectedTile.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); +// set.put(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, items); +// } +// } else { +// // other world not loaded - we need to defer this somehow TODO +// CompactMachines.LOGGER.debug("not loaded"); +// } +// }); + + return set; + } } diff --git a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneInTunnelDefinition.java b/src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneInTunnelDefinition.java similarity index 56% rename from src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneInTunnelDefinition.java rename to src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneInTunnelDefinition.java index 57f9b67e..bb0f5b22 100644 --- a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneInTunnelDefinition.java +++ b/src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneInTunnelDefinition.java @@ -1,19 +1,12 @@ -package com.robotgryphon.compactmachines.tunnels.definitions; - -import com.robotgryphon.compactmachines.CompactMachines; -import com.robotgryphon.compactmachines.api.tunnels.EnumTunnelSide; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.block.tiles.TunnelWallTile; -import com.robotgryphon.compactmachines.data.machines.CompactMachineRegistrationData; -import com.robotgryphon.compactmachines.teleportation.DimensionalPosition; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneReaderTunnel; +package dev.compactmods.machines.tunnels.definitions; + +import dev.compactmods.machines.api.teleportation.IDimensionalPosition; +import dev.compactmods.machines.api.tunnels.EnumTunnelSide; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.api.tunnels.redstone.IRedstoneReaderTunnel; import net.minecraft.block.BlockState; -import net.minecraft.server.MinecraftServer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; import net.minecraft.world.server.ServerWorld; @@ -37,7 +30,7 @@ public int getTunnelIndicatorColor() { public int getPowerLevel(ITunnelConnectionInfo connectionInfo) { IWorldReader connectedWorld = connectionInfo.getConnectedWorld(EnumTunnelSide.OUTSIDE).orElse(null); if (connectedWorld instanceof ServerWorld) { - DimensionalPosition pos = connectionInfo.getConnectedPosition(EnumTunnelSide.OUTSIDE).orElse(null); + IDimensionalPosition pos = connectionInfo.getConnectedPosition(EnumTunnelSide.OUTSIDE).orElse(null); if (pos == null) return 0; diff --git a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneOutTunnelDefinition.java b/src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneOutTunnelDefinition.java similarity index 60% rename from src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneOutTunnelDefinition.java rename to src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneOutTunnelDefinition.java index ea553e96..fd3ec649 100644 --- a/src/main/java/com/robotgryphon/compactmachines/tunnels/definitions/RedstoneOutTunnelDefinition.java +++ b/src/main/java/dev/compactmods/machines/tunnels/definitions/RedstoneOutTunnelDefinition.java @@ -1,8 +1,8 @@ -package com.robotgryphon.compactmachines.tunnels.definitions; +package dev.compactmods.machines.tunnels.definitions; -import com.robotgryphon.compactmachines.api.tunnels.ITunnelConnectionInfo; -import com.robotgryphon.compactmachines.api.tunnels.TunnelDefinition; -import com.robotgryphon.compactmachines.api.tunnels.redstone.IRedstoneWriterTunnel; +import dev.compactmods.machines.api.tunnels.ITunnelConnectionInfo; +import dev.compactmods.machines.api.tunnels.TunnelDefinition; +import dev.compactmods.machines.api.tunnels.redstone.IRedstoneWriterTunnel; import java.awt.Color; diff --git a/src/main/java/com/robotgryphon/compactmachines/util/CompactStructureGenerator.java b/src/main/java/dev/compactmods/machines/util/CompactStructureGenerator.java similarity index 93% rename from src/main/java/com/robotgryphon/compactmachines/util/CompactStructureGenerator.java rename to src/main/java/dev/compactmods/machines/util/CompactStructureGenerator.java index 74e55aa7..d4485c12 100644 --- a/src/main/java/com/robotgryphon/compactmachines/util/CompactStructureGenerator.java +++ b/src/main/java/dev/compactmods/machines/util/CompactStructureGenerator.java @@ -1,7 +1,7 @@ -package com.robotgryphon.compactmachines.util; +package dev.compactmods.machines.util; -import com.robotgryphon.compactmachines.core.Registration; -import com.robotgryphon.compactmachines.reference.EnumMachineSize; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.reference.EnumMachineSize; import net.minecraft.block.BlockState; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; diff --git a/src/main/java/dev/compactmods/machines/util/LocationUtil.java b/src/main/java/dev/compactmods/machines/util/LocationUtil.java new file mode 100644 index 00000000..ebefe0ec --- /dev/null +++ b/src/main/java/dev/compactmods/machines/util/LocationUtil.java @@ -0,0 +1,19 @@ +package dev.compactmods.machines.util; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class LocationUtil { + + public static Vector3d blockPosToVector(BlockPos pos) { + return new Vector3d( + pos.getX() + 0.5f, + pos.getY(), + pos.getZ() + 0.5f + ); + } + + public static BlockPos vectorToBlockPos(Vector3d position) { + return new BlockPos(position.x, position.y, position.z); + } +} diff --git a/src/main/java/com/robotgryphon/compactmachines/util/MathUtil.java b/src/main/java/dev/compactmods/machines/util/MathUtil.java similarity index 52% rename from src/main/java/com/robotgryphon/compactmachines/util/MathUtil.java rename to src/main/java/dev/compactmods/machines/util/MathUtil.java index 1aeb8fe2..68cbc461 100644 --- a/src/main/java/com/robotgryphon/compactmachines/util/MathUtil.java +++ b/src/main/java/dev/compactmods/machines/util/MathUtil.java @@ -1,9 +1,17 @@ -package com.robotgryphon.compactmachines.util; +package dev.compactmods.machines.util; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.vector.Vector3i; public class MathUtil { + /** + * + * @param i + * @return + */ public static Vector3i getRegionPositionByIndex(int i) { + // From SO, https://stackoverflow.com/a/41141648 int index = i + 1; // wth int s = (int) Math.ceil(Math.sqrt(index)) + (int) ((Math.ceil(Math.sqrt(index)) % 2 + 1) % 2); @@ -14,7 +22,7 @@ public static Vector3i getRegionPositionByIndex(int i) { p = s * s - (s - 2) * (s - 2); } - int ri = (ringIndex + (int) (s / 2)) % p; + int ri = (ringIndex + (s / 2)) % p; int x = 0; if (s > 1) { @@ -35,9 +43,28 @@ public static Vector3i getRegionPositionByIndex(int i) { (ri <= (p / 4 * 3) ? (p / 4) : (p - ri))); - x -= (int) (s / 2); - y -= (int) (s / 2); + x -= s / 2; + y -= s / 2; return new Vector3i(x, 0, y); } + + public static BlockPos getCenterWithY(ChunkPos chunk, int y) { + return chunk.getWorldPosition() + .offset(new BlockPos(8, y, 8)); + } + + public static BlockPos getCenterWithY(Vector3i regionIndex, int y) { + ChunkPos chunk = new ChunkPos( + regionIndex.getX() * 64, + regionIndex.getZ() * 64); + + return getCenterWithY(chunk, y); + } + + public static ChunkPos getChunkForRoomIndex(int roomIndex) { + Vector3i region = getRegionPositionByIndex(roomIndex); + BlockPos roomCenter = getCenterWithY(region, 0); + return new ChunkPos(roomCenter); + } } diff --git a/src/main/java/dev/compactmods/machines/util/PlayerUtil.java b/src/main/java/dev/compactmods/machines/util/PlayerUtil.java new file mode 100644 index 00000000..e871583e --- /dev/null +++ b/src/main/java/dev/compactmods/machines/util/PlayerUtil.java @@ -0,0 +1,243 @@ +package dev.compactmods.machines.util; + +import com.mojang.authlib.GameProfile; +import dev.compactmods.machines.CompactMachines; +import dev.compactmods.machines.advancement.AdvancementTriggers; +import dev.compactmods.machines.api.core.Messages; +import dev.compactmods.machines.block.tiles.CompactMachineTile; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.core.Registration; +import dev.compactmods.machines.data.persistent.MachineConnections; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.data.persistent.CompactRoomData; +import dev.compactmods.machines.network.CMPacketTargets; +import dev.compactmods.machines.network.MachinePlayersChangedPacket; +import dev.compactmods.machines.network.NetworkHandler; +import dev.compactmods.machines.reference.EnumMachineSize; +import dev.compactmods.machines.rooms.history.IRoomHistoryItem; +import dev.compactmods.machines.rooms.capability.CapabilityRoomHistory; +import dev.compactmods.machines.rooms.capability.IRoomHistory; +import dev.compactmods.machines.rooms.history.PlayerRoomHistoryItem; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3i; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nonnull; +import javax.naming.OperationNotSupportedException; +import java.util.Optional; +import java.util.UUID; + +public abstract class PlayerUtil { + public static Optional getProfileByUUID(IWorld world, UUID uuid) { + PlayerEntity player = world.getPlayerByUUID(uuid); + if (player == null) + return Optional.empty(); + + GameProfile profile = player.getGameProfile(); + return Optional.of(profile); + } + + public static DimensionalPosition getPlayerDimensionalPosition(PlayerEntity player) { + Vector3d pos = player.position(); + RegistryKey dim = player.level.dimension(); + + return new DimensionalPosition(dim, pos); + } + + public static void teleportPlayerIntoMachine(ServerPlayerEntity serverPlayer, BlockPos machinePos, EnumMachineSize size) { + ServerWorld serverWorld = serverPlayer.getLevel(); + + MinecraftServer serv = serverWorld.getServer(); + + ServerWorld compactWorld = serv.getLevel(Registration.COMPACT_DIMENSION); + if (compactWorld == null) { + CompactMachines.LOGGER.warn("Compact dimension not found; player attempted to enter machine."); + return; + } + + CompactMachineTile tile = (CompactMachineTile) serverWorld.getBlockEntity(machinePos); + if (tile == null) + return; + + final boolean grantAdvancement = !tile.mapped(); + if (!tile.mapped()) { + CompactMachineData machines = CompactMachineData.get(serv); + CompactRoomData rooms = CompactRoomData.get(serv); + MachineConnections connections = MachineConnections.get(serv); + + if (machines == null || rooms == null || connections == null) { + CompactMachines.LOGGER.error("Could not load world saved data while creating new machine and room."); + return; + } + + int nextId = rooms.getNextId(); + Vector3i location = MathUtil.getRegionPositionByIndex(nextId); + + int centerY = ServerConfig.MACHINE_FLOOR_Y.get() + (size.getInternalSize() / 2); + BlockPos newCenter = MathUtil.getCenterWithY(location, centerY); + + // Generate a new machine inside and update the tile + CompactStructureGenerator.generateCompactStructure(compactWorld, size, newCenter); + + ChunkPos machineChunk = new ChunkPos(newCenter); + tile.setMachineId(nextId); + + connections.graph.addMachine(nextId); + connections.graph.addRoom(machineChunk); + connections.graph.connectMachineToRoom(nextId, machineChunk); + connections.setDirty(); + + machines.setMachineLocation(nextId, new DimensionalPosition(serverWorld.dimension(), machinePos)); + + try { + rooms.createNew() + .owner(serverPlayer.getUUID()) + .size(size) + .chunk(machineChunk) + .register(); + } catch (OperationNotSupportedException e) { + CompactMachines.LOGGER.warn(e); + } + } + + serv.submitAsync(() -> { + DimensionalPosition spawn = tile.getSpawn().orElse(null); + if (spawn == null) { + CompactMachines.LOGGER.error("Machine " + tile.machineId + " could not load spawn info."); + return; + } + + try { + // Mark the player as inside the machine, set external spawn, and yeet + addPlayerToMachine(serverPlayer, machinePos); + } catch (Exception ex) { + CompactMachines.LOGGER.error(ex); + } + + Vector3d sp = spawn.getPosition(); + Vector3d sr = spawn.getRotation() != Vector3d.ZERO ? + spawn.getRotation() : new Vector3d(serverPlayer.xRot, serverPlayer.yRot, 0); + + serverPlayer.teleportTo( + compactWorld, + sp.x, + sp.y, + sp.z, + (float) sr.y, + (float) sr.x); + + if(grantAdvancement) + AdvancementTriggers.getTriggerForMachineClaim(size).trigger(serverPlayer); + }); + } + + public static void teleportPlayerOutOfMachine(ServerWorld world, @Nonnull ServerPlayerEntity serverPlayer) { + + MinecraftServer serv = world.getServer(); + + final LazyOptional history = serverPlayer.getCapability(CapabilityRoomHistory.HISTORY_CAPABILITY); + + if (!history.isPresent()) { + howDidYouGetThere(serverPlayer); + return; + } + + history.ifPresent(hist -> { + ChunkPos currentRoomChunk = new ChunkPos(serverPlayer.blockPosition()); + + if(hist.hasHistory()) { + final IRoomHistoryItem prevArea = hist.pop(); + + DimensionalPosition spawnPoint = prevArea.getEntryLocation(); + + ServerWorld w = spawnPoint.getWorld(serv).orElse(serv.overworld()); + Vector3d worldPos, entryRot; + + if (serv.getLevel(spawnPoint.getDimension()) != null) { + worldPos = spawnPoint.getPosition(); + entryRot = spawnPoint.getRotation(); + + serverPlayer.teleportTo(w, worldPos.x(), worldPos.y(), worldPos.z(), (float) entryRot.y, (float) entryRot.x); + } else { + hist.clear(); + teleportPlayerToRespawnOrOverworld(serv, serverPlayer); + } + } else { + howDidYouGetThere(serverPlayer); + + hist.clear(); + teleportPlayerToRespawnOrOverworld(serv, serverPlayer); + } + + final Chunk chunk = serv.getLevel(Registration.COMPACT_DIMENSION) + .getChunk(currentRoomChunk.x, currentRoomChunk.z); + + MachinePlayersChangedPacket p = MachinePlayersChangedPacket.Builder.create(serv) + .forMachine(currentRoomChunk) + .forPlayer(serverPlayer) + .build(); + + NetworkHandler.MAIN_CHANNEL.send(CMPacketTargets.TRACKING_ROOM.with(() -> chunk), p); + }); + } + + private static void howDidYouGetThere(@Nonnull ServerPlayerEntity serverPlayer) { + AdvancementTriggers.HOW_DID_YOU_GET_HERE.trigger(serverPlayer); + + serverPlayer.displayClientMessage( + TranslationUtil.message(Messages.HOW_DID_YOU_GET_HERE), + true + ); + } + + public static void teleportPlayerToRespawnOrOverworld(MinecraftServer serv, @Nonnull ServerPlayerEntity player) { + ServerWorld level = Optional.ofNullable(serv.getLevel(player.getRespawnDimension())).orElse(serv.overworld()); + Vector3d worldPos = LocationUtil.blockPosToVector(level.getSharedSpawnPos()); + + if (player.getRespawnPosition() != null) + worldPos = LocationUtil.blockPosToVector(player.getRespawnPosition()); + + player.teleportTo(level, worldPos.x(), worldPos.y(), worldPos.z(), 0, player.getRespawnAngle()); + } + + public static void addPlayerToMachine(ServerPlayerEntity serverPlayer, BlockPos machinePos) { + MinecraftServer serv = serverPlayer.getServer(); + if (serv == null) + return; + + CompactMachineTile tile = (CompactMachineTile) serverPlayer.getLevel().getBlockEntity(machinePos); + if (tile == null) + return; + + tile.getInternalChunkPos().ifPresent(mChunk -> { + final Chunk chunk = serv.getLevel(Registration.COMPACT_DIMENSION) + .getChunk(mChunk.x, mChunk.z); + + serverPlayer.getCapability(CapabilityRoomHistory.HISTORY_CAPABILITY) + .ifPresent(hist -> { + DimensionalPosition pos = DimensionalPosition.fromEntity(serverPlayer); + hist.addHistory(new PlayerRoomHistoryItem(pos, tile.machineId)); + }); + + MachinePlayersChangedPacket p = MachinePlayersChangedPacket.Builder.create(serv) + .forMachine(mChunk) + .forPlayer(serverPlayer) + .enteredFrom(tile.machineId) + .build(); + + NetworkHandler.MAIN_CHANNEL.send(CMPacketTargets.TRACKING_ROOM.with(() -> chunk), p); + }); + } + +} diff --git a/src/main/java/dev/compactmods/machines/util/TranslationUtil.java b/src/main/java/dev/compactmods/machines/util/TranslationUtil.java new file mode 100644 index 00000000..68a02ad3 --- /dev/null +++ b/src/main/java/dev/compactmods/machines/util/TranslationUtil.java @@ -0,0 +1,52 @@ +package dev.compactmods.machines.util; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Util; +import net.minecraft.util.text.TranslationTextComponent; + +public abstract class TranslationUtil { + + public static String messageId(ResourceLocation message) { + return Util.makeDescriptionId("message", message); + } + + public static TranslationTextComponent message(ResourceLocation message) { + return new TranslationTextComponent(messageId(message)); + } + + public static TranslationTextComponent message(ResourceLocation message, Object... params) { + return new TranslationTextComponent(messageId(message), params); + } + + public static String tooltipId(ResourceLocation tooltip) { + return Util.makeDescriptionId("tooltip", tooltip); + } + + public static TranslationTextComponent tooltip(ResourceLocation tooltip) { + return new TranslationTextComponent(tooltipId(tooltip)); + } + + public static TranslationTextComponent tooltip(ResourceLocation tooltip, Object... params) { + return new TranslationTextComponent(tooltipId(tooltip), params); + } + + public static String advId(ResourceLocation tooltip) { + return Util.makeDescriptionId("advancement", tooltip); + } + + public static TranslationTextComponent advancement(ResourceLocation advancement) { + return new TranslationTextComponent(advId(advancement)); + } + + public static TranslationTextComponent advancementTitle(ResourceLocation advancement) { + return advancement(advancement); + } + + public static TranslationTextComponent advancementDesc(ResourceLocation advancement) { + return new TranslationTextComponent(Util.makeDescriptionId("advancement", advancement) + ".desc"); + } + + public static TranslationTextComponent jeiInfo(ResourceLocation jei) { + return new TranslationTextComponent(Util.makeDescriptionId("jei", jei)); + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 00000000..ae083745 --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1 @@ +public net.minecraft.world.biome.BiomeContainer field_227054_f_ # biomes \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 9e258970..ef5bd5e3 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -6,7 +6,7 @@ # 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="[35,)" #mandatory This is typically bumped every Minecraft version by Forge. See our download page for lists of versions. +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" @@ -40,7 +40,7 @@ license="All rights reserved" # Does this dependency have to exist - if not, ordering below must be specified mandatory=true #mandatory # The version range of the dependency - versionRange="[35,)" #mandatory + versionRange="[36.1.4,)" #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 @@ -50,6 +50,6 @@ license="All rights reserved" [[dependencies.compactmachines]] modId="minecraft" mandatory=true - versionRange="[1.16.4,1.17)" + versionRange="[1.16.5,1.17)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/assets/compactmachines/lang/en_us.json b/src/main/resources/assets/compactmachines/lang/en_us.json index 44855a15..b5b0bb78 100644 --- a/src/main/resources/assets/compactmachines/lang/en_us.json +++ b/src/main/resources/assets/compactmachines/lang/en_us.json @@ -1,19 +1,20 @@ { "itemGroup.compactmachines": "Compact Machines", - - "tooltip.compactmachines.machine_id": "Machine ID: %s", - "tooltip.compactmachines.owner": "Owner: %s", + "tooltip.compactmachines.machine.id": "Machine ID: %s", + "tooltip.compactmachines.machine.owner": "Owner: %s", + "tooltip.compactmachines.machine.size": "Internal Size: %1$sx%1$sx%1$s", "tooltip.compactmachines.unknown_player": "Unknown Player", - "tooltip.compactmachines.machine.size": "Size: %1$sx%1$sx%1$s", - "tooltip.compactmachines.hold_shift.hint": "Hold shift for details.", - "tooltip.compactmachines.psd.hint": "Used as in-game documentation and to enter Compact Machines.", - "tooltip.compactmachines.solid_wall.hint": "Warning! Unbreakable for non-creative players!", - "tooltip.compactmachines.machine.hint": "A %1$s provides a %2$s room.", "tooltip.compactmachines.tunnel_type": "Type ID: %1$s", - - "messages.compactmachines.psd.spawnpoint_set": "New spawn point set.", - "messages.compactmachines.no_machine_data": "No machine data loaded; report this.", - + "tooltip.compactmachines.hint.hold_shift": "Hold shift for details.", + "tooltip.compactmachines.details.psd": "Used as in-game documentation and to enter Compact Machines.", + "tooltip.compactmachines.details.solid_wall": "Warning! Unbreakable for non-creative players!", + "message.compactmachines.new_machine": "New Machine", + "message.compactmachines.cannot_enter": "You fumble with the shrinking device, to no avail. It refuses to work.", + "message.compactmachines.spawnpoint_set": "New spawn point set.", + "message.compactmachines.no_machine_data": "No machine data loaded; report this.", + "message.compactmachines.teleport_oob": "An otherworldly force prevents your teleportation.", + "message.compactmachines.fixbiome_bad_dim": "Cannot use fixbiome command outside of a machine room.", + "message.compactmachines.tunnels_nyi": "Tunnels will be implemented in 1.17.", "block.compactmachines.machine": "Compact Machine", "block.compactmachines.machine_tiny": "Compact Machine (Tiny)", "block.compactmachines.machine_small": "Compact Machine (Small)", @@ -21,26 +22,19 @@ "block.compactmachines.machine_large": "Compact Machine (Large)", "block.compactmachines.machine_giant": "Compact Machine (Giant)", "block.compactmachines.machine_maximum": "Compact Machine (Maximum)", - "block.compactmachines.solid_wall": "Solid Compact Machine Wall", "block.compactmachines.wall": "Compact Machine Wall", "block.compactmachines.tunnel_wall": "Solid Compact Machine Wall (with Tunnel)", - "item.compactmachines.machine_tiny": "Compact Machine (Tiny)", "item.compactmachines.machine_small": "Compact Machine (Small)", "item.compactmachines.machine_normal": "Compact Machine (Normal)", "item.compactmachines.machine_large": "Compact Machine (Large)", "item.compactmachines.machine_giant": "Compact Machine (Giant)", "item.compactmachines.machine_maximum": "Compact Machine (Maximum)", - "item.compactmachines.personal_shrinking_device": "Personal Shrinking Device", - "item.compactmachines.tunnels.item": "Item Tunnel", "item.compactmachines.tunnels.redstone_in": "Redstone Tunnel (In)", "item.compactmachines.tunnels.redstone_out": "Redstone Tunnel (Out)", - - "compactmachines.cannot_enter": "You fumble with the shrinking device, to no avail. It refuses to work.", - "compactmachines.connected_block": "Connected: %s", "compactmachines.direction.side": "Side: %s", "compactmachines.direction.up": "Up", @@ -49,9 +43,29 @@ "compactmachines.direction.south": "South", "compactmachines.direction.west": "West", "compactmachines.direction.east": "East", - "compactmachines.psd.pages.machines.title": "Compact Machines", "compactmachines.psd.pages.machines": "Compact Machines are the core mechanic of this mod. They allow you to build large rooms in a single block space connected to the outside world. They come in various sizes ranging from 3x3x3 to 13x13x13.\n\nYou can use Tunnels to connect the outside block faces with any of the inside walls to transport items, fluids etc.\n\nYou can enter a Compact Machine by right-clicking it with a Personal Shrinking Device. Please use JEI to look up crafting recipes.", - - "compactmachines.errors.unknown_tunnel_type": "Unknown Tunnel Type (%s)" + "compactmachines.errors.unknown_tunnel_type": "Unknown Tunnel Type (%s)", + "advancement.compactmachines.root": "Compact Machines", + "advancement.compactmachines.root.desc": "", + "advancement.compactmachines.how_did_you_get_here": "How Did You Get Here?!", + "advancement.compactmachines.how_did_you_get_here.desc": "Manage to trap yourself inside a machine room.", + "advancement.compactmachines.foundations": "Foundations", + "advancement.compactmachines.foundations.desc": "Obtain a breakable wall block.", + "advancement.compactmachines.got_shrinking_device": "Personal Shrinking Device", + "advancement.compactmachines.got_shrinking_device.desc": "Obtain a Personal Shrinking Device.", + "advancement.compactmachines.claimed_machine_tiny": "Small Spaces, Big Ideas", + "advancement.compactmachines.claimed_machine_tiny.desc": "Claim a tiny compact machine.", + "advancement.compactmachines.claimed_machine_small": "I Can Breathe", + "advancement.compactmachines.claimed_machine_small.desc": "Claim a small compact machine.", + "advancement.compactmachines.claimed_machine_normal": "Bigger on the Inside", + "advancement.compactmachines.claimed_machine_normal.desc": "Claim a normal compact machine.", + "advancement.compactmachines.claimed_machine_large": "Room to Grow", + "advancement.compactmachines.claimed_machine_large.desc": "Claim a large compact machine.", + "advancement.compactmachines.claimed_machine_giant": "Got Enough Space?", + "advancement.compactmachines.claimed_machine_giant.desc": "Claim a giant compact machine.", + "advancement.compactmachines.claimed_machine_max": "Room for Activities!", + "advancement.compactmachines.claimed_machine_max.desc": "Claim a maximum compact machine.", + "jei.compactmachines.shrinking_device": "Use the Personal Shrinking Device (PSD) on a machine in order to enter a compact space. You can also right click it in the overworld for more info.", + "jei.compactmachines.machines": "Machines are used to make pocket dimensions. Craft a machine and place it in world, then use a Personal Shrinking Device to go inside." } \ No newline at end of file diff --git a/src/main/resources/assets/compactmachines/lang/en_us.lang b/src/main/resources/assets/compactmachines/lang/en_us.lang deleted file mode 100644 index 9a1b57df..00000000 --- a/src/main/resources/assets/compactmachines/lang/en_us.lang +++ /dev/null @@ -1,138 +0,0 @@ -generator.compactsky=Compact Sky - -tile.compactmachines.tunnel.name=Tunnel -tile.compactmachines.redstonetunnel.name=Redstone Tunnel -tile.compactmachines.fieldprojector.name=Miniaturization Field Projector - -item.compactmachines.psd.spawnpoint_set=Entry point set! - -hint.compactmachines.missing_opposite_projector=Missing opposite field projector! It is required to determine the field size! -hint.compactmachines.missing_projector_at=Missing field projector at %d,%d,%d -hint.compactmachines.currently_crafting=Currently crafting: %s (progress: %s%%) -hint.compactmachines.no_recipe_found=No valid recipe found -hint.compactmachines.found_recipe_for=Recipe for: %s -hint.compactmachines.invalid_block_in_field=Invalid block in field area @ %d,%d,%d: %s -hint.compactmachines.cant_sleep_here=You can not sleep in the Compact Machines dimension -hint.compactmachines.bed_position_set=Respawn position set to this Machine -hint.compactmachines.not_permitted_to_enter=You do not have permission to enter this machine - -hint.compactmachines.skyworld.no_block_breaking=You can not break any blocks in the Compact Hub! -hint.compactmachines.skyworld.no_block_placing=You can not place any blocks in the Compact Hub! -hint.compactmachines.skyworld.only_one_machine_claim=You can only claim a single Compact Machine in the hub! - -top.compactmachines.currently_crafting=Crafting: -top.compactmachines.found_recipe_for=Recipe for: - -tooltip.compactmachines.machine.coords=Machine: -tooltip.compactmachines.machine.coords.unused=Unused -tooltip.compactmachines.machine.schema=Schema: -tooltip.compactmachines.machine.stopitsoaryn=Feedbackloop detected - -tooltip.compactmachines.fieldprojector.hint=Place 4 opposite of each other to create a Miniaturization Crafting field. Right click to get hints where the next projector needs to be! -tooltip.compactmachines.tunneltool.hint=Used to connect Wall blocks with outside Compact Machine faces. -tooltip.compactmachines.redstonetunneltool.hint=Used to transfer redstone signals between wall blocks and outside Compact Machine faces. - -tooltip.compactmachines.lockforotherplayers.checkbox=Lock for other players - -tooltip.compactmachines.jei.crafting_trigger=Throw this into the miniaturization field to start the crafting process. -tooltip.compactmachines.jei.shape=Use these to build the multiblock - -compactmachines.jei.category.multiblock_miniaturization=Multiblock Miniaturization - - -commands.compactmachines.usage=/compactmachines [subcommand, leave empty for list of commands] - -commands.compactmachines.available=Available sub-commands: -commands.compactmachines.denied=You do not have the permission to use this command. - -commands.compactmachines.schema.description=Save/load the contents of machines -commands.compactmachines.schema.save.usage=/compactmachines schema save -commands.compactmachines.schema.save.description=Saves the machine you are in to disk -commands.compactmachines.schema.save.exception.not_in_machine_dimension=You must be in the machine dimension for this command to work. -commands.compactmachines.schema.save.exception.invalid_file=Could not open file for writing! Schema is not saved! -commands.compactmachines.schema.save.exception.not_serializable=Could not serialize machine! Schema is not saved! -commands.compactmachines.schema.save.success=Wrote schema to file: %s - -commands.compactmachines.schema.load.usage=/compactmachines schema load -commands.compactmachines.schema.load.description=Generates the specified schema in the room you are standing in -commands.compactmachines.schema.load.exception.not_in_machine_dimension=You must be in the machine dimension for this command to work. -commands.compactmachines.schema.load.exception.unknown_schema=No schema with that name exists! -commands.compactmachines.schema.load.exception.machine_size_does_not_match=The size of the machine does not match the schema! -commands.compactmachines.schema.load.machine_schema_set_to=Machine set to schema: %s - -commands.compactmachines.schema.set.usage=/compactmachines schema set -commands.compactmachines.schema.set.description=Sets the specified schema to the Compact Machine block you are looking at -commands.compactmachines.schema.set.exception.unknown_schema=No schema with that name exists! -commands.compactmachines.schema.set.exception.look_at_compact_machine=You need to look at a Compact Machine block! -commands.compactmachines.schema.set.exception.machine_size_does_not_match=The size of the machine does not match the schema! -commands.compactmachines.schema.set.exception.machine_is_already_in_use=Machine is already in use. Place a new machine! -commands.compactmachines.schema.set.machine_schema_set_to=Machine set to schema: %s - -commands.compactmachines.schema.reload-files.usage=/compactmachines schema reload-files -commands.compactmachines.schema.reload-files.description=Reloads all the stored schema files from disk and from the jar - - -commands.compactmachines.recipe.description=Stuff related to Multiblock Miniaturization recipes -commands.compactmachines.recipe.unpack-defaults.usage=/compactmachines recipe unpack-defaults [force] -commands.compactmachines.recipe.unpack-defaults.description=Extract the default recipes from the .jar to the config folder. Append "force" to overwrite existing files. - -commands.compactmachines.recipe.copy-shape.usage=/compactmachines recipe copy-shape -commands.compactmachines.recipe.copy-shape.description=Copies the crafting shape of the projector you are looking at into your clipboard -commands.compactmachines.recipe.copy-shape.exception.not_looking_at_projector=You are not looking at a Field Projector -commands.compactmachines.recipe.copy-shape.success=Copied shape to clipboard! - -commands.compactmachines.recipe.copy-item.usage=/compactmachines recipe copy-item [catalyst|target] -commands.compactmachines.recipe.copy-item.description=Copies the stack in your main hand to the clipboard -commands.compactmachines.recipe.copy-item.exception.missing_type=You need to specify whether you want to get the JSON for a catalyst or for the target stack -commands.compactmachines.recipe.copy-item.exception.missing_item=You need to hold something in your hand for this command to work! -commands.compactmachines.recipe.copy-item.success=Copied item to clipboard! - -commands.compactmachines.recipe.generate.usage=/compactmachines recipe generate -commands.compactmachines.recipe.generate.description=Generates the given recipe in world. Warning: Replaces all blocks in area! -commands.compactmachines.recipe.generate.exception.not_looking_at_block=You are not looking at a block where the Recipe will be built. -commands.compactmachines.recipe.generate.exception.unknown_recipe=The given recipe does not seem to exist. -commands.compactmachines.recipe.generate.exception.missing_machine_recipe=You need to specify a recipe name (use tab completion!) - -commands.compactmachines.machines.description=Commands to recover lost/broken machines -commands.compactmachines.machines.give.usage=/compactmachines machines give -commands.compactmachines.machines.give.description=Gives the player a corresponding cube. WARNING: This breaks Machines if they already exist in the world! -commands.compactmachines.machines.give.warning=WARNING: This breaks Machines if they already exist in the world! - -commands.compactmachines.machines.view.usage=/compactmachines machines view [] -commands.compactmachines.machines.view.description=Opens a GUI allowing inspectation of all existing Compact Machines - -commands.compactmachines.machines.clear.usage=/compactmachines machines clear [] -commands.compactmachines.machines.clear.description=Sets all blocks inside the given machine to air. - -gui.compactmachines.psd.welcome.welcome=Compact Machines 3 allows you to build complex machine contraptions within a single block! -gui.compactmachines.psd.welcome.chapters=Available chapters: - -gui.compactmachines.psd.machines.label=Compact Machines -gui.compactmachines.psd.machines.text=Compact Machines are the core mechanic of this mod. They allow you to build large rooms in a single block space connected to the outside world.\nThey come in various sizes ranging from 3x3x3 to 13x13x13.\nYou can use Tunnels to connect the outside block faces with any of the inside walls to transport items, fluids etc.\nYou can enter a Compact Machine by right-clicking it with a Personal Shrinking Device.\nPlease use JEI to look up crafting recipes. - -gui.compactmachines.psd.tunnels.label=Tunnels -gui.compactmachines.psd.tunnels.text=Tunnels are used to connect inside wall faces to outside block faces. Only one connection for each outside face, this means a total of 6 tunnels per machine.\nRight click a Compact Machine Wall with a Tunnel Tool to place a tunnel. Right click it again to cycle through the outside faces it is connected to.\nTunnels are using the Forge Capability system to "connect" the two blocks. Other mods need to use this system for tunnels to work properly. This is the case for most storage, but rarely for multiblock systems, so expect some pipes etc to not work as expected. - -gui.compactmachines.psd.redstone_tunnels.label=Redstone Tunnels -gui.compactmachines.psd.redstone_tunnels.text=These can be used to transfer redstone signals between the machine and the world it is placed in. In comparison to normal Tunnels they are not bidirectional, but need to be configured to be either In- or Output. Press the button in the top right corner to toggle between modes (red=in, green=out).\nYou can use these to either enable/disable redstone based systems inside your machines or to build complicated redstone circuits inside a single block. - -gui.compactmachines.psd.crafting.label=Miniaturization Crafting -gui.compactmachines.psd.crafting.text=To craft Compact Machines you will need to set up a miniaturization crafting structure.\nGrab 4 Miniaturization Field Projectors and place them opposite of each other, with 7, 11 or 15 spaces between them. All of them need to face the center.\nOnce placed correctly they will start emitting a miniaturization field. Build a recipe like specified in JEI and throw the catalyst item inside the field to start the crafting process. - -gui.compactmachines.compactsky.whitelist=Whitelist -gui.compactmachines.compactsky.preview=Preview -gui.compactmachines.compactsky.enter=Enter machine -gui.compactmachines.compactsky.rename=Rename - -gui.compactmachines.compactsky.configuration.startLocked=Start machines in locked state -gui.compactmachines.compactsky.configuration.givePSD=Give players a Shrinking Device on first spawn -gui.compactmachines.compactsky.configuration.voidDimensions=Use void dimensions -gui.compactmachines.compactsky.configuration.schema=Schema -gui.compactmachines.compactsky.configuration.close=Done -gui.compactmachines.compactsky.configuration.label.MachineSize=Machine Size -gui.compactmachines.compactsky.configuration.label.Description=Description -gui.compactmachines.compactsky.configuration.warning.PleaseSpecifyADescription=Please specify a description in the schemas .json file! - -gui.compactmachines.compactsky.configuration.small=16 Players -gui.compactmachines.compactsky.configuration.medium=64 Players -gui.compactmachines.compactsky.configuration.large=256 Players \ No newline at end of file diff --git a/src/main/resources/data/compactmachines/dimension/compact_world.json b/src/main/resources/data/compactmachines/dimension/compact_world.json index 5070cb65..e1c929b2 100644 --- a/src/main/resources/data/compactmachines/dimension/compact_world.json +++ b/src/main/resources/data/compactmachines/dimension/compact_world.json @@ -17,7 +17,7 @@ "generator": { "type": "minecraft:flat", "settings": { - "biome": "minecraft:the_void", + "biome": "minecraft:plains", "layers": [ { "block": "minecraft:air", diff --git a/src/test/java/dev/compactmods/machines/tests/GraphTests.java b/src/test/java/dev/compactmods/machines/tests/GraphTests.java new file mode 100644 index 00000000..94c17bd8 --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/GraphTests.java @@ -0,0 +1,353 @@ +package dev.compactmods.machines.tests; + +import com.google.common.graph.Graph; +import com.mojang.serialization.DataResult; +import dev.compactmods.machines.data.codec.CodecExtensions; +import dev.compactmods.machines.data.graph.CompactMachineConnectionGraph; +import dev.compactmods.machines.data.graph.CompactMachineNode; +import dev.compactmods.machines.data.graph.CompactMachineRoomNode; +import dev.compactmods.machines.data.graph.IMachineGraphNode; +import dev.compactmods.machines.util.MathUtil; +import net.minecraft.nbt.*; +import net.minecraft.util.math.ChunkPos; +import net.minecraftforge.common.util.Constants; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.Optional; + +@DisplayName("Machine Graph Tests") +public class GraphTests { + + private CompactMachineConnectionGraph generateGraphWithSingleRoom() { + CompactMachineConnectionGraph g = new CompactMachineConnectionGraph(); + + g.addMachine(0); + g.addRoom(new ChunkPos(0, 0)); + + g.connectMachineToRoom(0, new ChunkPos(0, 0)); + return g; + } + + private CompactMachineConnectionGraph generateGraphWithMultipleRooms(int numRooms) { + CompactMachineConnectionGraph g = new CompactMachineConnectionGraph(); + + for (int i = 0; i < numRooms; i++) { + g.addMachine(i); + ChunkPos chunk = MathUtil.getChunkForRoomIndex(i); + g.addRoom(chunk); + g.connectMachineToRoom(i, chunk); + } + + return g; + } + + private void verifySingleRoomValid(CompactMachineConnectionGraph graph, int machine, ChunkPos room) { + Optional connectedRoom = graph.getConnectedRoom(machine); + Assertions.assertTrue(connectedRoom.isPresent()); + + connectedRoom.ifPresent(cRoom -> { + Assertions.assertEquals(room, cRoom); + }); + } + + @Test + @DisplayName("Can Create Basic Graph") + void basicGraph() { + + CompactMachineConnectionGraph g = new CompactMachineConnectionGraph(); + + Assertions.assertEquals(0, g.getMachines().count()); + + // At construction, no machines or rooms are registered + // The method itself should just return an empty collection in this scenario + Assertions.assertDoesNotThrow(() -> g.getMachinesFor(new ChunkPos(0, 0))); + + // Make sure that there's no linked machines here + Collection linkedMachines = g.getMachinesFor(new ChunkPos(0, 0)); + Assertions.assertNotNull(linkedMachines); + Assertions.assertEquals(0, linkedMachines.size()); + + // Make sure there's no linked rooms + Optional connectedRoom = g.getConnectedRoom(0); + Assertions.assertNotNull(connectedRoom); + Assertions.assertFalse(connectedRoom.isPresent()); + } + + @Test + @DisplayName("Create Single Linked Machine (1:1)") + void canCreateGraphWithLinkedMachine() { + int machine = 0; + ChunkPos room = new ChunkPos(0, 0); + + CompactMachineConnectionGraph g = generateGraphWithSingleRoom(); + + verifySingleRoomValid(g, machine, room); + + Collection linkedMachines = g.getMachinesFor(room); + Assertions.assertEquals(1, linkedMachines.size()); + Assertions.assertTrue(linkedMachines.contains(machine)); + } + + + @Test + @DisplayName("Create Multiple Rooms (1:1)") + void canCreateMultipleRoomsWithSingleLinkedMachine() { + CompactMachineConnectionGraph graph = generateGraphWithMultipleRooms(10); + + for (int roomIndex = 0; roomIndex < 10; roomIndex++) { + final ChunkPos EXPECTED_CHUNK = MathUtil.getChunkForRoomIndex(roomIndex); + + verifySingleRoomValid(graph, roomIndex, EXPECTED_CHUNK); + } + } + + @Test + @DisplayName("Create Multiple Linked Machines (M:1)") + void canCreateRoomWithMultipleLinkedMachines() { + int MACHINE_1 = 0; + int MACHINE_2 = 1; + ChunkPos EXPECTED_ROOM = new ChunkPos(0, 0); + + CompactMachineConnectionGraph g = new CompactMachineConnectionGraph(); + + g.addMachine(0); + g.addMachine(1); + + ChunkPos roomChunk = new ChunkPos(0, 0); + g.addRoom(roomChunk); + g.connectMachineToRoom(0, roomChunk); + g.connectMachineToRoom(1, roomChunk); + + verifySingleRoomValid(g, 0, EXPECTED_ROOM); + verifySingleRoomValid(g, 1, EXPECTED_ROOM); + + Collection linkedMachines = g.getMachinesFor(EXPECTED_ROOM); + Assertions.assertEquals(2, linkedMachines.size()); + Assertions.assertTrue(linkedMachines.contains(MACHINE_1)); + Assertions.assertTrue(linkedMachines.contains(MACHINE_2)); + } + + @Test + @DisplayName("Correctly serializes to NBT") + void canSerialize() { + CompactMachineConnectionGraph graph = generateGraphWithSingleRoom(); + + DataResult nbtResult = CompactMachineConnectionGraph.CODEC.encodeStart(NBTDynamicOps.INSTANCE, graph); + + nbtResult.resultOrPartial(Assertions::fail) + .ifPresent(nbt -> { + Assertions.assertTrue(nbt instanceof CompoundNBT); + +// try { +// File file = FileHelper.RESOURCES_DIR.resolve("graph.dat").toFile(); +// file.delete(); +// CompressedStreamTools.writeCompressed((CompoundNBT) nbt, file); +// } catch (IOException e) { +// e.printStackTrace(); +// } + + CompoundNBT c = (CompoundNBT) nbt; + Assertions.assertFalse(c.isEmpty()); + + Assertions.assertTrue(c.contains("connections")); + + ListNBT connections = c.getList("connections", Constants.NBT.TAG_COMPOUND); + Assertions.assertEquals(1, connections.size(), "Expected one connection from a machine to a single room."); + + CompoundNBT conn1 = connections.getCompound(0); + Assertions.assertNotNull(conn1); + + Assertions.assertTrue(conn1.contains("machine")); + Assertions.assertTrue(conn1.contains("connections")); + + INBT machineChunk = conn1.get("machine"); + DataResult chunkRes = CodecExtensions.CHUNKPOS.parse(NBTDynamicOps.INSTANCE, machineChunk); + chunkRes.resultOrPartial(Assertions::fail) + .ifPresent(chunk -> { + Assertions.assertEquals(new ChunkPos(0, 0), chunk); + }); + + ListNBT connList = conn1.getList("connections", Constants.NBT.TAG_INT); + Assertions.assertNotNull(connList); + Assertions.assertEquals(1, connList.size()); + Assertions.assertEquals(0, connList.getInt(0)); + }); + } + + @Test + void simpleNestedMachines() { + /* + Overworld - Contains Machine 0, linked to Room 0 + CompactWorld - Contains Machine 1, linked to Room 1 (Inside Room 0) + */ + + CompactMachineConnectionGraph graph = new CompactMachineConnectionGraph(); + + graph.addMachine(0); + graph.addMachine(1); + + // Add two rooms + ChunkPos room0 = MathUtil.getChunkForRoomIndex(0); + ChunkPos room1 = MathUtil.getChunkForRoomIndex(1); + graph.addRoom(room0); + graph.addRoom(room1); + + graph.connectMachineToRoom(0, room0); + graph.connectMachineToRoom(1, room1); + + } +// private void generateData(MutableGraph g, HashMap lookup) { +// Random r = new Random(); +// MachineExternalLocation[] values = MachineExternalLocation.values(); +// int numInsides = 0; +// int numOutsides = 0; +// +// Set disconnected = new HashSet<>(); +// List externals = new ArrayList<>(); +// List internals = new ArrayList<>(); +// +// // Seed a couple of machines and insides so they're always there +// for(int i = 0; i < 10; i++) { +// ChunkPos machineChunk = getMachineChunkPos(numInsides + 1); +// CompactMachineExternalNode extern = createMachineExternalNode(g, lookup, i); +// CompactMachineInsideNode intern = createMachineInternalNode(g, lookup, machineChunk); +// +// externals.add(extern); +// internals.add(intern); +// +// extern.connectTo(intern); +// numOutsides++; +// numInsides++; +// } +// +// for(int i = 0; i < 50; i++) { +// +// if(r.nextBoolean()) { +// // Creating the outside of a machine +// MachineExternalLocation loc = values[r.nextInt(values.length)]; +// +// CompactMachineExternalNode machine = createMachineExternalNode(g, lookup, numOutsides + 1); +// externals.add(machine); +// +// switch (loc) { +// case EXTERNAL_DIMENSION: +// int randomMachineInsideE = r.nextInt(internals.size()); +// CompactMachineInsideNode miE = internals.get(randomMachineInsideE); +// machine.connectTo(miE); +// +// // try to remove from disconnected if it exists there +// disconnected.remove(miE); +// break; +// +// case INSIDE_MACHINE: +// int randomMachineInsideI = r.nextInt(internals.size()); +// CompactMachineInsideNode miI = internals.get(randomMachineInsideI); +// +// // Put the machine inside a randomly chosen existing machine +// g.putEdge(miI, machine); +// +// boolean connectToAnother = r.nextBoolean(); +// if(connectToAnother) { +// System.out.println("connect"); +// int randomMachine = r.nextInt(internals.size()); +// CompactMachineInsideNode in = internals.get(randomMachine); +// machine.connectTo(in); +// +// g.successors(machine); // All the connections internally +// } +// break; +// } +// +// numOutsides++; +// } else { +// // Creating the inside of a machine +// ChunkPos machineChunk= getMachineChunkPos(numInsides + 1); +// CompactMachineInsideNode mi = createMachineInternalNode(g, lookup, machineChunk); +// disconnected.add(mi); +// numInsides++; +// } +// } +// +// if(!disconnected.isEmpty()) { +// for (IMachineGraphNode di : disconnected) { +// CompactMachineExternalNode machine = createMachineExternalNode(g, lookup, numOutsides + 1); +// machine.connectTo(di); +// numOutsides++; +// } +// } +// +// disconnected.clear(); +// } + + public static String write(final CompactMachineConnectionGraph graph) { + StringBuilder sb = new StringBuilder(); + sb + .append("strict digraph G {") + .append(System.lineSeparator()) + .append("\tlayout = fdp;").append(System.lineSeparator()) + .append("\tnode [shape=square,style=filled,color=lightgray];").append(System.lineSeparator()); + +// Set topLevelMachines = graph.getMachines() +// .filter(n -> graph.getConnectedRoom(n.getMachineId()).isPresent()) +// .collect(Collectors.toSet()); +// +// for (CompactMachineNode n : topLevelMachines) +// outputExternalNode(sb, n); +// +// graph.nodes().stream() +// .filter(n -> n instanceof CompactMachineRoomNode) +// .map(n -> (CompactMachineRoomNode) n) +// .forEach(n -> { +// outputMachineInside(graph, sb, n); +// }); + + sb.append("}"); + return sb.toString(); + } + + private static void outputMachineInside(Graph graph, StringBuilder sb, IMachineGraphNode inside) { + if (inside instanceof CompactMachineRoomNode) { + CompactMachineRoomNode min = (CompactMachineRoomNode) inside; + + String insideClusterName = "cluster_" + min.getId(); + graph.predecessors(min).forEach(incoming -> { + sb.append("\t") + .append(incoming.getId()) + .append("->") + .append(insideClusterName) + .append(System.lineSeparator()); + }); + + sb.append("\t") + .append("subgraph ").append(insideClusterName) + .append(" {") + .append(System.lineSeparator()); + + sb.append("\t\t") + .append(String.format("graph [label=\"%s\",style=filled,color=cadetblue]", min.label())) + .append(System.lineSeparator()); + + graph.successors(min).forEach(insideNode -> { + if (insideNode instanceof CompactMachineNode) { + CompactMachineNode men = (CompactMachineNode) insideNode; + outputExternalNode(sb, men); + } + }); + + sb.append("\t") + .append("}").append(System.lineSeparator()) + .append(System.lineSeparator()); + } + } + + private static void outputExternalNode(StringBuilder sb, CompactMachineNode men) { + boolean connected = true; + sb.append("\t") + .append(men.getId()) + .append(String.format(" [label=\"%s\",style=filled,color=%s]", men.label(), connected ? "lightgray" : "palevioletred1")) + .append(System.lineSeparator()); + } +} diff --git a/src/test/java/dev/compactmods/machines/tests/MathTests.java b/src/test/java/dev/compactmods/machines/tests/MathTests.java new file mode 100644 index 00000000..6bfd49db --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/MathTests.java @@ -0,0 +1,45 @@ +package dev.compactmods.machines.tests; + +import dev.compactmods.machines.util.MathUtil; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.vector.Vector3i; +import org.junit.jupiter.api.*; + +import java.util.HashMap; + +@DisplayName("Math") +public class MathTests { + + @Test + @DisplayName("Position Generator Works Correctly") + void positionGeneratorWorksCorrectly() { + // Our generation works in a counter-clockwise spiral, starting at 0,0 + /* + * 6 5 4 + * 7 0 3 + * 8 1 2 + */ + + HashMap tests = new HashMap<>(); + tests.put(0, new ChunkPos(0, 0)); + tests.put(1, new ChunkPos(0, -64)); + tests.put(2, new ChunkPos(64, -64)); + tests.put(3, new ChunkPos(64, 0)); + tests.put(4, new ChunkPos(64, 64)); + tests.put(5, new ChunkPos(0, 64)); + tests.put(6, new ChunkPos(-64, 64)); + tests.put(7, new ChunkPos(-64, 0)); + tests.put(8, new ChunkPos(-64, -64)); + + tests.forEach((id, expectedChunk) -> { + Vector3i byIndex = MathUtil.getRegionPositionByIndex(id); + BlockPos finalPos = MathUtil.getCenterWithY(byIndex, 0); + + ChunkPos calculatedChunk = new ChunkPos(finalPos); + + String error = String.format("Generation did not match for %s.", id); + Assertions.assertEquals(expectedChunk, calculatedChunk, error); + }); + } +} diff --git a/src/test/java/dev/compactmods/machines/tests/codec/CodecTests.java b/src/test/java/dev/compactmods/machines/tests/codec/CodecTests.java new file mode 100644 index 00000000..7da92e27 --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/codec/CodecTests.java @@ -0,0 +1,44 @@ +package dev.compactmods.machines.tests.codec; + +import com.mojang.serialization.DataResult; +import dev.compactmods.machines.data.codec.CodecExtensions; +import dev.compactmods.machines.reference.EnumMachineSize; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.nbt.StringNBT; +import net.minecraft.util.math.vector.Vector3d; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CodecTests { + + @Test + void canSerializeVector3d() { + Vector3d expected = new Vector3d(1.25d, 2.50d, 3.75d); + + DataResult nbtResult = CodecExtensions.VECTOR3D.encodeStart(NBTDynamicOps.INSTANCE, expected); + nbtResult.resultOrPartial(Assertions::fail) + .ifPresent(nbt -> { + ListNBT list = (ListNBT) nbt; + + Assertions.assertEquals(expected.x, list.getDouble(0)); + Assertions.assertEquals(expected.y, list.getDouble(1)); + Assertions.assertEquals(expected.z, list.getDouble(2)); + }); + } + + @Test + void canSerializeMachineSize() { + DataResult result = EnumMachineSize.CODEC.encodeStart(NBTDynamicOps.INSTANCE, EnumMachineSize.LARGE); + + result.resultOrPartial(Assertions::fail) + .ifPresent(nbt -> { + Assertions.assertEquals(StringNBT.TYPE, nbt.getType()); + + StringNBT string = (StringNBT) nbt; + Assertions.assertNotNull(string); + Assertions.assertEquals(EnumMachineSize.LARGE.getSerializedName(), string.getAsString()); + }); + } +} diff --git a/src/test/java/dev/compactmods/machines/tests/minecraft/ExampleTest.java b/src/test/java/dev/compactmods/machines/tests/minecraft/ExampleTest.java new file mode 100644 index 00000000..4e5148c6 --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/minecraft/ExampleTest.java @@ -0,0 +1,19 @@ +package dev.compactmods.machines.tests.minecraft; + +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +public class ExampleTest { + + @Test + @Tag("minecraft") + void CanDoBasicTest() { + MinecraftServer serv = ServerLifecycleHooks.getCurrentServer(); + // SavedMachineData sd = SavedMachineData.getInstance(serv); + // SavedMachineDataMigrator.migrate(serv); + } + + +} diff --git a/src/test/java/dev/compactmods/machines/tests/nbt/MachineExternalDataTests.java b/src/test/java/dev/compactmods/machines/tests/nbt/MachineExternalDataTests.java new file mode 100644 index 00000000..bbead231 --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/nbt/MachineExternalDataTests.java @@ -0,0 +1,58 @@ +package dev.compactmods.machines.tests.nbt; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import dev.compactmods.machines.data.persistent.CompactMachineData; +import dev.compactmods.machines.teleportation.DimensionalPosition; +import dev.compactmods.machines.tests.util.FileHelper; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTDynamicOps; +import net.minecraft.util.RegistryKey; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +@DisplayName("External Machine Data") +public class MachineExternalDataTests { + private final Path EXTERNAL = Paths.get("scenario", "single-machine-player-inside", "machines_external.dat"); + + Codec> c = CompactMachineData.MachineData.CODEC.listOf() + .fieldOf("locations") + .stable() + .codec(); + + @Test + @DisplayName("Loads Single Machine Data") + void canLoadSingleMachineData() throws IOException { + // The external point is overworld @ 8x4x8 (it was made in a default void superflat) + DimensionalPosition OUTSIDE = new DimensionalPosition( + RegistryKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation("overworld")), + new BlockPos(8,4,8) + ); + + CompoundNBT nbt = FileHelper.INSTANCE.getNbtFromFile(EXTERNAL.toString()); + CompoundNBT data = nbt.getCompound("data"); + DataResult> result = c.parse(NBTDynamicOps.INSTANCE, data); + + Assertions.assertFalse(data.isEmpty()); + + Optional> res = result.result(); + Assertions.assertTrue(res.isPresent()); + + res.ifPresent(list -> { + Assertions.assertEquals(1, list.size()); + + CompactMachineData.MachineData extern = list.get(0); + Assertions.assertEquals(OUTSIDE, extern.location); + }); + } +} diff --git a/src/test/java/dev/compactmods/machines/tests/util/FileHelper.java b/src/test/java/dev/compactmods/machines/tests/util/FileHelper.java new file mode 100644 index 00000000..791f26d8 --- /dev/null +++ b/src/test/java/dev/compactmods/machines/tests/util/FileHelper.java @@ -0,0 +1,48 @@ +package dev.compactmods.machines.tests.util; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.CompressedStreamTools; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class FileHelper { + public static final FileHelper INSTANCE = new FileHelper(); + public static Path RESOURCES_DIR = Paths.get("src","test","resources"); + + private FileHelper() { + } + + public InputStream getFileStream(String filename) { + return getClass().getClassLoader().getResourceAsStream(filename); + } + + public InputStreamReader openFile(String filename) { + URL res = getClass().getClassLoader().getResource(filename); + try { + InputStream inputStream = res.openStream(); + return new InputStreamReader(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + public JsonElement getJsonFromFile(String filename) { + Gson g = new Gson(); + InputStreamReader isr = openFile(filename); + return g.fromJson(isr, JsonElement.class); + } + + public CompoundNBT getNbtFromFile(String filename) throws IOException { + InputStream isr = getFileStream(filename); + return CompressedStreamTools.readCompressed(isr); + } +} diff --git a/src/test/resources/scenario/single-machine-player-inside/machines_external.dat b/src/test/resources/scenario/single-machine-player-inside/machines_external.dat new file mode 100644 index 00000000..d217b852 Binary files /dev/null and b/src/test/resources/scenario/single-machine-player-inside/machines_external.dat differ diff --git a/src/test/resources/scenario/single-machine-player-inside/machines_internal.dat b/src/test/resources/scenario/single-machine-player-inside/machines_internal.dat new file mode 100644 index 00000000..051b30de Binary files /dev/null and b/src/test/resources/scenario/single-machine-player-inside/machines_internal.dat differ diff --git a/src/test/resources/scenario/single-machine-player-inside/players.dat b/src/test/resources/scenario/single-machine-player-inside/players.dat new file mode 100644 index 00000000..1a485dda Binary files /dev/null and b/src/test/resources/scenario/single-machine-player-inside/players.dat differ