From 36599b321e0a1e27ad47a81cba1ee8699d29b3d3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 16 Jan 2024 21:41:15 +0000 Subject: [PATCH] Backport small changes from the 1.20.4 branch - Add support for version overrides/exclusions in our dependency check. Sometimes mod loaders use different versions to vanilla, and we need some way to handle that. - Rescan wired network connections on the tick after invalidation, rather than when invalidated. - Convert some constant lambdas to static method references. Lambdas don't allocate if they don't capture variables, so this has the same performance and is a little less ugly. - Small code-style/formatting changes. --- .gitignore | 1 + .../cc/tweaked/gradle/DependencyCheck.kt | 22 ++++++++++++++++++- .../client/network/ClientNetworking.java | 5 ++++- .../computercraft/impl/UpgradeManager.java | 2 +- .../modem/wired/CableBlockEntity.java | 11 +++++++++- .../wired/WiredModemFullBlockEntity.java | 11 +++++++++- .../shared/turtle/core/TurtleBrain.java | 9 ++++---- .../computercraft/shared/util/WorldUtil.java | 10 ++++----- .../computercraft/gametest/Modem_Test.kt | 5 ++++- .../computercraft/gametest/Monitor_Test.kt | 1 - .../computercraft/gametest/Recipe_Test.kt | 7 +++--- 11 files changed, 64 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index d2a7e288d..96b40ce93 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /logs /build /projects/*/logs +/projects/fabric/fabricloader.log /projects/*/build /buildSrc/build /out diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/DependencyCheck.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/DependencyCheck.kt index ee0b26cbb..78987ff72 100644 --- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/DependencyCheck.kt +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/DependencyCheck.kt @@ -7,12 +7,15 @@ package cc.tweaked.gradle import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.artifacts.component.ModuleComponentSelector import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.result.DependencyResult import org.gradle.api.artifacts.result.ResolvedDependencyResult import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import org.gradle.language.base.plugins.LifecycleBasePlugin @@ -21,9 +24,25 @@ abstract class DependencyCheck : DefaultTask() { @get:Input abstract val configuration: ListProperty + /** + * A mapping of module coordinates (`group:module`) to versions, overriding the requested version. + */ + @get:Input + abstract val overrides: MapProperty + init { description = "Check :core's dependencies are consistent with Minecraft's." group = LifecycleBasePlugin.VERIFICATION_GROUP + + configuration.finalizeValueOnRead() + overrides.finalizeValueOnRead() + } + + /** + * Override a module with a different version. + */ + fun override(module: Provider, version: String) { + overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) }) } @TaskAction @@ -60,7 +79,8 @@ abstract class DependencyCheck : DefaultTask() { ) { // If the version is different between the requested and selected version, report an error. val selected = dependency.selected.moduleVersion!!.version - if (requested.version != selected) { + val requestedVersion = overrides.get()["${requested.group}:${requested.module}"] ?: requested.version + if (requestedVersion != selected) { logger.error("Requested dependency {} (via {}) but got version {}", requested, from, selected) return false } diff --git a/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java b/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java index bf8070fa9..8f9b6de9d 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java +++ b/projects/common/src/client/java/dan200/computercraft/client/network/ClientNetworking.java @@ -12,7 +12,10 @@ import net.minecraft.client.Minecraft; /** * Methods for sending packets from clients to the server. */ -public class ClientNetworking { +public final class ClientNetworking { + private ClientNetworking() { + } + /** * Send a network message to the server. * diff --git a/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java b/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java index dd7dd6a64..3b3598c82 100644 --- a/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java +++ b/projects/common/src/main/java/dan200/computercraft/impl/UpgradeManager.java @@ -123,7 +123,7 @@ public class UpgradeManager, T extends // TODO: Can we track which mod this resource came from and use that instead? It's theoretically possible, // but maybe not ideal for datapacks. var modId = id.getNamespace(); - if (modId.equals("minecraft") || modId.equals("")) modId = ComputerCraftAPI.MOD_ID; + if (modId.equals("minecraft") || modId.isEmpty()) modId = ComputerCraftAPI.MOD_ID; var upgrade = serialiser.fromJson(id, root); if (!upgrade.getUpgradeID().equals(id)) { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java index e8c4b2081..ef6257b52 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBlockEntity.java @@ -63,6 +63,7 @@ public class CableBlockEntity extends BlockEntity { private @Nullable Runnable modemChanged; private boolean connectionsFormed = false; + private boolean connectionsChanged = false; private final WiredModemElement cable = new CableElement(); private final WiredNode node = cable.getNode(); @@ -87,7 +88,7 @@ public class CableBlockEntity extends BlockEntity { } }; - private final ComponentAccess connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> connectionsChanged()); + private final ComponentAccess connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> scheduleConnectionsChanged()); public CableBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); @@ -236,10 +237,18 @@ public class CableBlockEntity extends BlockEntity { updateConnectedPeripherals(); } } + + if (connectionsChanged) connectionsChanged(); + } + + private void scheduleConnectionsChanged() { + connectionsChanged = true; + TickScheduler.schedule(tickToken); } void connectionsChanged() { if (getLevel().isClientSide) return; + connectionsChanged = false; var state = getBlockState(); var world = getLevel(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java index 40a842980..af92d6fe8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemFullBlockEntity.java @@ -74,13 +74,14 @@ public class WiredModemFullBlockEntity extends BlockEntity { private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6]; private boolean connectionsFormed = false; + private boolean connectionsChanged = false; private final TickScheduler.Token tickToken = new TickScheduler.Token(this); private final ModemState modemState = new ModemState(() -> TickScheduler.schedule(tickToken)); private final WiredModemElement element = new FullElement(this); private final WiredNode node = element.getNode(); - private final ComponentAccess connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> connectionsChanged()); + private final ComponentAccess connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> scheduleConnectionsChanged()); private int invalidSides = 0; @@ -204,10 +205,18 @@ public class WiredModemFullBlockEntity extends BlockEntity { updateConnectedPeripherals(); } } + + if (connectionsChanged) connectionsChanged(); + } + + private void scheduleConnectionsChanged() { + connectionsChanged = true; + TickScheduler.schedule(tickToken); } private void connectionsChanged() { if (getLevel().isClientSide) return; + connectionsChanged = false; var world = getLevel(); var current = getBlockPos(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index e399096bf..70d01d941 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -42,7 +42,6 @@ import net.minecraft.world.phys.Vec3; import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR; import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED; @@ -59,8 +58,6 @@ public class TurtleBrain implements TurtleAccessInternal { private static final int ANIM_DURATION = 8; - public static final Predicate PUSHABLE_ENTITY = entity -> !entity.isSpectator() && entity.getPistonPushReaction() != PushReaction.IGNORE; - private TurtleBlockEntity owner; private @Nullable GameProfile owningPlayer; @@ -694,7 +691,7 @@ public class TurtleBrain implements TurtleAccessInternal { } var aabb = new AABB(minX, minY, minZ, maxX, maxY, maxZ); - var list = world.getEntitiesOfClass(Entity.class, aabb, PUSHABLE_ENTITY); + var list = world.getEntitiesOfClass(Entity.class, aabb, TurtleBrain::canPush); if (!list.isEmpty()) { double pushStep = 1.0f / ANIM_DURATION; var pushStepX = moveDir.getStepX() * pushStep; @@ -737,6 +734,10 @@ public class TurtleBrain implements TurtleAccessInternal { } } + private static boolean canPush(Entity entity) { + return !entity.isSpectator() && entity.getPistonPushReaction() != PushReaction.IGNORE; + } + private float getAnimationFraction(float f) { var next = (float) animationProgress / ANIM_DURATION; var previous = (float) lastAnimationProgress / ANIM_DURATION; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 864b2d92d..049e4bf37 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -27,12 +27,8 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import javax.annotation.Nullable; -import java.util.function.Predicate; public final class WorldUtil { - @SuppressWarnings("UnnecessaryLambda") - private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable(); - public static boolean isLiquidBlock(Level world, BlockPos pos) { if (!world.isInWorldBounds(pos)) return false; return world.getBlockState(pos).liquid(); @@ -84,7 +80,7 @@ public final class WorldUtil { Entity bestEntity = null; Vec3 bestHit = null; - for (var entity : level.getEntities(source, bounds, WorldUtil.CAN_COLLIDE)) { + for (var entity : level.getEntities(source, bounds, WorldUtil::canCollide)) { var aabb = entity.getBoundingBox().inflate(entity.getPickRadius()); // clip doesn't work when inside the entity. Just assume we've got a perfect match and break. @@ -109,6 +105,10 @@ public final class WorldUtil { return bestEntity == null ? null : new EntityHitResult(bestEntity, bestHit); } + private static boolean canCollide(Entity entity) { + return entity != null && entity.isAlive() && entity.isPickable(); + } + public static Vec3 getRayStart(Player entity) { return entity.getEyePosition(); } diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt index d4de9f575..738f69398 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt @@ -7,7 +7,10 @@ package dan200.computercraft.gametest import dan200.computercraft.api.lua.ObjectArguments import dan200.computercraft.core.apis.PeripheralAPI import dan200.computercraft.core.computer.ComputerSide -import dan200.computercraft.gametest.api.* +import dan200.computercraft.gametest.api.getBlockEntity +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenOnComputer +import dan200.computercraft.gametest.api.thenStartComputer import dan200.computercraft.shared.ModRegistry import dan200.computercraft.shared.peripheral.modem.wired.CableBlock import dan200.computercraft.test.core.assertArrayEquals diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt index ebc158c67..2d5a4d48a 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt @@ -21,7 +21,6 @@ import net.minecraft.world.entity.EntityType import net.minecraft.world.item.ItemStack import net.minecraft.world.level.block.Blocks import org.junit.jupiter.api.Assertions.* -import java.util.* class Monitor_Test { @GameTest diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt index fb186d1cb..2c65cfe92 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt @@ -19,7 +19,6 @@ import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.TransientCraftingContainer import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items -import net.minecraft.world.item.crafting.CraftingRecipe import net.minecraft.world.item.crafting.RecipeType import org.junit.jupiter.api.Assertions.assertEquals import java.util.* @@ -37,11 +36,11 @@ class Recipe_Test { container.setItem(0, ItemStack(Items.SKELETON_SKULL)) container.setItem(1, ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get())) - val recipe: Optional = context.level.server.recipeManager + val recipe = context.level.server.recipeManager .getRecipeFor(RecipeType.CRAFTING, container, context.level) - if (!recipe.isPresent) throw GameTestAssertException("No recipe matches") + .orElseThrow { GameTestAssertException("No recipe matches") } - val result = recipe.get().assemble(container, context.level.registryAccess()) + val result = recipe.assemble(container, context.level.registryAccess()) val profile = GameProfile(UUID.fromString("f3c8d69b-0776-4512-8434-d1b2165909eb"), "dan200")