From cef32e86b4d4010167008c955db2eb86eeb7eb53 Mon Sep 17 00:00:00 2001 From: TheRealWormbo Date: Mon, 23 Oct 2023 12:47:08 +0200 Subject: [PATCH] Optimized Alfheim portal multiblock and pylon validation Also cleaned up portal particle logic and portal AABB creation code a bit. --- .../AlfheimPortalBlockEntity.java | 131 +++++++++--------- 1 file changed, 66 insertions(+), 65 deletions(-) diff --git a/Xplat/src/main/java/vazkii/botania/common/block/block_entity/AlfheimPortalBlockEntity.java b/Xplat/src/main/java/vazkii/botania/common/block/block_entity/AlfheimPortalBlockEntity.java index 5308dba2c5..699348de24 100644 --- a/Xplat/src/main/java/vazkii/botania/common/block/block_entity/AlfheimPortalBlockEntity.java +++ b/Xplat/src/main/java/vazkii/botania/common/block/block_entity/AlfheimPortalBlockEntity.java @@ -106,6 +106,8 @@ public TriPredicate getStatePredicate() { }); public static final int MANA_COST = 500; + public static final int MANA_COST_OPENING = 200000; + public static final int MIN_REQUIRED_PYLONS = 2; private static final String TAG_TICKS_OPEN = "ticksOpen"; private static final String TAG_TICKS_SINCE_LAST_ITEM = "ticksSinceLastItem"; private static final String TAG_STACK_COUNT = "stackCount"; @@ -113,6 +115,7 @@ public TriPredicate getStatePredicate() { public static final String TAG_PORTAL_FLAG = "_elvenPortal"; private final List stacksIn = new ArrayList<>(); + private final List cachedPylonPositions = new ArrayList<>(); public int ticksOpen = 0; private int ticksSinceLastItem = 0; @@ -126,16 +129,16 @@ public AlfheimPortalBlockEntity(BlockPos pos, BlockState state) { } public static void commonTick(Level level, BlockPos worldPosition, BlockState blockState, AlfheimPortalBlockEntity self) { - if (blockState.getValue(BotaniaStateProperties.ALFPORTAL_STATE) == AlfheimPortalState.OFF) { + AlfheimPortalState state = blockState.getValue(BotaniaStateProperties.ALFPORTAL_STATE); + if (state == AlfheimPortalState.OFF) { self.ticksOpen = 0; return; } - AlfheimPortalState state = blockState.getValue(BotaniaStateProperties.ALFPORTAL_STATE); - AlfheimPortalState newState = self.getValidState(); + AlfheimPortalState newState = self.getValidState(state); self.ticksOpen++; - AABB aabb = self.getPortalAABB(); + AABB aabb = self.getPortalAABB(state); boolean open = self.ticksOpen > 60; XplatAbstractions.INSTANCE.fireElvenPortalUpdateEvent(self, aabb, open, self.stacksIn); @@ -222,48 +225,10 @@ private boolean validateItemUsage(ItemEntity entity) { } private void blockParticle(AlfheimPortalState state) { - double dh, dy; - - // Pick one of the inner positions - switch (level.random.nextInt(9)) { - case 0 -> { - dh = 0; - dy = 1; - } - case 1 -> { - dh = 0; - dy = 2; - } - case 2 -> { - dh = 0; - dy = 3; - } - case 3 -> { - dh = -1; - dy = 1; - } - case 4 -> { - dh = -1; - dy = 2; - } - case 5 -> { - dh = -1; - dy = 3; - } - case 6 -> { - dh = 1; - dy = 1; - } - case 7 -> { - dh = 1; - dy = 2; - } - case 8 -> { - dh = 1; - dy = 3; - } - default -> throw new AssertionError(); - } + // Pick one of the inner positions, offsets [-1,+1] and [+1,+3] + int rnd = level.random.nextInt(9); + double dh = (rnd / 3) - 1; + double dy = (rnd % 3) + 1; double dx = state == AlfheimPortalState.ON_X ? 0 : dh; double dz = state == AlfheimPortalState.ON_Z ? 0 : dh; @@ -276,7 +241,7 @@ private void blockParticle(AlfheimPortalState state) { public boolean onUsedByWand(@Nullable Player player, ItemStack stack, Direction side) { AlfheimPortalState state = getBlockState().getValue(BotaniaStateProperties.ALFPORTAL_STATE); if (state == AlfheimPortalState.OFF) { - AlfheimPortalState newState = getValidState(); + AlfheimPortalState newState = getValidState(state); if (newState != AlfheimPortalState.OFF) { level.setBlockAndUpdate(getBlockPos(), getBlockState().setValue(BotaniaStateProperties.ALFPORTAL_STATE, newState)); if (player instanceof ServerPlayer serverPlayer) { @@ -289,13 +254,10 @@ public boolean onUsedByWand(@Nullable Player player, ItemStack stack, Direction return false; } - private AABB getPortalAABB() { - AABB aabb = new AABB(worldPosition.offset(-1, 1, 0), worldPosition.offset(2, 4, 1)); - if (getBlockState().getValue(BotaniaStateProperties.ALFPORTAL_STATE) == AlfheimPortalState.ON_X) { - aabb = new AABB(worldPosition.offset(0, 1, -1), worldPosition.offset(1, 4, 2)); - } - - return aabb; + private AABB getPortalAABB(AlfheimPortalState state) { + return state == AlfheimPortalState.ON_X + ? new AABB(worldPosition.offset(0, 1, -1), worldPosition.offset(1, 4, 2)) + : new AABB(worldPosition.offset(-1, 1, 0), worldPosition.offset(2, 4, 1)); } private void addItem(ItemStack stack) { @@ -315,7 +277,7 @@ public static Collection elvenTradeRecipes(Level world) { } private void resolveRecipes() { - List pylons = locatePylons(); + List pylons = locatePylons(true); for (Recipe r : BotaniaRecipeTypes.getRecipes(level, BotaniaRecipeTypes.ELVEN_TRADE_TYPE).values()) { if (!(r instanceof ElvenTradeRecipe recipe)) { continue; @@ -381,8 +343,25 @@ public void readPacketNBT(CompoundTag cmp) { ticksSinceLastItem = cmp.getInt(TAG_TICKS_SINCE_LAST_ITEM); } - private AlfheimPortalState getValidState() { - Rotation rot = MULTIBLOCK.get().validate(level, getBlockPos()); + private static Rotation getStateRotation(AlfheimPortalState state) { + return switch (state) { + case ON_X -> Rotation.CLOCKWISE_90; + case ON_Z -> Rotation.NONE; + default -> null; + }; + } + + private AlfheimPortalState getValidState(AlfheimPortalState oldState) { + Rotation rot; + if (oldState != AlfheimPortalState.OFF) { + Rotation oldRot = getStateRotation(oldState); + if (!MULTIBLOCK.get().validate(level, getBlockPos(), oldRot)) { + return AlfheimPortalState.OFF; + } + rot = oldRot; + } else { + rot = MULTIBLOCK.get().validate(level, getBlockPos()); + } if (rot == null) { return AlfheimPortalState.OFF; } @@ -394,28 +373,50 @@ private AlfheimPortalState getValidState() { }; } - public List locatePylons() { + public List locatePylons(boolean rescanNow) { + if (!rescanNow && cachedPylonPositions.size() >= MIN_REQUIRED_PYLONS) { + List cachedResult = new ArrayList<>(); + for (BlockPos pos : cachedPylonPositions) { + if (isValidPylonPosition(pos)) { + cachedResult.add(pos); + } + } + if (cachedResult.size() >= MIN_REQUIRED_PYLONS) { + return cachedResult; + } + + // not enough valid cached pylons, scan again + } + int range = 5; List result = new ArrayList<>(); for (BlockPos pos : BlockPos.betweenClosed(getBlockPos().offset(-range, -range, -range), getBlockPos().offset(range, range, range))) { - if (getLevel().hasChunkAt(pos) - && getLevel().getBlockState(pos).is(BotaniaBlocks.naturaPylon) - && getLevel().getBlockState(pos.below()).getBlock() instanceof ManaPoolBlock) { + if (isValidPylonPosition(pos)) { result.add(pos.immutable()); } } + cachedPylonPositions.clear(); + cachedPylonPositions.addAll(result); + return result; } + private boolean isValidPylonPosition(BlockPos pos) { + return getLevel().hasChunkAt(pos) + && getLevel().getBlockState(pos).is(BotaniaBlocks.naturaPylon) + && getLevel().getBlockState(pos.below()).getBlock() instanceof ManaPoolBlock; + } + public void lightPylons() { if (ticksOpen < 50) { return; } - List pylons = locatePylons(); + boolean finishOpening = ticksOpen == 50; + List pylons = locatePylons(finishOpening); for (BlockPos pos : pylons) { BlockEntity tile = level.getBlockEntity(pos); if (tile instanceof PylonBlockEntity pylon) { @@ -424,8 +425,8 @@ public void lightPylons() { } } - if (ticksOpen == 50) { - consumeMana(pylons, 200000, true); + if (finishOpening) { + consumeMana(pylons, MANA_COST_OPENING, true); } } @@ -433,7 +434,7 @@ public boolean consumeMana(List pylons, int totalCost, boolean close) List consumePools = new ArrayList<>(); int consumed = 0; - if (pylons.size() < 2) { + if (pylons.size() < MIN_REQUIRED_PYLONS) { closeNow = true; return false; }