generated from MrSphay/codex-agent-repository-kit
Decompile upstream Explosion Overhaul 0.2.3.0
This commit is contained in:
395
com/vinlanx/explosionoverhaul/RedstoneLampEffects.java
Normal file
395
com/vinlanx/explosionoverhaul/RedstoneLampEffects.java
Normal file
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.BlockIndexManager;
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import com.vinlanx.explosionoverhaul.ModSounds;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
public class RedstoneLampEffects {
|
||||
private static final Map<UUID, List<DelayedLampEffect>> perPlayerDelayedLampEffects = new ConcurrentHashMap<UUID, List<DelayedLampEffect>>();
|
||||
private static final int MIN_INITIAL_FLICKERS = 2;
|
||||
private static final int MAX_INITIAL_FLICKERS = 5;
|
||||
private static final int MIN_FLICKER_PHASE_TICKS = 1;
|
||||
private static final int MAX_FLICKER_PHASE_TICKS = 4;
|
||||
private static final int BASE_MIN_LONG_OFF_TICKS = 20;
|
||||
private static final int FINAL_FLICKER_COUNT = 4;
|
||||
private static final int LAMP_UPDATE_BATCH_SIZE_PER_EFFECT = 25;
|
||||
private static final int LAMP_UPDATE_BUDGET_PER_PLAYER_PER_TICK = 200;
|
||||
private static final int MAX_CONCURRENT_LAMP_GROUPS_PER_PLAYER = 250;
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static void triggerLampFlicker(ServerLevel level, ServerPlayer player, float explosionPower, long initialDelayTicks, double distanceToExplosionOrigin) {
|
||||
List playerSpecificEffects;
|
||||
if (!((Boolean)Config.COMMON.enableLampFlicker.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
RandomSource random = level.m_213780_();
|
||||
BlockPos playerPos = player.m_20183_();
|
||||
UUID playerId = player.m_20148_();
|
||||
int lampEffectRadius = (Integer)Config.COMMON.lampFlickerSearchRadius.get();
|
||||
long currentMinLongOffTicks = 20L;
|
||||
long currentMaxLongOffTicks = distanceToExplosionOrigin < 500.0 ? 200L : (distanceToExplosionOrigin < 1000.0 ? 100L : 60L);
|
||||
if (currentMinLongOffTicks > currentMaxLongOffTicks) {
|
||||
currentMinLongOffTicks = Math.max(1L, currentMaxLongOffTicks / 2L);
|
||||
}
|
||||
if (currentMaxLongOffTicks <= 0L) {
|
||||
currentMaxLongOffTicks = 1L;
|
||||
}
|
||||
long sharedLongOffDuration = currentMaxLongOffTicks <= currentMinLongOffTicks ? currentMinLongOffTicks : currentMinLongOffTicks + (long)random.m_188503_((int)(currentMaxLongOffTicks - currentMinLongOffTicks + 1L));
|
||||
ArrayList<PotentialLampGroup> potentialLampGroupsFoundThisExplosion = new ArrayList<PotentialLampGroup>();
|
||||
List<BlockPos> allCandidates = BlockIndexManager.getNearby(level, playerPos, lampEffectRadius, BlockIndexManager.BlockType.LAMP);
|
||||
if (allCandidates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayList<BlockPos> litLampCandidates = new ArrayList<BlockPos>();
|
||||
for (BlockPos pos : allCandidates) {
|
||||
Object state;
|
||||
if (!level.m_46749_(pos) || !(state = level.m_8055_(pos)).m_60713_(Blocks.f_50261_) || !((Boolean)state.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) continue;
|
||||
litLampCandidates.add(pos);
|
||||
}
|
||||
if (litLampCandidates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
HashSet<BlockPos> lampsAlreadyInAGroup = new HashSet<BlockPos>();
|
||||
HashSet candidateSet = new HashSet(litLampCandidates);
|
||||
for (BlockPos startPos : litLampCandidates) {
|
||||
BlockState startState;
|
||||
if (lampsAlreadyInAGroup.contains(startPos) || !level.m_46749_(startPos) || !(startState = level.m_8055_(startPos)).m_60713_(Blocks.f_50261_)) continue;
|
||||
ArrayList<BlockPos> currentLampGroupPositions = new ArrayList<BlockPos>();
|
||||
LinkedList<BlockPos> toProcess = new LinkedList<BlockPos>();
|
||||
toProcess.add(startPos);
|
||||
lampsAlreadyInAGroup.add(startPos);
|
||||
while (!toProcess.isEmpty()) {
|
||||
BlockPos lampInQueue = (BlockPos)toProcess.poll();
|
||||
currentLampGroupPositions.add(lampInQueue);
|
||||
for (Direction direction : Direction.values()) {
|
||||
BlockState neighborState;
|
||||
BlockPos neighborPos = lampInQueue.m_5484_(direction, 1);
|
||||
if (!candidateSet.contains(neighborPos) || lampsAlreadyInAGroup.contains(neighborPos) || !level.m_46749_(neighborPos) || !(neighborState = level.m_8055_(neighborPos)).m_60713_(Blocks.f_50261_) || !((Boolean)neighborState.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) continue;
|
||||
lampsAlreadyInAGroup.add(neighborPos);
|
||||
toProcess.add(neighborPos);
|
||||
}
|
||||
}
|
||||
if (currentLampGroupPositions.isEmpty()) continue;
|
||||
double distanceSq = startPos.m_123331_((Vec3i)playerPos);
|
||||
long lampSpecificInitialDelay = initialDelayTicks + (long)random.m_188503_(10);
|
||||
potentialLampGroupsFoundThisExplosion.add(new PotentialLampGroup(startPos, currentLampGroupPositions, true, sharedLongOffDuration, distanceSq, lampSpecificInitialDelay));
|
||||
}
|
||||
if (potentialLampGroupsFoundThisExplosion.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
potentialLampGroupsFoundThisExplosion.sort(Comparator.comparingDouble(PotentialLampGroup::distanceSqToPlayer));
|
||||
List list = playerSpecificEffects = perPlayerDelayedLampEffects.computeIfAbsent(playerId, k -> Collections.synchronizedList(new ArrayList()));
|
||||
synchronized (list) {
|
||||
int currentEffectCountForPlayer = playerSpecificEffects.size();
|
||||
int availableSlotsForThisPlayer = 250 - currentEffectCountForPlayer;
|
||||
if (availableSlotsForThisPlayer <= 0) {
|
||||
return;
|
||||
}
|
||||
int numToAdd = Math.min(potentialLampGroupsFoundThisExplosion.size(), availableSlotsForThisPlayer);
|
||||
for (int i = 0; i < numToAdd; ++i) {
|
||||
PotentialLampGroup chosenGroup = (PotentialLampGroup)potentialLampGroupsFoundThisExplosion.get(i);
|
||||
playerSpecificEffects.add(new DelayedLampEffect(level, chosenGroup.representativePos(), chosenGroup.groupPositions(), chosenGroup.initialDelay(), chosenGroup.originallyLit(), chosenGroup.predeterminedLongOffDuration(), random));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static void onServerTick() {
|
||||
for (Map.Entry<UUID, List<DelayedLampEffect>> entry : perPlayerDelayedLampEffects.entrySet()) {
|
||||
List<DelayedLampEffect> playerEffects = entry.getValue();
|
||||
int[] playerBudget = new int[]{200};
|
||||
List<DelayedLampEffect> list = playerEffects;
|
||||
synchronized (list) {
|
||||
Iterator<DelayedLampEffect> effectIterator = playerEffects.iterator();
|
||||
while (effectIterator.hasNext() && playerBudget[0] > 0) {
|
||||
DelayedLampEffect effect = effectIterator.next();
|
||||
if (!effect.tick(playerBudget)) continue;
|
||||
effectIterator.remove();
|
||||
}
|
||||
}
|
||||
if (!playerEffects.isEmpty()) continue;
|
||||
perPlayerDelayedLampEffects.remove(entry.getKey(), playerEffects);
|
||||
}
|
||||
}
|
||||
|
||||
private record PotentialLampGroup(BlockPos representativePos, List<BlockPos> groupPositions, boolean originallyLit, long predeterminedLongOffDuration, double distanceSqToPlayer, long initialDelay) {
|
||||
}
|
||||
|
||||
private static class DelayedLampEffect {
|
||||
public ServerLevel level;
|
||||
public BlockPos representativeLampPos;
|
||||
public List<BlockPos> groupLampPositions;
|
||||
public boolean originallyLit;
|
||||
private final RandomSource random;
|
||||
private LampEffectStage currentStage;
|
||||
private long ticksUntilNextStageAction;
|
||||
private int flickersRemainingInCycle;
|
||||
private long actualLongOffDuration;
|
||||
private int lampUpdateProgressIndex = 0;
|
||||
private boolean currentPhaseTargetLitState;
|
||||
|
||||
public DelayedLampEffect(ServerLevel level, BlockPos representativeLampPos, List<BlockPos> allGroupPositions, long initialDelayTicks, boolean lit, long predeterminedLongOffDuration, RandomSource randomSource) {
|
||||
this.level = level;
|
||||
this.representativeLampPos = representativeLampPos;
|
||||
this.groupLampPositions = new ArrayList<BlockPos>(allGroupPositions);
|
||||
this.originallyLit = lit;
|
||||
this.actualLongOffDuration = predeterminedLongOffDuration;
|
||||
this.random = randomSource;
|
||||
this.currentStage = LampEffectStage.AWAITING_INITIAL_DELAY;
|
||||
this.ticksUntilNextStageAction = initialDelayTicks;
|
||||
}
|
||||
|
||||
private void playFlickerSound() {
|
||||
if (!ModSounds.LAMP_FLICKER_SOUNDS.isEmpty() && !this.groupLampPositions.isEmpty()) {
|
||||
SoundEvent flickerSound = (SoundEvent)ModSounds.LAMP_FLICKER_SOUNDS.get(this.random.m_188503_(ModSounds.LAMP_FLICKER_SOUNDS.size())).get();
|
||||
this.level.m_5594_(null, this.representativeLampPos, flickerSound, SoundSource.BLOCKS, 0.5f, 1.0f + (this.random.m_188501_() - 0.5f) * 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRandomPhaseDuration(int minTicks, int maxTicks) {
|
||||
if (minTicks >= maxTicks) {
|
||||
return minTicks;
|
||||
}
|
||||
return this.random.m_188503_(maxTicks - minTicks + 1) + minTicks;
|
||||
}
|
||||
|
||||
private boolean processLampUpdateBatch(int[] budget) {
|
||||
if (this.groupLampPositions.isEmpty()) {
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
return true;
|
||||
}
|
||||
for (int processedInThisEffectCall = 0; this.lampUpdateProgressIndex < this.groupLampPositions.size() && processedInThisEffectCall < 25 && budget[0] > 0; ++processedInThisEffectCall) {
|
||||
boolean currentlyLit;
|
||||
BlockPos posInGroup = this.groupLampPositions.get(this.lampUpdateProgressIndex);
|
||||
BlockState currentBlockState = this.level.m_8055_(posInGroup);
|
||||
if (currentBlockState.m_60713_(Blocks.f_50261_) && (currentlyLit = ((Boolean)currentBlockState.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) != this.currentPhaseTargetLitState) {
|
||||
this.level.m_7731_(posInGroup, (BlockState)currentBlockState.m_61124_((Property)BlockStateProperties.f_61443_, (Comparable)Boolean.valueOf(this.currentPhaseTargetLitState)), 2);
|
||||
budget[0] = budget[0] - 1;
|
||||
}
|
||||
++this.lampUpdateProgressIndex;
|
||||
}
|
||||
if (this.lampUpdateProgressIndex >= this.groupLampPositions.size()) {
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean tick(int[] budget) {
|
||||
if (this.currentStage == LampEffectStage.FINISHED) {
|
||||
return true;
|
||||
}
|
||||
--this.ticksUntilNextStageAction;
|
||||
if (this.ticksUntilNextStageAction <= 0L) {
|
||||
LampEffectStage nextStageDecision = this.currentStage;
|
||||
boolean phaseUpdateCompleted = false;
|
||||
switch (this.currentStage) {
|
||||
case AWAITING_INITIAL_DELAY: {
|
||||
this.flickersRemainingInCycle = 2 + this.random.m_188503_(4);
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_PREPARE_OFF: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_WAITING_OFF;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_WAITING_OFF: {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_PREPARE_ON: {
|
||||
this.currentPhaseTargetLitState = true;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_UPDATING_TO_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_UPDATING_TO_ON: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
--this.flickersRemainingInCycle;
|
||||
if (this.flickersRemainingInCycle > 0) {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_WAITING_ON;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_PREPARE;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_WAITING_ON: {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_PREPARE: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_WAITING;
|
||||
this.ticksUntilNextStageAction = this.actualLongOffDuration;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_WAITING: {
|
||||
this.flickersRemainingInCycle = 4;
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_PREPARE_ON: {
|
||||
this.currentPhaseTargetLitState = true;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_UPDATING_TO_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_UPDATING_TO_ON: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_WAITING_ON;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_WAITING_ON: {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_PREPARE_OFF: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
--this.flickersRemainingInCycle;
|
||||
if (this.flickersRemainingInCycle > 0) {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_WAITING_OFF;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
nextStageDecision = LampEffectStage.RESTORING_PREPARE;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_WAITING_OFF: {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case RESTORING_PREPARE: {
|
||||
this.currentPhaseTargetLitState = this.originallyLit;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
nextStageDecision = LampEffectStage.RESTORING_UPDATING_TO_ORIGINAL;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case RESTORING_UPDATING_TO_ORIGINAL: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.FINISHED;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.currentStage = nextStageDecision;
|
||||
}
|
||||
return this.currentStage == LampEffectStage.FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
private static enum LampEffectStage {
|
||||
AWAITING_INITIAL_DELAY,
|
||||
INITIAL_FLICKER_PREPARE_OFF,
|
||||
INITIAL_FLICKER_UPDATING_TO_OFF,
|
||||
INITIAL_FLICKER_WAITING_OFF,
|
||||
INITIAL_FLICKER_PREPARE_ON,
|
||||
INITIAL_FLICKER_UPDATING_TO_ON,
|
||||
INITIAL_FLICKER_WAITING_ON,
|
||||
LONG_OFF_PREPARE,
|
||||
LONG_OFF_UPDATING_TO_OFF,
|
||||
LONG_OFF_WAITING,
|
||||
FINAL_FLICKER_PREPARE_ON,
|
||||
FINAL_FLICKER_UPDATING_TO_ON,
|
||||
FINAL_FLICKER_WAITING_ON,
|
||||
FINAL_FLICKER_PREPARE_OFF,
|
||||
FINAL_FLICKER_UPDATING_TO_OFF,
|
||||
FINAL_FLICKER_WAITING_OFF,
|
||||
RESTORING_PREPARE,
|
||||
RESTORING_UPDATING_TO_ORIGINAL,
|
||||
FINISHED;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user