generated from MrSphay/codex-agent-repository-kit
396 lines
20 KiB
Java
396 lines
20 KiB
Java
/*
|
|
* 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;
|
|
|
|
}
|
|
}
|
|
|