diff --git a/build.gradle b/build.gradle index 043d4d5..5eb5655 100644 --- a/build.gradle +++ b/build.gradle @@ -1,85 +1,66 @@ -plugins { - id 'eclipse' - id 'maven-publish' - id 'net.minecraftforge.gradle' version '5.1.+' +buildscript { + repositories { + maven { url = 'https://maven.minecraftforge.net' } + mavenCentral() + jcenter() + maven { url = 'https://repo.spongepowered.org/repository/maven-public' } + maven { url = 'https://maven.parchmentmc.org' } + } + dependencies { + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: "${forgegradle_version}", changing: false + classpath "org.spongepowered:mixingradle:${mixingradle_version}" + classpath "org.parchmentmc:librarian:${librarian_version}" + } } +plugins { + id 'com.matthewprenger.cursegradle' version "${cursegradle_version}" +} +apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'org.parchmentmc.librarian.forgegradle' +apply plugin: 'eclipse' +apply plugin: 'maven-publish' +apply plugin: 'org.spongepowered.mixin' -version = '1.19-2.40' +jarJar.enable() + +boolean flywheelInWorkspace = findProject(':Flywheel') != null + +ext.buildNumber = System.getenv('BUILD_NUMBER') + +version = mod_version group = 'nl.requios.effortlessbuilding' -archivesBaseName = 'effortlessbuilding' +archivesBaseName = "effortlessbuilding-${artifact_minecraft_version}" -// Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { - // The mappings can be changed at any time, and must be in the following format. - // snapshot_YYYYMMDD Snapshot are built nightly. - // stable_# Stables are built at the discretion of the MCP team. - // Use non-default mappings at your own risk. they may not always work. - // Simply re-run your setup task after changing the mappings to update your workspace. - mappings channel: 'official', version: '1.19.2' + mappings channel: 'parchment', version: "${parchment_version}-${minecraft_version}" accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. - // Default run configurations. - // These can be tweaked, removed, or duplicated as needed. runs { client { workingDirectory project.file('run') - - // Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP) - property 'forge.logging.markers', 'REGISTRIES' - - // Recommended logging level for the console - property 'forge.logging.console.level', 'debug' - - // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. - property 'forge.enabledGameTestNamespaces', 'effortlessbuilding' - - // Flywheel - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" + arg '-mixin.config=flywheel.mixins.json' + //jvmArgs '-XX:+UnlockCommercialFeatures' // uncomment for profiling + property 'forge.logging.console.level', 'info' mods { effortlessbuilding { source sourceSets.main } + + if (flywheelInWorkspace) { + flywheel { + source project(":Flywheel").sourceSets.main + } + } } } server { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - - property 'forge.logging.console.level', 'debug' - - property 'forge.enabledGameTestNamespaces', 'effortlessbuilding' - - // Flywheel - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - - mods { - effortlessbuilding { - source sourceSets.main - } - } - } - - // This run config launches GameTestServer and runs all registered gametests, then exits. - // By default, the server will crash when no gametests are provided. - // The gametest system is also enabled by default for other run configs under the /test command. - gameTestServer { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - - property 'forge.logging.console.level', 'debug' - - property 'forge.enabledGameTestNamespaces', 'effortlessbuilding' - + workingDirectory project.file('run/server') + property 'forge.logging.console.level', 'info' mods { effortlessbuilding { source sourceSets.main @@ -89,73 +70,107 @@ minecraft { data { workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - + property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' - - // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. - args '--mod', 'effortlessbuilding', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - + args '--mod', 'effortlessbuilding', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources') mods { effortlessbuilding { source sourceSets.main } + + if (flywheelInWorkspace) { + flywheel { + source project(":Flywheel").sourceSets.main + } + } } } } } -// Include resources generated by data generators. -sourceSets.main.resources { srcDir 'src/generated/resources' } - repositories { - // Put repositories for dependencies here - // ForgeGradle automatically adds the Forge maven and Maven Central for you - - // If you have mod jar dependencies in ./libs, you can declare them as a repository like so: - // flatDir { - // dir 'libs' - // } - - //Flywheel maven { - name "tterrag maven" - url "https://maven.tterrag.com/" + // Location of the maven that hosts JEI files (and TiC) + name 'Progwml6 maven' + url 'https://dvs1.progwml6.com/files/maven' + } + /*maven { + // Location of a maven mirror for JEI files, as a fallback + name 'ModMaven' + url 'https://modmaven.k-4u.nl' + }*/ + maven { + // Location of the maven for vazkii's mods + name 'blamejared' + url 'https://maven.blamejared.com' + } + maven { + // Location of the maven for mixed mappings, Registrate, and Flywheel + name 'tterrag maven' + url 'https://maven.tterrag.com' + } + maven { + url 'https://www.cursemaven.com' + content { + includeGroup "curse.maven" + } + } + maven { + //location of the maven for dynamic trees + url 'https://harleyoconnor.com/maven' + } + maven { + //location of the maven for curios api + url = "https://maven.theillusivec4.top/" + } + maven { + name = "Modrinth" + url = "https://api.modrinth.com/maven" + content { + includeGroup "maven.modrinth" + } } } dependencies { - // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed - // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied. - // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft 'net.minecraftforge:forge:1.19.2-43.1.47' + minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" - // Real mod deobf dependency examples - these get remapped to your current mappings - // compileOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}:api") // Adds JEI API as a compile dependency - // runtimeOnly fg.deobf("mezz.jei:jei-${mc_version}:${jei_version}") // Adds the full JEI mod as a runtime dependency - // implementation fg.deobf("com.tterrag.registrate:Registrate:MC${mc_version}-${registrate_version}") // Adds registrate as a dependency + jarJar(group: 'com.jozufozu.flywheel', name: "flywheel-forge-${flywheel_minecraft_version}", version: '[0.6.8,0.6.9)') { + jarJar.pin(it, project.flywheel_version) + } - // Examples using mod jars from ./libs - // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}") + if (flywheelInWorkspace) { + implementation project(':Flywheel') + } else { + implementation fg.deobf("com.jozufozu.flywheel:flywheel-forge-${flywheel_minecraft_version}:${flywheel_version}") + } - // For more info... - // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html - // http://www.gradle.org/docs/current/userguide/dependency_management.html - - //Flywheel - //Versions: https://maven.tterrag.com/com/jozufozu/flywheel/flywheel-forge-1.19.2/ - implementation fg.deobf("com.jozufozu.flywheel:flywheel-forge-1.19.2:0.6.8-13") + // Prevent Mixin annotation processor from getting into IntelliJ's annotation processor settings + // This allows 'Settings > Build, Execution, and Deployment > Build Tools > Gradle > Build and run using' set to IntelliJ to work correctly + if (System.getProperty('idea.sync.active') != 'true') { + annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" + } +} + +sourceSets.main.resources { + srcDir 'src/generated/resources' + exclude '.cache/' +} +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation +} + +compileJava { + options.compilerArgs = ['-Xdiags:verbose'] } -// Example for how to get properties into the manifest for reading by the runtime.. jar { manifest { attributes([ "Specification-Title": "effortlessbuilding", "Specification-Vendor": "requios", - "Specification-Version": "1", // We are version 1 of ourselves - "Implementation-Title": project.name, + "Specification-Version": "1", + "Implementation-Title": project.jar.baseName, "Implementation-Version": project.jar.archiveVersion, "Implementation-Vendor" :"requios", "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") @@ -163,25 +178,37 @@ jar { } } -// Example configuration to allow publishing using the maven-publish plugin -// This is the preferred method to reobfuscate your jar file +task jarJarRelease { + doLast { + tasks.jarJar { + classifier = '' + } + } + finalizedBy tasks.jarJar +} + +java { + withSourcesJar() + withJavadocJar() +} + jar.finalizedBy('reobfJar') -// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing -// publish.dependsOn('reobfJar') +tasks.jarJar.finalizedBy('reobfJarJar') publishing { publications { mavenJava(MavenPublication) { - artifact jar + artifactId = archivesBaseName + + from components.java + fg.component(it) + jarJar.component(it) } } repositories { - maven { - url "file://${project.projectDir}/mcmodsrepo" + if (project.hasProperty('mavendir')) { + maven { url mavendir } } } } -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation -} diff --git a/gradle.properties b/gradle.properties index 878bf1f..99d343f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,20 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.daemon=false + +mod_version = 3.0 +artifact_minecraft_version = 1.19.2 + +minecraft_version = 1.19.2 +forge_version = 43.1.47 + +forgegradle_version = 5.1.53 +mixingradle_version = 0.7-SNAPSHOT +mixin_version = 0.8.5 +librarian_version = 1.+ +cursegradle_version = 1.4.0 +parchment_version = 2022.11.06 + +flywheel_minecraft_version = 1.19.2 +flywheel_version = 0.6.8.a-14 \ No newline at end of file diff --git a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java index bc3749a..87bf8bb 100644 --- a/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/ClientEvents.java @@ -2,7 +2,6 @@ package nl.requios.effortlessbuilding; import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.vertex.DefaultVertexFormat; -import net.minecraft.ChatFormatting; import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; @@ -13,7 +12,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.InputEvent; @@ -27,12 +25,9 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmode.ModeOptions; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; -import nl.requios.effortlessbuilding.render.BlockPreviews; -import nl.requios.effortlessbuilding.render.RenderHandler; import nl.requios.effortlessbuilding.utilities.ReachHelper; import nl.requios.effortlessbuilding.network.*; import nl.requios.effortlessbuilding.render.BuildRenderTypes; @@ -161,7 +156,7 @@ public class ClientEvents { //QuickReplace toggle if (keyBindings[1].consumeClick()) { - EffortlessBuildingClient.QUICK_REPLACE.toggleQuickReplacing(); + EffortlessBuildingClient.BUILD_SETTINGS.toggleQuickReplace(); } //Radial menu @@ -241,7 +236,7 @@ public class ClientEvents { keyBindings[keybindIndex].getKey().getValue()); } - public static BlockHitResult getLookingAt(Player player) { + public static BlockHitResult getLookingAtFar(Player player) { Level world = player.level; //base distance off of player ability (config) diff --git a/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java b/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java index 19c0261..04ae015 100644 --- a/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java +++ b/src/main/java/nl/requios/effortlessbuilding/CommonEvents.java @@ -17,11 +17,11 @@ import net.minecraftforge.event.level.BlockEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.network.PacketDistributor; -import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.systems.ServerBuildState; import nl.requios.effortlessbuilding.utilities.ReachHelper; import nl.requios.effortlessbuilding.network.AddUndoMessage; import nl.requios.effortlessbuilding.network.ClearUndoMessage; @@ -55,7 +55,7 @@ public class CommonEvents { EffortlessBuilding.DELAYED_BLOCK_PLACER.tick(); } - //Cancel event if necessary. Nothing more, rest is handled on mouse right click + //Cancel event if necessary. Nothing more, rest is handled on mouseclick @SubscribeEvent public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) { if (event.getLevel().isClientSide()) return; //Never called clientside anyway, but just to be sure @@ -65,9 +65,7 @@ public class CommonEvents { //Don't cancel event if our custom logic is breaking blocks if (EffortlessBuilding.SERVER_BLOCK_PLACER.isPlacingOrBreakingBlocks()) return; - BuildModeEnum buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); - - if (buildMode != BuildModeEnum.DISABLED || EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing()) { + if (!ServerBuildState.isLikeVanilla(player)) { //Only cancel if itemblock in hand //Fixed issue with e.g. Create Wrench shift-rightclick disassembling being cancelled. @@ -83,6 +81,7 @@ public class CommonEvents { } } + //Cancel event if necessary. Nothing more, rest is handled on mouseclick @SubscribeEvent public static void onBlockBroken(BlockEvent.BreakEvent event) { if (event.getLevel().isClientSide()) return; @@ -92,10 +91,7 @@ public class CommonEvents { //Don't cancel event if our custom logic is breaking blocks if (EffortlessBuilding.SERVER_BLOCK_PLACER.isPlacingOrBreakingBlocks()) return; - //Cancel event if necessary - //If cant break far then dont cancel event ever - BuildModeEnum buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); - if (buildMode != BuildModeEnum.DISABLED && ReachHelper.canBreakFar(player)) { + if (!ServerBuildState.isLikeVanilla(player) && ReachHelper.canBreakFar(player)) { event.setCanceled(true); } else { //NORMAL mode, let vanilla handle block breaking diff --git a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java index 91b6b47..0a48603 100644 --- a/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java +++ b/src/main/java/nl/requios/effortlessbuilding/EffortlessBuildingClient.java @@ -10,14 +10,14 @@ import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen; import nl.requios.effortlessbuilding.gui.RandomizerBagScreen; import nl.requios.effortlessbuilding.render.BlockPreviews; import nl.requios.effortlessbuilding.systems.BuilderChain; -import nl.requios.effortlessbuilding.systems.QuickReplace; +import nl.requios.effortlessbuilding.systems.BuildSettings; public class EffortlessBuildingClient { public static final BuilderChain BUILDER_CHAIN = new BuilderChain(); public static final BuildModes BUILD_MODES = new BuildModes(); public static final BuildModifiers BUILD_MODIFIERS = new BuildModifiers(); - public static final QuickReplace QUICK_REPLACE = new QuickReplace(); + public static final BuildSettings BUILD_SETTINGS = new BuildSettings(); public static final BlockPreviews BLOCK_PREVIEWS = new BlockPreviews(); public static void onConstructorClient(IEventBus modEventBus, IEventBus forgeEventBus) { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BaseBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BaseBuildMode.java index 77490d2..7cc0f80 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BaseBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BaseBuildMode.java @@ -1,12 +1,6 @@ package nl.requios.effortlessbuilding.buildmode; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; -import nl.requios.effortlessbuilding.utilities.BlockEntry; - -import java.util.List; +import nl.requios.effortlessbuilding.utilities.BlockSet; public abstract class BaseBuildMode implements IBuildMode { @@ -18,7 +12,7 @@ public abstract class BaseBuildMode implements IBuildMode { } @Override - public boolean onClick(List blocks) { + public boolean onClick(BlockSet blocks) { clicks++; return false; } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java index 4065451..f7b87dd 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/BuildModes.java @@ -9,6 +9,7 @@ import net.minecraftforge.api.distmarker.OnlyIn; import nl.requios.effortlessbuilding.network.IsUsingBuildModePacket; import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import nl.requios.effortlessbuilding.utilities.ReachHelper; import java.util.*; @@ -17,14 +18,8 @@ import java.util.*; public class BuildModes { private BuildModeEnum buildMode = BuildModeEnum.DISABLED; - public void findCoordinates(List blocks, Player player, BuildModeEnum buildMode) { + public void findCoordinates(BlockSet blocks, Player player, BuildModeEnum buildMode) { buildMode.instance.findCoordinates(blocks); - - //Limit number of blocks you can place - int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); - while (blocks.size() > limit) { - blocks.remove(blocks.size()-1); - } } public BuildModeEnum getBuildMode() { diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/IBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/IBuildMode.java index 51e41d7..43d4fe5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/IBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/IBuildMode.java @@ -1,12 +1,6 @@ package nl.requios.effortlessbuilding.buildmode; -import net.minecraft.world.entity.player.Player; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; -import nl.requios.effortlessbuilding.utilities.BlockEntry; - -import java.util.List; +import nl.requios.effortlessbuilding.utilities.BlockSet; public interface IBuildMode { @@ -14,7 +8,7 @@ public interface IBuildMode { void initialize(); //Returns if we should place blocks now - boolean onClick(List blocks); + boolean onClick(BlockSet blocks); - void findCoordinates(List blocks); + void findCoordinates(BlockSet blocks); } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java index c57abab..98c190b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ModeOptions.java @@ -1,11 +1,9 @@ package nl.requios.effortlessbuilding.buildmode; import net.minecraft.world.entity.player.Player; -import net.minecraft.ChatFormatting; import nl.requios.effortlessbuilding.ClientEvents; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuildingClient; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; public class ModeOptions { @@ -73,7 +71,7 @@ public class ModeOptions { break; case REPLACE: if (player.level.isClientSide) - EffortlessBuildingClient.QUICK_REPLACE.toggleQuickReplacing(); + EffortlessBuildingClient.BUILD_SETTINGS.toggleQuickReplace(); break; case OPEN_MODIFIER_SETTINGS: if (player.level.isClientSide) diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java index c45bc3c..9d0db46 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/ThreeClicksBuildMode.java @@ -5,6 +5,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.Vec3; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import nl.requios.effortlessbuilding.utilities.ReachHelper; import java.util.ArrayList; @@ -23,7 +24,7 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode { } @Override - public boolean onClick(List blocks) { + public boolean onClick(BlockSet blocks) { super.onClick(blocks); if (clicks == 1) { @@ -35,7 +36,7 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode { return false; } - firstBlockEntry = blocks.get(0); + firstBlockEntry = blocks.getFirstBlockEntry(); } else if (clicks == 2) { //Second click, find second position @@ -57,7 +58,7 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode { } @Override - public void findCoordinates(List blocks) { + public void findCoordinates(BlockSet blocks) { if (clicks == 0) return; if (clicks == 1) { @@ -85,6 +86,8 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode { for (BlockPos pos : getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2)) { blocks.add(new BlockEntry(pos)); } + blocks.firstPos = firstPos; + blocks.lastPos = secondPos; } else { var player = Minecraft.getInstance().player; BlockPos firstPos = firstBlockEntry.blockPos; @@ -118,6 +121,8 @@ public abstract class ThreeClicksBuildMode extends BaseBuildMode { for (BlockPos pos : getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3)) { blocks.add(new BlockEntry(pos)); } + blocks.firstPos = firstPos; + blocks.lastPos = thirdPos; } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java index 4f224f4..239966d 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/TwoClicksBuildMode.java @@ -4,6 +4,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Player; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import nl.requios.effortlessbuilding.utilities.ReachHelper; import java.util.List; @@ -19,7 +20,7 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode { } @Override - public boolean onClick(List blocks) { + public boolean onClick(BlockSet blocks) { super.onClick(blocks); if (clicks == 1) { @@ -31,7 +32,7 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode { return false; } - firstBlockEntry = blocks.get(0); + firstBlockEntry = blocks.getFirstBlockEntry(); } else { //Second click, place blocks clicks = 0; @@ -41,7 +42,7 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode { } @Override - public void findCoordinates(List blocks) { + public void findCoordinates(BlockSet blocks) { if (clicks == 0) return; var player = Minecraft.getInstance().player; @@ -68,6 +69,8 @@ public abstract class TwoClicksBuildMode extends BaseBuildMode { for (BlockPos pos : getAllBlocks(player, x1, y1, z1, x2, y2, z2)) { blocks.add(new BlockEntry(pos)); } + blocks.firstPos = firstPos; + blocks.lastPos = secondPos; } //Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc) diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java index bdfca9d..2f365e4 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Disabled.java @@ -1,9 +1,7 @@ package nl.requios.effortlessbuilding.buildmode.buildmodes; import nl.requios.effortlessbuilding.buildmode.IBuildMode; -import nl.requios.effortlessbuilding.utilities.BlockEntry; - -import java.util.List; +import nl.requios.effortlessbuilding.utilities.BlockSet; public class Disabled implements IBuildMode { @@ -13,12 +11,12 @@ public class Disabled implements IBuildMode { } @Override - public boolean onClick(List blocks) { + public boolean onClick(BlockSet blocks) { return true; } @Override - public void findCoordinates(List blocks) { + public void findCoordinates(BlockSet blocks) { //Do nothing } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java index d6ec7d9..66d7eda 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/buildmodes/Single.java @@ -1,9 +1,7 @@ package nl.requios.effortlessbuilding.buildmode.buildmodes; import nl.requios.effortlessbuilding.buildmode.IBuildMode; -import nl.requios.effortlessbuilding.utilities.BlockEntry; - -import java.util.List; +import nl.requios.effortlessbuilding.utilities.BlockSet; public class Single implements IBuildMode { @@ -13,12 +11,12 @@ public class Single implements IBuildMode { } @Override - public boolean onClick(List blocks) { + public boolean onClick(BlockSet blocks) { return true; } @Override - public void findCoordinates(List blocks) { + public void findCoordinates(BlockSet blocks) { //Do nothing } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java index 61ac582..6b942b0 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BuildModifiers.java @@ -20,9 +20,9 @@ import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.systems.DelayedBlockPlacer; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; -import nl.requios.effortlessbuilding.render.BlockPreviews; import java.util.ArrayList; import java.util.Collections; @@ -30,7 +30,7 @@ import java.util.List; public class BuildModifiers { - public void findCoordinates(List blocks, LocalPlayer player, ModifierSettingsManager.ModifierSettings modifierSettings) { + public void findCoordinates(BlockSet blocks, LocalPlayer player, ModifierSettingsManager.ModifierSettings modifierSettings) { } @@ -115,7 +115,7 @@ public class BuildModifiers { //add to undo stack BlockPos firstPos = startCoordinates.get(0); BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1); - UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, firstPos, secondPos)); + UndoRedo.addUndo(player, new UndoRedoBlockSet(coordinates, previousBlockStates, newBlockStates, firstPos, secondPos)); } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java index 81768f2..3f7f863 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedo.java @@ -6,16 +6,13 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; -import net.minecraft.core.Direction; import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; import net.minecraft.server.level.ServerLevel; import nl.requios.effortlessbuilding.CommonConfig; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.utilities.FixedStack; import nl.requios.effortlessbuilding.utilities.InventoryHelper; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; -import nl.requios.effortlessbuilding.render.BlockPreviews; import java.util.*; @@ -23,14 +20,14 @@ public class UndoRedo { //Undo and redo stacks per player //Gets added to twice in singleplayer (server and client) if not careful. So separate stacks. - private static final Map> undoStacksClient = new HashMap<>(); - private static final Map> undoStacksServer = new HashMap<>(); - private static final Map> redoStacksClient = new HashMap<>(); - private static final Map> redoStacksServer = new HashMap<>(); + private static final Map> undoStacksClient = new HashMap<>(); + private static final Map> undoStacksServer = new HashMap<>(); + private static final Map> redoStacksClient = new HashMap<>(); + private static final Map> redoStacksServer = new HashMap<>(); //add to undo stack - public static void addUndo(Player player, BlockSet blockSet) { - Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; + public static void addUndo(Player player, UndoRedoBlockSet blockSet) { + Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; //Assert coordinates is as long as previous and new blockstate lists if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() || @@ -50,35 +47,35 @@ public class UndoRedo { //If no stack exists, make one if (!undoStacks.containsKey(player.getUUID())) { - undoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); + undoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); } undoStacks.get(player.getUUID()).push(blockSet); } - private static void addRedo(Player player, BlockSet blockSet) { - Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; + private static void addRedo(Player player, UndoRedoBlockSet blockSet) { + Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; //(No asserts necessary, it's private) //If no stack exists, make one if (!redoStacks.containsKey(player.getUUID())) { - redoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); + redoStacks.put(player.getUUID(), new FixedStack<>(new UndoRedoBlockSet[CommonConfig.survivalBalancers.undoStackSize.get()])); } redoStacks.get(player.getUUID()).push(blockSet); } public static boolean undo(Player player) { - Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; + Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; if (!undoStacks.containsKey(player.getUUID())) return false; - FixedStack undoStack = undoStacks.get(player.getUUID()); + FixedStack undoStack = undoStacks.get(player.getUUID()); if (undoStack.isEmpty()) return false; - BlockSet blockSet = undoStack.pop(); + UndoRedoBlockSet blockSet = undoStack.pop(); List coordinates = blockSet.getCoordinates(); List previousBlockStates = blockSet.getPreviousBlockStates(); List newBlockStates = blockSet.getNewBlockStates(); @@ -129,15 +126,15 @@ public class UndoRedo { } public static boolean redo(Player player) { - Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; + Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; if (!redoStacks.containsKey(player.getUUID())) return false; - FixedStack redoStack = redoStacks.get(player.getUUID()); + FixedStack redoStack = redoStacks.get(player.getUUID()); if (redoStack.isEmpty()) return false; - BlockSet blockSet = redoStack.pop(); + UndoRedoBlockSet blockSet = redoStack.pop(); List coordinates = blockSet.getCoordinates(); List previousBlockStates = blockSet.getPreviousBlockStates(); List newBlockStates = blockSet.getNewBlockStates(); @@ -187,8 +184,8 @@ public class UndoRedo { } public static void clear(Player player) { - Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; - Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; + Map> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; + Map> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer; if (undoStacks.containsKey(player.getUUID())) { undoStacks.get(player.getUUID()).clear(); } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedoBlockSet.java similarity index 80% rename from src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java rename to src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedoBlockSet.java index a145646..3fac572 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmodifier/BlockSet.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmodifier/UndoRedoBlockSet.java @@ -2,20 +2,19 @@ package nl.requios.effortlessbuilding.buildmodifier; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; import java.util.List; //Used only for Undo -public class BlockSet { +public class UndoRedoBlockSet { private final List coordinates; private final List previousBlockStates; private final List newBlockStates; private final BlockPos firstPos; private final BlockPos secondPos; - public BlockSet(List coordinates, List previousBlockStates, List newBlockStates, - BlockPos firstPos, BlockPos secondPos) { + public UndoRedoBlockSet(List coordinates, List previousBlockStates, List newBlockStates, + BlockPos firstPos, BlockPos secondPos) { this.coordinates = coordinates; this.previousBlockStates = previousBlockStates; this.newBlockStates = newBlockStates; diff --git a/src/main/java/nl/requios/effortlessbuilding/compatibility/CompatHelper.java b/src/main/java/nl/requios/effortlessbuilding/compatibility/CompatHelper.java index 51ec9bf..8e032d6 100644 --- a/src/main/java/nl/requios/effortlessbuilding/compatibility/CompatHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/compatibility/CompatHelper.java @@ -1,10 +1,14 @@ package nl.requios.effortlessbuilding.compatibility; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import nl.requios.effortlessbuilding.create.foundation.item.ItemHelper; import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; public class CompatHelper { @@ -64,4 +68,21 @@ public class CompatHelper { return ItemStack.EMPTY; } + public static boolean containsBlock(ItemStack stack, Block block) { + if (stack == null || stack.isEmpty() || !isItemBlockProxy(stack)) { + return block == null || block == Blocks.AIR; + } + + if (stack.getItem() instanceof BlockItem) { + return ((BlockItem) stack.getItem()).getBlock() == block; + } + + if (stack.getItem() instanceof AbstractRandomizerBagItem randomizerBagItem) { + IItemHandler bagInventory = randomizerBagItem.getBagInventory(stack); + ItemStack firstMatch = ItemHelper.findFirstMatch(bagInventory, s -> s.getItem() instanceof BlockItem); + return firstMatch != null && !firstMatch.isEmpty(); + } + return false; + } + } diff --git a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java index 14415e6..7ac0a24 100644 --- a/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/create/foundation/utility/BlockHelper.java @@ -32,6 +32,7 @@ import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Material; import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.BlockSnapshot; import net.minecraftforge.event.level.BlockEvent; import javax.annotation.Nullable; @@ -144,7 +145,7 @@ public class BlockHelper { destroyBlockAs(world, pos, null, ItemStack.EMPTY, effectChance, droppedItemCallback); } - public static void destroyBlockAs(Level world, BlockPos pos, @Nullable Player player, ItemStack usedTool, + public static boolean destroyBlockAs(Level world, BlockPos pos, @Nullable Player player, ItemStack usedTool, float effectChance, Consumer droppedItemCallback) { FluidState fluidState = world.getFluidState(pos); BlockState state = world.getBlockState(pos); @@ -157,7 +158,7 @@ public class BlockHelper { BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, pos, state, player); MinecraftForge.EVENT_BUS.post(event); if (event.isCanceled()) - return; + return false; if (event.getExpToDrop() > 0 && world instanceof ServerLevel) state.getBlock() @@ -178,19 +179,20 @@ public class BlockHelper { if (state.getBlock() instanceof IceBlock && usedTool.getEnchantmentLevel(Enchantments.SILK_TOUCH) == 0) { if (world.dimensionType() .ultraWarm()) - return; + return false; Material material = world.getBlockState(pos.below()) .getMaterial(); if (material.blocksMotion() || material.isLiquid()) world.setBlockAndUpdate(pos, Blocks.WATER.defaultBlockState()); - return; + return true; } state.spawnAfterBreak((ServerLevel) world, pos, ItemStack.EMPTY, true); } world.setBlockAndUpdate(pos, fluidState.createLegacyBlock()); + return true; } public static boolean isSolidWall(BlockGetter reader, BlockPos fromPos, Direction toDirection) { @@ -223,7 +225,7 @@ public class BlockHelper { .getBlock(), target.below()); } - public static void placeSchematicBlock(Level world, BlockState state, BlockPos target, ItemStack stack, + public static boolean placeSchematicBlock(Level world, Player player, BlockState state, BlockPos target, ItemStack stack, @Nullable CompoundTag data) { BlockEntity existingTile = world.getBlockEntity(target); @@ -253,7 +255,7 @@ public class BlockHelper { 0.0D, 0.0D, 0.0D); } Block.dropResources(state, world, target); - return; + return true; } if (state.getBlock() instanceof BaseRailBlock) { @@ -287,6 +289,7 @@ public class BlockHelper { .setPlacedBy(world, target, state, null, stack); } catch (Exception e) { } + return true; } public static double getBounceMultiplier(Block block) { diff --git a/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java b/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java index 272f573..434c5f2 100644 --- a/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java +++ b/src/main/java/nl/requios/effortlessbuilding/item/AbstractRandomizerBagItem.java @@ -23,7 +23,6 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.systems.ServerBuildState; import nl.requios.effortlessbuilding.capability.ItemHandlerCapabilityProvider; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @@ -133,7 +132,7 @@ public abstract class AbstractRandomizerBagItem extends Item { if (world.isClientSide) return InteractionResult.SUCCESS; //Only place manually if in normal vanilla mode - if (ServerBuildState.isUsingBuildMode(player) || ServerBuildState.isQuickReplacing(player)) { + if (!ServerBuildState.isLikeVanilla(player)) { return InteractionResult.FAIL; } diff --git a/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java b/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java index 6e5e21c..209aa9d 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/AddUndoMessage.java @@ -5,14 +5,13 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.entity.player.Player; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.network.NetworkEvent; import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.buildmodifier.BlockSet; +import nl.requios.effortlessbuilding.buildmodifier.UndoRedoBlockSet; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import java.util.ArrayList; @@ -84,7 +83,7 @@ public class AddUndoMessage { Player player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx); //Add to undo stack clientside //Only the appropriate player that needs to add this to the undo stack gets this message - UndoRedo.addUndo(player, new BlockSet( + UndoRedo.addUndo(player, new UndoRedoBlockSet( new ArrayList() {{ add(message.getCoordinate()); }}, diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java b/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java index 25bc353..4a30530 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ServerBreakBlocksPacket.java @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import java.util.List; import java.util.function.Supplier; @@ -14,25 +15,24 @@ import java.util.function.Supplier; */ public class ServerBreakBlocksPacket { - private List blocks; + private BlockSet blocks; public ServerBreakBlocksPacket() {} - public ServerBreakBlocksPacket(List blocks) { + public ServerBreakBlocksPacket(BlockSet blocks) { this.blocks = blocks; } public static void encode(ServerBreakBlocksPacket message, FriendlyByteBuf buf) { - buf.writeCollection(message.blocks, BlockEntry::encode); + BlockSet.encode(buf, message.blocks); } public static ServerBreakBlocksPacket decode(FriendlyByteBuf buf) { ServerBreakBlocksPacket message = new ServerBreakBlocksPacket(); - message.blocks = buf.readList(BlockEntry::decode); + message.blocks = BlockSet.decode(buf); return message; } - public static class Handler { public static void handle(ServerBreakBlocksPacket message, Supplier ctx) { ctx.get().enqueueWork(() -> { diff --git a/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java b/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java index 03633c2..cc92680 100644 --- a/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java +++ b/src/main/java/nl/requios/effortlessbuilding/network/ServerPlaceBlocksPacket.java @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import java.util.List; import java.util.function.Supplier; @@ -14,25 +15,24 @@ import java.util.function.Supplier; */ public class ServerPlaceBlocksPacket { - private List blocks; + private BlockSet blocks; public ServerPlaceBlocksPacket() {} - public ServerPlaceBlocksPacket(List blocks) { + public ServerPlaceBlocksPacket(BlockSet blocks) { this.blocks = blocks; } public static void encode(ServerPlaceBlocksPacket message, FriendlyByteBuf buf) { - buf.writeCollection(message.blocks, BlockEntry::encode); + BlockSet.encode(buf, message.blocks); } public static ServerPlaceBlocksPacket decode(FriendlyByteBuf buf) { ServerPlaceBlocksPacket message = new ServerPlaceBlocksPacket(); - message.blocks = buf.readList(BlockEntry::decode); + message.blocks = BlockSet.decode(buf); return message; } - public static class Handler { public static void handle(ServerPlaceBlocksPacket message, Supplier ctx) { ctx.get().enqueueWork(() -> { diff --git a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java index 903043e..e25ad8b 100644 --- a/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java +++ b/src/main/java/nl/requios/effortlessbuilding/render/BlockPreviews.java @@ -1,15 +1,8 @@ package nl.requios.effortlessbuilding.render; -import net.minecraft.network.chat.Component; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import net.minecraft.core.BlockPos; -import net.minecraft.world.phys.BlockHitResult; import net.minecraft.util.Mth; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; @@ -17,20 +10,17 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import nl.requios.effortlessbuilding.*; import nl.requios.effortlessbuilding.buildmode.BuildModeEnum; -import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; -import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.create.AllSpecialTextures; import nl.requios.effortlessbuilding.create.CreateClient; import nl.requios.effortlessbuilding.create.foundation.utility.Color; -import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.systems.BuilderChain; import nl.requios.effortlessbuilding.utilities.BlockEntry; -import nl.requios.effortlessbuilding.utilities.ReachHelper; -import nl.requios.effortlessbuilding.utilities.SurvivalHelper; +import nl.requios.effortlessbuilding.utilities.BlockSet; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; @OnlyIn(Dist.CLIENT) public class BlockPreviews { @@ -69,16 +59,15 @@ public class BlockPreviews { !ClientConfig.visuals.alwaysShowBlockPreview.get()) return; var blocks = EffortlessBuildingClient.BUILDER_CHAIN.getBlocks(); - var state = EffortlessBuildingClient.BUILDER_CHAIN.getState(); - if (blocks.size() == 0) return; - var coordinates = EffortlessBuildingClient.BUILDER_CHAIN.getCoordinates(); + var coordinates = blocks.getCoordinates(); + var state = EffortlessBuildingClient.BUILDER_CHAIN.getState(); //Dont fade out the outline if we are still determining where to place //Every outline with same ID will not fade out (because it gets replaced) Object outlineID = "single"; - if (blocks.size() > 1) outlineID = blocks.get(0).blockPos; + if (blocks.size() > 1) outlineID = blocks.firstPos; if (state != BuilderChain.State.BREAKING) { //Use fancy shader if config allows, otherwise outlines @@ -138,57 +127,44 @@ public class BlockPreviews { } public void drawOutlinesIfNoBlockInHand(Player player) { - ItemStack mainhand = player.getMainHandItem(); - HitResult lookingAt = ClientEvents.getLookingAt(player); - if (EffortlessBuildingClient.BUILD_MODES.getBuildMode() == BuildModeEnum.DISABLED) - lookingAt = Minecraft.getInstance().hitResult; + var builderChain = EffortlessBuildingClient.BUILDER_CHAIN; + if (builderChain.isBlockInHand()) return; + if (builderChain.getState() != BuilderChain.State.IDLE) return; - boolean noBlockInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand)); - if (!noBlockInHand) return; + var blocks = new ArrayList<>(builderChain.getBlocks().values()); + if (blocks.size() == 0) return; - //Draw outlines if no block in hand - //Find proper raytrace: either normal range or increased range depending on canBreakFar - HitResult objectMouseOver = Minecraft.getInstance().hitResult; - HitResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver; + //Only render first outline if further than normal reach + var lookingAtNear = Minecraft.getInstance().hitResult; + if (lookingAtNear != null && lookingAtNear.getType() == HitResult.Type.BLOCK) + blocks.remove(0); - if (player.isCreative() && breakingRaytrace != null && breakingRaytrace.getType() == HitResult.Type.BLOCK) { - BlockHitResult blockBreakingRaytrace = (BlockHitResult) breakingRaytrace; - List breakCoordinates = BuildModifiers.findCoordinates(player, blockBreakingRaytrace.getBlockPos()); + //Only render outlines if there is a block, like vanilla + blocks.removeIf(blockEntry -> blockEntry.existingBlockState == null || + blockEntry.existingBlockState.isAir() || + blockEntry.existingBlockState.getMaterial().isLiquid()); - //Only render first outline if further than normal reach - if (objectMouseOver != null && objectMouseOver.getType() == HitResult.Type.BLOCK) - breakCoordinates.remove(0); - - breakCoordinates.removeIf(pos -> { - BlockState blockState = player.level.getBlockState(pos); - if (blockState.isAir() || blockState.getMaterial().isLiquid()) return true; - return !SurvivalHelper.canBreak(player.level, player, pos); - }); - - if (!breakCoordinates.isEmpty()) { - CreateClient.OUTLINER.showCluster("break", breakCoordinates) - .disableNormals() - .lineWidth(1 / 64f) - .colored(0x222222); - } + if (!blocks.isEmpty()) { + var coordinates = blocks.stream().map(blockEntry -> blockEntry.blockPos).collect(Collectors.toList()); + CreateClient.OUTLINER.showCluster("break", coordinates) + .disableNormals() + .lineWidth(1 / 64f) + .colored(0x222222); } } - protected void renderBlockPreviews(List blocks, boolean breaking, float dissolve) { - - var firstPos = blocks.get(0).blockPos; - var lastPos = blocks.get(blocks.size() - 1).blockPos; + protected void renderBlockPreviews(BlockSet blocks, boolean breaking, float dissolve) { for (BlockEntry blockEntry : blocks) { - renderBlockPreview(blockEntry, breaking, dissolve, firstPos, lastPos); + renderBlockPreview(blockEntry, breaking, dissolve, blocks.firstPos, blocks.lastPos); } } protected void renderBlockPreview(BlockEntry blockEntry, boolean breaking, float dissolve, BlockPos firstPos, BlockPos lastPos) { - if (blockEntry.blockState == null) return; + if (blockEntry.newBlockState == null) return; var blockPos = blockEntry.blockPos; - var blockState = blockEntry.blockState; + var blockState = blockEntry.newBlockState; float scale = 0.5f; float alpha = 0.7f; @@ -247,22 +223,22 @@ public class BlockPreviews { return (ay * t3) + (by * t2) + (cy * t) + 0; } - public void onBlocksPlaced(List blocks) { + public void onBlocksPlaced(BlockSet blocks) { if (!ClientConfig.visuals.showBlockPreviews.get()) return; if (blocks.size() <= 1 || blocks.size() > ClientConfig.visuals.maxBlockPreviews.get()) return; - placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, false, new ArrayList<>(blocks))); + placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, false, new BlockSet(blocks))); - CreateClient.OUTLINER.keep(blocks.get(0).blockPos, CommonConfig.visuals.appearAnimationLength.get()); + CreateClient.OUTLINER.keep(blocks.firstPos, CommonConfig.visuals.appearAnimationLength.get()); } - public void onBlocksBroken(List blocks) { + public void onBlocksBroken(BlockSet blocks) { if (!ClientConfig.visuals.showBlockPreviews.get()) return; if (blocks.size() <= 1 || blocks.size() > ClientConfig.visuals.maxBlockPreviews.get()) return; - placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, true, new ArrayList<>(blocks))); + placedBlocksList.add(new PlacedBlocksEntry(ClientEvents.ticksInGame, true, new BlockSet(blocks))); - CreateClient.OUTLINER.keep(blocks.get(0).blockPos, CommonConfig.visuals.breakAnimationLength.get()); + CreateClient.OUTLINER.keep(blocks.firstPos, CommonConfig.visuals.breakAnimationLength.get()); } private void sortOnDistanceToPlayer(List coordinates, Player player) { @@ -279,9 +255,9 @@ public class BlockPreviews { public static class PlacedBlocksEntry { float time; boolean breaking; - List blocks; + BlockSet blocks; - public PlacedBlocksEntry(float time, boolean breaking, List blocks) { + public PlacedBlocksEntry(float time, boolean breaking, BlockSet blocks) { this.time = time; this.breaking = breaking; this.blocks = blocks; diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java new file mode 100644 index 0000000..08547a1 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuildSettings.java @@ -0,0 +1,67 @@ +package nl.requios.effortlessbuilding.systems; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.network.IsQuickReplacingPacket; +import nl.requios.effortlessbuilding.network.PacketHandler; + +@OnlyIn(Dist.CLIENT) +public class BuildSettings { + public enum ReplaceMode { + ONLY_AIR, + SOLID_AND_AIR, + SOLID_ONLY, + FILTERED_BY_OFFHAND + } + + private boolean quickReplace = false; + public ReplaceMode replaceMode = ReplaceMode.ONLY_AIR; + private boolean replaceTileEntities; + + public boolean isQuickReplacing() { + return quickReplace; + } + + public void toggleQuickReplace() { + setQuickReplace(!quickReplace); + } + + public void setQuickReplace(boolean quickReplace) { + this.quickReplace = quickReplace; + + EffortlessBuilding.log(Minecraft.getInstance().player, "Set " + ChatFormatting.GOLD + "Quick Replace " + + ChatFormatting.RESET + (this.quickReplace ? "on" : "off")); + PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(this.quickReplace)); + } + + public void setReplaceMode(ReplaceMode replaceMode) { + this.replaceMode = replaceMode; + } + + public void setReplaceTileEntities(boolean replaceTileEntities) { + this.replaceTileEntities = replaceTileEntities; + } + + public boolean shouldReplaceAir() { + return replaceMode == ReplaceMode.ONLY_AIR || replaceMode == ReplaceMode.SOLID_AND_AIR; + } + + public boolean shouldReplaceSolid() { + return replaceMode == ReplaceMode.SOLID_ONLY || replaceMode == ReplaceMode.SOLID_AND_AIR; + } + + public boolean shouldReplaceFiltered() { + return replaceMode == ReplaceMode.FILTERED_BY_OFFHAND; + } + + public boolean shouldReplaceTileEntities() { + return replaceTileEntities; + } + + public boolean shouldOffsetStartPosition() { + return shouldReplaceSolid() || shouldReplaceFiltered(); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java index c848459..359ee1e 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderChain.java @@ -1,9 +1,7 @@ package nl.requios.effortlessbuilding.systems; import net.minecraft.client.Minecraft; -import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; @@ -12,10 +10,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; @@ -29,11 +25,10 @@ import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.network.ServerBreakBlocksPacket; import nl.requios.effortlessbuilding.network.ServerPlaceBlocksPacket; -import nl.requios.effortlessbuilding.utilities.BlockEntry; -import nl.requios.effortlessbuilding.utilities.ReachHelper; -import nl.requios.effortlessbuilding.utilities.SurvivalHelper; +import nl.requios.effortlessbuilding.utilities.*; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; // Receives block placed events, then finds additional blocks we want to place through various systems, @@ -42,10 +37,11 @@ import java.util.List; @OnlyIn(Dist.CLIENT) public class BuilderChain { - private final List blocks = new ArrayList<>(); - private final List coordinates = new ArrayList<>(); - private int soundTime = 0; + private final BlockSet blocks = new BlockSet(); + private boolean blockInHand; + private boolean lookingAtInteractiveObject; private Item previousHeldItem; + private int soundTime = 0; public enum State { IDLE, @@ -56,6 +52,7 @@ public class BuilderChain { private State state = State.IDLE; public void onRightClick() { + if (lookingAtInteractiveObject) return; var player = Minecraft.getInstance().player; if (state == State.BREAKING) { @@ -63,9 +60,6 @@ public class BuilderChain { return; } - //Check if we have a BlockItem in hand - var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND); - boolean blockInHand = CompatHelper.isItemBlockProxy(itemStack); if (!blockInHand) { if (state == State.PLACING) cancel(); return; @@ -83,13 +77,15 @@ public class BuilderChain { if (!blocks.isEmpty()) { EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksPlaced(blocks); - playSoundIfFurtherThanNormal(player, blocks.get(0), false); + BlockUtilities.playSoundIfFurtherThanNormal(player, blocks.getLastBlockEntry(), false); + player.swing(InteractionHand.MAIN_HAND); PacketHandler.INSTANCE.sendToServer(new ServerPlaceBlocksPacket(blocks)); } } } public void onLeftClick() { + if (lookingAtInteractiveObject) return; var player = Minecraft.getInstance().player; if (state == State.PLACING) { @@ -114,53 +110,55 @@ public class BuilderChain { if (!blocks.isEmpty()) { EffortlessBuildingClient.BLOCK_PREVIEWS.onBlocksBroken(blocks); - playSoundIfFurtherThanNormal(player, blocks.get(0), true); + BlockUtilities.playSoundIfFurtherThanNormal(player, blocks.getLastBlockEntry(), true); + player.swing(InteractionHand.MAIN_HAND); PacketHandler.INSTANCE.sendToServer(new ServerBreakBlocksPacket(blocks)); } } } public void onTick() { - var previousCoordinates = new ArrayList<>(coordinates); + var previousCoordinates = new HashSet<>(blocks.getCoordinates()); blocks.clear(); var mc = Minecraft.getInstance(); var player = mc.player; - var level = mc.level; + var world = mc.level; //Check if we have a BlockItem in hand var itemStack = player.getItemInHand(InteractionHand.MAIN_HAND); - boolean blockInHand = CompatHelper.isItemBlockProxy(itemStack); + blockInHand = CompatHelper.isItemBlockProxy(itemStack); - //Cancel placing as soon as we aren't holding a block anymore -// if (!blockInHand && state == State.PLACING) { -// state = State.IDLE; -// } + lookingAtInteractiveObject = BlockUtilities.determineIfLookingAtInteractiveObject(mc, world); + if (lookingAtInteractiveObject) return; - var modifierSettings = ModifierSettingsManager.getModifierSettings(player); var buildMode = EffortlessBuildingClient.BUILD_MODES.getBuildMode(); + var modifierSettings = ModifierSettingsManager.getModifierSettings(player); - - BlockHitResult lookingAt = ClientEvents.getLookingAt(player); - BlockEntry startEntry = findStartPosition(player, lookingAt); - if (startEntry != null) { - blocks.add(startEntry); + if (state == State.IDLE) { + //Find start position + BlockHitResult lookingAt = ClientEvents.getLookingAtFar(player); + BlockEntry startEntry = findStartPosition(player, lookingAt); + if (startEntry != null) { + blocks.add(startEntry); + blocks.firstPos = startEntry.blockPos; + blocks.lastPos = startEntry.blockPos; + } } EffortlessBuildingClient.BUILD_MODES.findCoordinates(blocks, player, buildMode); EffortlessBuildingClient.BUILD_MODIFIERS.findCoordinates(blocks, player, modifierSettings); - removeDuplicateCoordinates(); + BuilderFilter.filterOnCoordinates(blocks, player); - coordinates.clear(); - for (BlockEntry blockEntry : blocks) { - coordinates.add(blockEntry.blockPos); - } + findExistingBlockStates(world); + BuilderFilter.filterOnExistingBlockStates(blocks, player); - findBlockStates(player, itemStack); + findNewBlockStates(player, itemStack); + BuilderFilter.filterOnNewBlockStates(blocks, player); //Check if any changes are made - if (previousHeldItem != itemStack.getItem() || !previousCoordinates.equals(coordinates)) { + if (previousHeldItem != itemStack.getItem() || !previousCoordinates.equals(blocks.getCoordinates())) { onBlocksChanged(player); } @@ -176,9 +174,9 @@ public class BuilderChain { if (blocks.size() > 1 && soundTime < ClientEvents.ticksInGame) { soundTime = ClientEvents.ticksInGame; - var firstBlockState = blocks.get(0).blockState; - if (firstBlockState != null) { - SoundType soundType = firstBlockState.getBlock().getSoundType(firstBlockState, player.level, blocks.get(0).blockPos, player); + if (blocks.getLastBlockEntry() != null && blocks.getLastBlockEntry().newBlockState != null) { + var lastBlockState = blocks.getLastBlockEntry().newBlockState; + SoundType soundType = lastBlockState.getBlock().getSoundType(lastBlockState, player.level, blocks.lastPos, player); SoundEvent soundEvent = state == BuilderChain.State.BREAKING ? soundType.getBreakSound() : soundType.getPlaceSound(); player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.3f, 0.8f); } @@ -192,34 +190,45 @@ public class BuilderChain { Minecraft.getInstance().player.playSound(SoundEvents.UI_TOAST_OUT, 4, 1); } - private BlockEntry findStartPosition(Player player, BlockHitResult lookingAt) { - if (lookingAt == null || lookingAt.getType() == HitResult.Type.MISS) return null; + private BlockEntry findStartPosition(Player player, BlockHitResult lookingAtFar) { + if (lookingAtFar == null || lookingAtFar.getType() == HitResult.Type.MISS) return null; - var startPos = lookingAt.getBlockPos(); + var startPos = lookingAtFar.getBlockPos(); //Check if out of reach int maxReach = ReachHelper.getMaxReach(player); if (player.blockPosition().distSqr(startPos) > maxReach * maxReach) return null; + //TODO we are always at IDLE state here, find another way to check if we are breaking if (state != State.BREAKING) { //Offset in direction of sidehit if not quickreplace and not replaceable - boolean isQuickReplacing = EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing(); + boolean shouldOffsetStartPosition = EffortlessBuildingClient.BUILD_SETTINGS.shouldOffsetStartPosition(); boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable(); boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos); - if (!isQuickReplacing && !replaceable && !becomesDoubleSlab) { - startPos = startPos.relative(lookingAt.getDirection()); + if (!shouldOffsetStartPosition && !replaceable && !becomesDoubleSlab) { + startPos = startPos.relative(lookingAtFar.getDirection()); } //Get under tall grass and other replaceable blocks - if (isQuickReplacing && replaceable) { + if (shouldOffsetStartPosition && replaceable) { startPos = startPos.below(); } + } else { + //Do not break far if we are not allowed to + if (!ReachHelper.canBreakFar(player)) { + boolean startPosIsNear = false; + var lookingAtNear = Minecraft.getInstance().hitResult; + if (lookingAtNear != null && lookingAtNear.getType() == HitResult.Type.BLOCK) { + startPosIsNear = ((BlockHitResult) lookingAtNear).getBlockPos().equals(startPos); + } + if (!startPosIsNear) return null; + } } var blockEntry = new BlockEntry(startPos); //Place upside-down stairs if we aim high at block - var hitVec = lookingAt.getLocation(); + var hitVec = lookingAtFar.getLocation(); //Format hitvec to 0.x hitVec = new Vec3(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z))); if (hitVec.y > 0.5) { @@ -229,32 +238,19 @@ public class BuilderChain { return blockEntry; } - private void removeDuplicateCoordinates() { - for (int i = 0; i < blocks.size(); i++) { - BlockEntry blockEntry = blocks.get(i); - for (int j = i + 1; j < blocks.size(); j++) { - BlockEntry blockEntry2 = blocks.get(j); - if (blockEntry.blockPos.equals(blockEntry2.blockPos)) { - blocks.remove(j); - j--; - } - } + private void findExistingBlockStates(Level world) { + for (BlockEntry blockEntry : blocks) { + blockEntry.existingBlockState = world.getBlockState(blockEntry.blockPos); } } - private void findBlockStates(Player player, ItemStack itemStack) { - - if (state == State.BREAKING) { - for (BlockEntry blockEntry : blocks) { - blockEntry.blockState = Minecraft.getInstance().level.getBlockState(blockEntry.blockPos); - } - return; - } + private void findNewBlockStates(Player player, ItemStack itemStack) { + if (state == State.BREAKING) return; if (itemStack.getItem() instanceof BlockItem) { for (BlockEntry blockEntry : blocks) { - blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemStack, blockEntry); + blockEntry.newBlockState = BlockUtilities.getBlockState(player, InteractionHand.MAIN_HAND, itemStack, blockEntry); } } else if (CompatHelper.isItemBlockProxy(itemStack, false)) { @@ -263,44 +259,25 @@ public class BuilderChain { for (BlockEntry blockEntry : blocks) { ItemStack itemBlockStack = CompatHelper.getItemBlockFromStack(itemStack); if (itemBlockStack == null || itemBlockStack.isEmpty()) continue; - blockEntry.blockState = getBlockState(player, InteractionHand.MAIN_HAND, itemBlockStack, blockEntry); + blockEntry.newBlockState = BlockUtilities.getBlockState(player, InteractionHand.MAIN_HAND, itemBlockStack, blockEntry); } } } - public BlockState getBlockState(Player player, InteractionHand hand, ItemStack blockItemStack, BlockEntry blockEntry) { - Block block = Block.byItem(blockItemStack.getItem()); - //TODO convert lookingAt hitvec to relative hitvec - var blockHitResult = new BlockHitResult(Vec3.ZERO, Direction.UP, blockEntry.blockPos, false); - return block.getStateForPlacement(new BlockPlaceContext(player, hand, blockItemStack, blockHitResult)); - } - - private void playSoundIfFurtherThanNormal(Player player, BlockEntry blockEntry, boolean breaking) { - - if (Minecraft.getInstance().hitResult != null && Minecraft.getInstance().hitResult.getType() == HitResult.Type.BLOCK) - return; - - if (blockEntry == null || blockEntry.blockState == null) - return; - - SoundType soundType = blockEntry.blockState.getBlock().getSoundType(blockEntry.blockState, player.level, blockEntry.blockPos, player); - SoundEvent soundEvent = breaking ? soundType.getBreakSound() : soundType.getPlaceSound(); - player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.6f, soundType.getPitch()); - } - - private void swingHand(Player player, InteractionHand hand) { - player.swing(hand); - } public State getState() { return state; } - public List getBlocks() { + public BlockSet getBlocks() { return blocks; } - public List getCoordinates() { - return coordinates; + public boolean isBlockInHand() { + return blockInHand; + } + + public boolean isLookingAtInteractiveObject() { + return lookingAtInteractiveObject; } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/BuilderFilter.java b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderFilter.java new file mode 100644 index 0000000..e752ceb --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/systems/BuilderFilter.java @@ -0,0 +1,57 @@ +package nl.requios.effortlessbuilding.systems; + +import net.minecraft.world.entity.player.Player; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import nl.requios.effortlessbuilding.EffortlessBuildingClient; +import nl.requios.effortlessbuilding.compatibility.CompatHelper; +import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; +import nl.requios.effortlessbuilding.utilities.PlaceChecker; + +@OnlyIn(Dist.CLIENT) +public class BuilderFilter { + public static void filterOnCoordinates(BlockSet blocks, Player player) { + + } + + public static void filterOnExistingBlockStates(BlockSet blocks, Player player) { + var buildSettings = EffortlessBuildingClient.BUILD_SETTINGS; + boolean placing = EffortlessBuildingClient.BUILDER_CHAIN.getState() == BuilderChain.State.PLACING; + + var iter = blocks.entrySet().iterator(); + while (iter.hasNext()) { + var blockEntry = iter.next().getValue(); + var blockState = blockEntry.existingBlockState; + boolean remove = false; + + if (!buildSettings.shouldReplaceTileEntities() && blockState.hasBlockEntity()) remove = true; + + if (placing) { + if (!buildSettings.shouldReplaceAir() && blockState.isAir()) remove = true; + boolean isSolid = blockState.isRedstoneConductor(player.level, blockEntry.blockPos); + if (!buildSettings.shouldReplaceSolid() && isSolid) remove = true; + } + + if (buildSettings.shouldReplaceFiltered()) { + var offhandItem = player.getOffhandItem(); + if (!CompatHelper.containsBlock(offhandItem, blockState.getBlock())) remove = true; + } + + if (remove) iter.remove(); + } + } + + public static void filterOnNewBlockStates(BlockSet blocks, Player player) { + + var iter = blocks.entrySet().iterator(); + while (iter.hasNext()) { + var blockEntry = iter.next().getValue(); + boolean remove = false; + + if (!PlaceChecker.shouldPlaceBlock(player.level, blockEntry)) remove = true; + + if (remove) iter.remove(); + } + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/DelayedBlockPlacer.java b/src/main/java/nl/requios/effortlessbuilding/systems/DelayedBlockPlacer.java index 0373849..337a369 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/DelayedBlockPlacer.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/DelayedBlockPlacer.java @@ -6,7 +6,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import nl.requios.effortlessbuilding.buildmodifier.BlockSet; +import nl.requios.effortlessbuilding.buildmodifier.UndoRedoBlockSet; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.utilities.InventoryHelper; import nl.requios.effortlessbuilding.utilities.SurvivalHelper; @@ -97,7 +97,7 @@ public class DelayedBlockPlacer { //add to undo stack BlockPos firstPos = coordinates.get(0); BlockPos secondPos = coordinates.get(coordinates.size() - 1); - UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, firstPos, secondPos)); + UndoRedo.addUndo(player, new UndoRedoBlockSet(coordinates, previousBlockStates, newBlockStates, firstPos, secondPos)); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java b/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java deleted file mode 100644 index 37223fe..0000000 --- a/src/main/java/nl/requios/effortlessbuilding/systems/QuickReplace.java +++ /dev/null @@ -1,30 +0,0 @@ -package nl.requios.effortlessbuilding.systems; - -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import nl.requios.effortlessbuilding.EffortlessBuilding; -import nl.requios.effortlessbuilding.network.IsQuickReplacingPacket; -import nl.requios.effortlessbuilding.network.PacketHandler; - -@OnlyIn(Dist.CLIENT) -public class QuickReplace { - private boolean isQuickReplacing = false; - - public boolean isQuickReplacing() { - return isQuickReplacing; - } - - public void toggleQuickReplacing() { - setIsQuickReplacing(!isQuickReplacing); - } - - public void setIsQuickReplacing(boolean isQuickReplacing) { - this.isQuickReplacing = isQuickReplacing; - - EffortlessBuilding.log(Minecraft.getInstance().player, "Set " + ChatFormatting.GOLD + "Quick Replace " + - ChatFormatting.RESET + (this.isQuickReplacing ? "on" : "off")); - PacketHandler.INSTANCE.sendToServer(new IsQuickReplacingPacket(this.isQuickReplacing)); - } -} diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java index c1d39df..51fb6e1 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBlockPlacer.java @@ -1,13 +1,27 @@ package nl.requios.effortlessbuilding.systems; -import net.minecraft.core.BlockPos; +import com.google.common.collect.Lists; +import net.minecraft.core.Direction; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BucketItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.items.ItemHandlerHelper; import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.create.foundation.utility.BlockHelper; import nl.requios.effortlessbuilding.utilities.BlockEntry; +import nl.requios.effortlessbuilding.utilities.BlockSet; import java.util.List; @@ -15,7 +29,7 @@ import java.util.List; public class ServerBlockPlacer { private boolean isPlacingOrBreakingBlocks = false; - public void placeBlocks(Player player, List blocks) { + public void placeBlocks(Player player, BlockSet blocks) { EffortlessBuilding.log(player, "Placing " + blocks.size() + " blocks"); for (BlockEntry block : blocks) { @@ -28,11 +42,11 @@ public class ServerBlockPlacer { if (!world.isLoaded(block.blockPos)) return; isPlacingOrBreakingBlocks = true; - BlockHelper.placeSchematicBlock(world, block.blockState, block.blockPos, block.itemStack, null); + boolean placedBlock = onPlaceItemIntoWorld(player, block) == InteractionResult.SUCCESS; isPlacingOrBreakingBlocks = false; } - public void breakBlocks(Player player, List blocks) { + public void breakBlocks(Player player, BlockSet blocks) { EffortlessBuilding.log(player, "Breaking " + blocks.size() + " blocks"); for (BlockEntry block : blocks) { @@ -45,7 +59,7 @@ public class ServerBlockPlacer { if (!world.isLoaded(block.blockPos) || world.isEmptyBlock(block.blockPos)) return; isPlacingOrBreakingBlocks = true; - BlockHelper.destroyBlockAs(world, block.blockPos, player, player.getMainHandItem(), 0f, stack -> { + boolean brokeBlock = BlockHelper.destroyBlockAs(world, block.blockPos, player, player.getMainHandItem(), 0f, stack -> { if (!player.isCreative()) { ItemHandlerHelper.giveItemToPlayer(player, stack); } @@ -56,4 +70,95 @@ public class ServerBlockPlacer { public boolean isPlacingOrBreakingBlocks() { return isPlacingOrBreakingBlocks; } + + //ForgeHooks::onPlaceItemIntoWorld + private InteractionResult onPlaceItemIntoWorld(Player player, BlockEntry block) { + + ItemStack itemstack = block.itemStack; + Level level = player.level; + + if (player != null && !player.getAbilities().mayBuild && !itemstack.hasAdventureModePlaceTagForBlock(level.registryAccess().registryOrThrow(Registry.BLOCK_REGISTRY), new BlockInWorld(level, block.blockPos, false))) + return InteractionResult.PASS; + + // handle all placement events here + Item item = itemstack.getItem(); + int size = itemstack.getCount(); + CompoundTag nbt = null; + if (itemstack.getTag() != null) + nbt = itemstack.getTag().copy(); + + if (!(itemstack.getItem() instanceof BucketItem)) // if not bucket + level.captureBlockSnapshots = true; + + ItemStack copy = itemstack.copy(); + BlockHelper.placeSchematicBlock(level, player, block.newBlockState, block.blockPos, block.itemStack, null); + InteractionResult ret = InteractionResult.SUCCESS; + if (itemstack.isEmpty()) + ForgeEventFactory.onPlayerDestroyItem(player, copy, InteractionHand.MAIN_HAND); + + level.captureBlockSnapshots = false; + + if (ret.consumesAction()) + { + // save new item data + int newSize = itemstack.getCount(); + CompoundTag newNBT = null; + if (itemstack.getTag() != null) + { + newNBT = itemstack.getTag().copy(); + } + @SuppressWarnings("unchecked") + List blockSnapshots = (List)level.capturedBlockSnapshots.clone(); + level.capturedBlockSnapshots.clear(); + + // make sure to set pre-placement item data for event + itemstack.setCount(size); + itemstack.setTag(nbt); + + Direction side = Direction.UP; + + boolean eventResult = false; + if (blockSnapshots.size() > 1) + { + eventResult = ForgeEventFactory.onMultiBlockPlace(player, blockSnapshots, side); + } + else if (blockSnapshots.size() == 1) + { + eventResult = ForgeEventFactory.onBlockPlace(player, blockSnapshots.get(0), side); + } + + if (eventResult) + { + ret = InteractionResult.FAIL; // cancel placement + // revert back all captured blocks + for (BlockSnapshot blocksnapshot : Lists.reverse(blockSnapshots)) + { + level.restoringBlockSnapshots = true; + blocksnapshot.restore(true, false); + level.restoringBlockSnapshots = false; + } + } + else + { + // Change the stack to its new content + itemstack.setCount(newSize); + itemstack.setTag(newNBT); + + for (BlockSnapshot snap : blockSnapshots) + { + int updateFlag = snap.getFlag(); + BlockState oldBlock = snap.getReplacedBlock(); + BlockState newBlock = level.getBlockState(snap.getPos()); + newBlock.onPlace(level, snap.getPos(), oldBlock, false); + + level.markAndNotifyBlock(snap.getPos(), level.getChunkAt(snap.getPos()), oldBlock, newBlock, updateFlag, 512); + } + if (player != null) + player.awardStat(Stats.ITEM_USED.get(item)); + } + } + level.capturedBlockSnapshots.clear(); + + return ret; + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java index 9e80ce0..f0fb590 100644 --- a/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java +++ b/src/main/java/nl/requios/effortlessbuilding/systems/ServerBuildState.java @@ -30,4 +30,8 @@ public class ServerBuildState { player.getPersistentData().remove(IS_QUICK_REPLACING_KEY); } } + + public static boolean isLikeVanilla(Player player) { + return !isUsingBuildMode(player) && !isQuickReplacing(player); + } } diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java index 6d0c40e..28b7649 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockEntry.java @@ -8,7 +8,6 @@ import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.state.BlockState; import java.util.BitSet; -import java.util.Objects; public class BlockEntry { public final BlockPos blockPos; @@ -16,7 +15,9 @@ public class BlockEntry { public boolean mirrorY; public boolean mirrorZ; public Rotation rotation; - public BlockState blockState; + //BlockState that is currently in the world + public BlockState existingBlockState; + public BlockState newBlockState; public ItemStack itemStack = ItemStack.EMPTY; public BlockEntry(BlockPos blockPos) { @@ -24,7 +25,7 @@ public class BlockEntry { } public boolean meansBreakBlock() { - return blockState == null || blockState.isAir(); + return newBlockState == null || newBlockState.isAir(); } public BitSet getMirrorBitSet() { @@ -43,13 +44,13 @@ public class BlockEntry { public static void encode(FriendlyByteBuf buf, BlockEntry block) { buf.writeBlockPos(block.blockPos); - buf.writeNullable(block.blockState, (buffer, blockState) -> buffer.writeNbt(NbtUtils.writeBlockState(blockState))); + buf.writeNullable(block.newBlockState, (buffer, blockState) -> buffer.writeNbt(NbtUtils.writeBlockState(blockState))); buf.writeItem(block.itemStack); } public static BlockEntry decode(FriendlyByteBuf buf) { BlockEntry block = new BlockEntry(buf.readBlockPos()); - block.blockState = buf.readNullable(buffer -> { + block.newBlockState = buf.readNullable(buffer -> { var nbt = buf.readNbt(); if (nbt == null) return null; return NbtUtils.readBlockState(nbt); diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockSet.java b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockSet.java new file mode 100644 index 0000000..1c5ccd4 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockSet.java @@ -0,0 +1,81 @@ +package nl.requios.effortlessbuilding.utilities; + +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.FriendlyByteBuf; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +public class BlockSet extends HashMap implements Iterable { + public static boolean logging = true; + + public BlockPos firstPos; + public BlockPos lastPos; + + public BlockSet() { + super(); + } + + public BlockSet(BlockSet blockSet) { + super(blockSet); + this.firstPos = blockSet.firstPos; + this.lastPos = blockSet.lastPos; + } + + public BlockSet(List blockEntries) { + super(); + for (BlockEntry blockEntry : blockEntries) { + add(blockEntry); + } + } + + public void add(BlockEntry blockEntry) { + if (!containsKey(blockEntry.blockPos)) { + + //Limit number of blocks you can place + int limit = ReachHelper.getMaxBlocksPlacedAtOnce(Minecraft.getInstance().player); + if (size() >= limit) { + if (logging) EffortlessBuilding.log("BlockSet limit reached, not adding block at " + blockEntry.blockPos); + return; + } + + put(blockEntry.blockPos, blockEntry); + + } else { + + if (logging) EffortlessBuilding.log("BlockSet already contains block at " + blockEntry.blockPos); + } + } + + public HashSet getCoordinates() { + return new HashSet<>(keySet()); + } + + public BlockEntry getFirstBlockEntry() { + return get(firstPos); + } + + public BlockEntry getLastBlockEntry() { + return get(lastPos); + } + + @NotNull + @Override + public Iterator iterator() { + return this.values().iterator(); + } + + public static void encode(FriendlyByteBuf buf, BlockSet block) { + buf.writeCollection(block.values(), BlockEntry::encode); + } + + public static BlockSet decode(FriendlyByteBuf buf) { + return new BlockSet(buf.readList(BlockEntry::decode)); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java new file mode 100644 index 0000000..9d63b11 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/BlockUtilities.java @@ -0,0 +1,58 @@ +package nl.requios.effortlessbuilding.utilities; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.Direction; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class BlockUtilities { + + public static BlockState getBlockState(Player player, InteractionHand hand, ItemStack blockItemStack, BlockEntry blockEntry) { + Block block = Block.byItem(blockItemStack.getItem()); + //TODO convert lookingAt hitvec to relative hitvec + var blockHitResult = new BlockHitResult(Vec3.ZERO, Direction.UP, blockEntry.blockPos, false); + return block.getStateForPlacement(new BlockPlaceContext(player, hand, blockItemStack, blockHitResult)); + } + + public static boolean determineIfLookingAtInteractiveObject(Minecraft mc, ClientLevel level) { + //Check if we are looking at an interactive object + var result = false; + if (mc.hitResult != null) { + if (mc.hitResult.getType() == HitResult.Type.BLOCK) { + var blockHitResult = (BlockHitResult) mc.hitResult; + var blockState = level.getBlockState(blockHitResult.getBlockPos()); + if (blockState.hasBlockEntity()) { + result = true; + } + } + if (mc.hitResult.getType() == HitResult.Type.ENTITY) { + result = true; + } + } + return result; + } + + public static void playSoundIfFurtherThanNormal(Player player, BlockEntry blockEntry, boolean breaking) { + + if (Minecraft.getInstance().hitResult != null && Minecraft.getInstance().hitResult.getType() == HitResult.Type.BLOCK) + return; + + if (blockEntry == null || blockEntry.newBlockState == null) + return; + + SoundType soundType = blockEntry.newBlockState.getBlock().getSoundType(blockEntry.newBlockState, player.level, blockEntry.blockPos, player); + SoundEvent soundEvent = breaking ? soundType.getBreakSound() : soundType.getPlaceSound(); + player.level.playSound(player, player.blockPosition(), soundEvent, SoundSource.BLOCKS, 0.6f, soundType.getPitch()); + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java index 14315da..eb64215 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/InventoryHelper.java @@ -7,6 +7,7 @@ import net.minecraft.world.item.ItemStack; public class InventoryHelper { + @Deprecated //Use BlockHelper.findAndRemoveInInventory instead public static ItemStack findItemStackInInventory(Player player, Block block) { for (ItemStack invStack : player.getInventory().items) { if (!invStack.isEmpty() && invStack.getItem() instanceof BlockItem && diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/PlaceChecker.java b/src/main/java/nl/requios/effortlessbuilding/utilities/PlaceChecker.java new file mode 100644 index 0000000..4061a08 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/PlaceChecker.java @@ -0,0 +1,105 @@ +package nl.requios.effortlessbuilding.utilities; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.piston.PistonHeadBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BedPart; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public class PlaceChecker { + + //SchematicPrinter::shouldPlaceBlock + public static boolean shouldPlaceBlock(Level world, BlockEntry blockEntry) { + if (world == null) + return false; + + var pos = blockEntry.blockPos; + var state = blockEntry.newBlockState; + BlockEntity tileEntity = null; + + BlockState toReplace = world.getBlockState(pos); + BlockEntity toReplaceTE = world.getBlockEntity(pos); + BlockState toReplaceOther = null; + + if (state.hasProperty(BlockStateProperties.BED_PART) && state.hasProperty(BlockStateProperties.HORIZONTAL_FACING) + && state.getValue(BlockStateProperties.BED_PART) == BedPart.FOOT) + toReplaceOther = world.getBlockState(pos.relative(state.getValue(BlockStateProperties.HORIZONTAL_FACING))); + if (state.hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF) + && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER) + toReplaceOther = world.getBlockState(pos.above()); + + if (!world.isLoaded(pos)) + return false; + if (!world.getWorldBorder().isWithinBounds(pos)) + return false; + if (toReplace == state) + return false; + if (toReplace.getDestroySpeed(world, pos) == -1 + || (toReplaceOther != null && toReplaceOther.getDestroySpeed(world, pos) == -1)) + return false; + + boolean isNormalCube = state.isRedstoneConductor(world, pos); + return shouldPlace(world, pos, state, tileEntity, toReplace, toReplaceOther, isNormalCube); + } + + //SchematicannonTileEntity::shouldPlace + private static boolean shouldPlace(Level level, BlockPos pos, BlockState state, BlockEntity tileEntity, BlockState toReplace, + BlockState toReplaceOther, boolean isNormalCube) { + return true; +// if (!replaceTileEntities +// && (toReplace.hasBlockEntity() || (toReplaceOther != null && toReplaceOther.hasBlockEntity()))) +// return false; +// +// if (shouldIgnoreBlockState(state)) +// return false; +// +// boolean placingAir = state.isAir(); +// +// if (replaceMode == 3) +// return true; +// if (replaceMode == 2 && !placingAir) +// return true; +// if (replaceMode == 1 && (isNormalCube || (!toReplace.isRedstoneConductor(level, pos) +// && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)))) && !placingAir) +// return true; +// if (replaceMode == 0 && !toReplace.isRedstoneConductor(level, pos) +// && (toReplaceOther == null || !toReplaceOther.isRedstoneConductor(level, pos)) && !placingAir) +// return true; +// +// return false; + } + + //SchematicannonTileEntity::shouldIgnoreBlockState + private static boolean shouldIgnoreBlockState(BlockState state) { + // Block doesn't have a mapping (Water, lava, etc) + if (state.getBlock() == Blocks.STRUCTURE_VOID) + return true; + +// ItemRequirement requirement = ItemRequirement.of(state, te); +// if (requirement.isEmpty()) +// return false; +// if (requirement.isInvalid()) +// return false; + + // Block doesn't need to be placed twice (Doors, beds, double plants) + if (state.hasProperty(BlockStateProperties.DOUBLE_BLOCK_HALF) + && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.UPPER) + return true; + if (state.hasProperty(BlockStateProperties.BED_PART) + && state.getValue(BlockStateProperties.BED_PART) == BedPart.HEAD) + return true; + if (state.getBlock() instanceof PistonHeadBlock) + return true; +// if (AllBlocks.BELT.has(state)) +// return state.getValue(BeltBlock.PART) == BeltPart.MIDDLE; + + return false; + } +} diff --git a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java index 3e0d987..7e74ef5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/utilities/SurvivalHelper.java @@ -2,7 +2,6 @@ package nl.requios.effortlessbuilding.utilities; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.core.Registry; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundSource; @@ -20,12 +19,10 @@ import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.pattern.BlockInWorld; import net.minecraft.world.level.material.Material; -import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.event.ForgeEventFactory; import nl.requios.effortlessbuilding.CommonConfig; import nl.requios.effortlessbuilding.EffortlessBuildingClient; -import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.systems.ServerBuildState; @@ -273,11 +270,9 @@ public class SurvivalHelper { } //Check quickreplace - boolean isQuickReplacing = false; if (placer instanceof Player player) { - if (world.isClientSide) EffortlessBuildingClient.QUICK_REPLACE.isQuickReplacing(); - else isQuickReplacing = ServerBuildState.isQuickReplacing(player); - + boolean isQuickReplacing = world.isClientSide ? EffortlessBuildingClient.BUILD_SETTINGS.isQuickReplacing() + : ServerBuildState.isQuickReplacing(player); if (isQuickReplacing) return true; }