From e249cb5fe8276cea5089a6a25ec9d223aeedaf32 Mon Sep 17 00:00:00 2001 From: George Paton Date: Sat, 16 Mar 2024 16:41:59 +1100 Subject: [PATCH 1/5] fix fog distance to work with longer render distances fix fog being cached when unnecessary --- src/main/java/com/hbm/main/ModEventHandlerRenderer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/hbm/main/ModEventHandlerRenderer.java b/src/main/java/com/hbm/main/ModEventHandlerRenderer.java index f70f25270..fd5bf7d78 100644 --- a/src/main/java/com/hbm/main/ModEventHandlerRenderer.java +++ b/src/main/java/com/hbm/main/ModEventHandlerRenderer.java @@ -428,8 +428,8 @@ public class ModEventHandlerRenderer { int[] ranges = ForgeModContainer.blendRanges; int distance = 0; - if(settings.fancyGraphics && settings.renderDistanceChunks >= 0 && settings.renderDistanceChunks < ranges.length) { - distance = ranges[settings.renderDistanceChunks]; + if(settings.fancyGraphics && settings.renderDistanceChunks >= 0) { + distance = ranges[Math.min(settings.renderDistanceChunks, ranges.length - 1)]; } float r = 0F; @@ -456,7 +456,7 @@ public class ModEventHandlerRenderer { if(doesBiomeApply) { fogRGBMultiplier = Vec3.createVectorHelper(r / divider, g / divider, b / divider); } else { - fogRGBMultiplier = Vec3.createVectorHelper(red, green, blue); + fogRGBMultiplier = null; } return fogRGBMultiplier; From 5ea0cae74c7c63278d5e81ce5ab3ebdb4883257a Mon Sep 17 00:00:00 2001 From: George Paton Date: Sun, 17 Mar 2024 14:52:25 +1100 Subject: [PATCH 2/5] Create virtual particles at each schottky for each valid exit, collapse the cheapest valid particle after analysis --- .../tileentity/machine/TileEntityHadron.java | 124 ++++++++++++------ 1 file changed, 86 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java index 173feb6de..04d496cd5 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java @@ -106,6 +106,9 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs power = Library.chargeTEFromItems(slots, 4, power, maxPower); drawPower(); + + particles.addAll(particlesToAdd); + particlesToAdd.clear(); if(delay <= 0 && this.isOn && particles.size() < maxParticles && slots[0] != null && slots[1] != null && power >= maxPower * 0.75) { @@ -133,6 +136,29 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs } particlesToRemove.clear(); + + // Sort the virtual particles by momentum, and run through them until we have enough momentum to complete the recipe + // If we succeed, "collapse" the cheapest particle that had enough momentum + // If we fail to make anything, "collapse" the most expensive particle + if (particles.isEmpty() && !particlesCompleted.isEmpty()) { + MainRegistry.logger.info("number of COMPLETED: " + particlesCompleted.size()); + + ItemStack[] result = null; + Particle particle = null; + + particlesCompleted.sort((p1, p2) -> { return p1.momentum - p2.momentum; }); + for(Particle p : particlesCompleted) { + MainRegistry.logger.info(p.momentum); + + particle = p; + result = HadronRecipes.getOutput(p.item1, p.item2, p.momentum, analysisOnly); + if(result != null) break; + } + + process(particle, result); + + particlesCompleted.clear(); + } NBTTagCompound data = new NBTTagCompound(); data.setBoolean("isOn", isOn); @@ -151,9 +177,9 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs } } - private void process(Particle p) { - - ItemStack[] result = HadronRecipes.getOutput(p.item1, p.item2, p.momentum, analysisOnly); + private void process(Particle p, ItemStack[] result) { + // Collapse this particle to real by consuming power + p.consumePower(); if(result == null) { this.state = HadronRecipes.returnCode; @@ -166,9 +192,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if((slots[2] == null || (slots[2].getItem() == result[0].getItem() && slots[2].stackSize < slots[2].getMaxStackSize())) && (slots[3] == null || (slots[3].getItem() == result[1].getItem() && slots[3].stackSize < slots[3].getMaxStackSize()))) { - for(int i = 2; i <= 3; i++ ) { - - //System.out.println("yes"); + for(int i = 2; i <= 3; i++) { if(slots[i] == null) slots[i] = result[i - 2].copy(); else @@ -252,17 +276,18 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs particlesToRemove.add(p); if(!p.isExpired()) - process(p); + particlesCompleted.add(p); p.expired = true; } static final int maxParticles = 1; - List particles = new ArrayList(); - List particlesToRemove = new ArrayList(); + List particles = new ArrayList(); + List particlesToRemove = new ArrayList(); + List particlesToAdd = new ArrayList(); + List particlesCompleted = new ArrayList(); private void updateParticles() { - for(Particle particle : particles) { particle.update(); } @@ -347,6 +372,12 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs int cl1 = 0; boolean expired = false; + boolean cloned = false; + + //Quantum mechanical ass particle + //Virtual particles traverse the accelerator without consuming electrical power + //The cheapest valid route to the analysis chamber is then turned into a real particle, consuming power + List plugs = new ArrayList(); public Particle(ItemStack item1, ItemStack item2, ForgeDirection dir, int posX, int posY, int posZ) { this.item1 = item1.copy(); @@ -361,6 +392,21 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs this.charge = 750; this.momentum = 0; } + + //Clones the particle and gives it a new direction + public Particle clone(ForgeDirection dir) { + Particle p = new Particle(item1, item2, dir, posX, posY, posZ); + p.momentum = momentum; + p.charge = charge; + p.analysis = analysis; + p.isCheckExempt = isCheckExempt; + p.cl0 = cl0; + p.cl1 = cl1; + p.expired = expired; + p.plugs = new ArrayList(plugs); + p.cloned = true; + return p; + } public void expire(EnumHadronState reason) { @@ -370,9 +416,6 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs this.expired = true; particlesToRemove.add(this); worldObj.newExplosion(null, posX + 0.5, posY + 0.5, posZ + 0.5, 10, false, false); - //System.out.println("Last dir: " + dir.name()); - //System.out.println("Last pos: " + posX + " " + posY + " " + posZ); - //Thread.currentThread().dumpStack(); TileEntityHadron.this.state = reason; TileEntityHadron.this.delay = delayError; @@ -388,7 +431,13 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if(expired) //just in case return; - changeDirection(this); + // Recently cloned particles have already set direction, disabling this causes infinite recursion + if (cloned) { + cloned = false; + } else { + changeDirection(this); + } + makeSteppy(this); if(!this.isExpired()) //only important for when the current segment is the core @@ -427,6 +476,14 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs this.momentum += coilVal; } + + public void consumePower() { + for(TileEntityHadronPower plug : plugs) { + long bit = 10000; + int times = (int) (plug.getPower() / bit); + plug.setPower(plug.getPower() - times * bit); + } + } } /** @@ -566,7 +623,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs int times = (int) (plug.getPower() / bit); //how many charges the plug has to offer p.charge += times; - plug.setPower(plug.getPower() - times * bit); + p.plugs.add(plug); continue; } @@ -575,9 +632,6 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if(p.isCheckExempt && ix + iy + iz == 2) { continue; } - - //System.out.println("Was exempt: " + p.isCheckExempt); - //worldObj.setBlock(a, b, c, Blocks.dirt); p.expire(EnumHadronState.ERROR_MALFORMED_SEGMENT); } @@ -594,8 +648,8 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs p.expire(EnumHadronState.ERROR_ANALYSIS_TOO_LONG); if(p.analysis == 2) { - this.worldObj.playSoundEffect(p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, "fireworks.blast", 2.0F, 2F); this.state = EnumHadronState.ANALYSIS; + this.worldObj.playSoundEffect(p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, "fireworks.blast", 2.0F, 2F); NBTTagCompound data = new NBTTagCompound(); data.setString("type", "hadron"); PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5), new TargetPoint(worldObj.provider.dimensionId, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, 25)); @@ -663,29 +717,23 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs p.isCheckExempt = true; TileEntityHadronDiode diode = (TileEntityHadronDiode)te; - - //the direction in which we were going anyway is an output, so we will keep going - if(diode.getConfig(dir.ordinal()) == DiodeConfig.OUT) { - return; - - //well then, iterate through some random directions and hope a valid output shows up - } else { - - List dirs = getRandomDirs(); - - for(ForgeDirection d : dirs) { - - if(d == dir || d == dir.getOpposite()) - continue; - - //looks like we can leave! - if(diode.getConfig(d.ordinal()) == DiodeConfig.OUT) { - //set the direction and leave this hellhole + + boolean hasTurnedCurrent = false; + + //Instance a new particle for each required fork + for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { + if(diode.getConfig(d.ordinal()) == DiodeConfig.OUT) { + if(!hasTurnedCurrent) { p.dir = d; - return; + hasTurnedCurrent = true; + } else { + particlesToAdd.add(p.clone(d)); } } } + + //If we managed to exit, keep going + if (hasTurnedCurrent) return; } //next step is air or the core, proceed From 942a05fea76bde513ea8a3a36c16cc3d5d31d0a9 Mon Sep 17 00:00:00 2001 From: George Paton Date: Sun, 17 Mar 2024 15:20:08 +1100 Subject: [PATCH 3/5] Only pop the first analysis particle --- .../hbm/tileentity/machine/TileEntityHadron.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java index 04d496cd5..1aef7f45f 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java @@ -141,15 +141,11 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs // If we succeed, "collapse" the cheapest particle that had enough momentum // If we fail to make anything, "collapse" the most expensive particle if (particles.isEmpty() && !particlesCompleted.isEmpty()) { - MainRegistry.logger.info("number of COMPLETED: " + particlesCompleted.size()); - ItemStack[] result = null; Particle particle = null; particlesCompleted.sort((p1, p2) -> { return p1.momentum - p2.momentum; }); for(Particle p : particlesCompleted) { - MainRegistry.logger.info(p.momentum); - particle = p; result = HadronRecipes.getOutput(p.item1, p.item2, p.momentum, analysisOnly); if(result != null) break; @@ -648,11 +644,14 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs p.expire(EnumHadronState.ERROR_ANALYSIS_TOO_LONG); if(p.analysis == 2) { + // Only pop for the first particle + if(this.state != EnumHadronState.ANALYSIS) { + this.worldObj.playSoundEffect(p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, "fireworks.blast", 2.0F, 2F); + NBTTagCompound data = new NBTTagCompound(); + data.setString("type", "hadron"); + PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5), new TargetPoint(worldObj.provider.dimensionId, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, 25)); + } this.state = EnumHadronState.ANALYSIS; - this.worldObj.playSoundEffect(p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, "fireworks.blast", 2.0F, 2F); - NBTTagCompound data = new NBTTagCompound(); - data.setString("type", "hadron"); - PacketDispatcher.wrapper.sendToAllAround(new AuxParticlePacketNT(data, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5), new TargetPoint(worldObj.provider.dimensionId, p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, 25)); } //if operating in line accelerator mode, halt after 2 blocks and staart the reading From 4859904e6cac313dac94dcaa8239e96aa8738828 Mon Sep 17 00:00:00 2001 From: George Paton Date: Sun, 17 Mar 2024 15:33:04 +1100 Subject: [PATCH 4/5] If ANY coils fail, it'll now throw an error and not process the particle, even if there is a valid route. This should make it easier to diagnose errors --- .../tileentity/machine/TileEntityHadron.java | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java index 1aef7f45f..098bffdc8 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java @@ -348,6 +348,22 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs this.stat_z = z; this.stat_success = false; } + + public void expire(Particle particle, EnumHadronState reason) { + if(particle.expired) + return; + + particle.consumePower(); + for(Particle p : particles) { + p.expired = true; + particlesToRemove.add(p); + } + worldObj.newExplosion(null, particle.posX + 0.5, particle.posY + 0.5, particle.posZ + 0.5, 10, false, false); + + TileEntityHadron.this.state = reason; + TileEntityHadron.this.delay = delayError; + TileEntityHadron.this.setExpireStats(reason, particle.momentum, particle.posX, particle.posY, particle.posZ); + } public class Particle { @@ -404,20 +420,6 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs return p; } - public void expire(EnumHadronState reason) { - - if(expired) - return; - - this.expired = true; - particlesToRemove.add(this); - worldObj.newExplosion(null, posX + 0.5, posY + 0.5, posZ + 0.5, 10, false, false); - - TileEntityHadron.this.state = reason; - TileEntityHadron.this.delay = delayError; - TileEntityHadron.this.setExpireStats(reason, this.momentum, posX, posY, posZ); - } - public boolean isExpired() { return this.expired; } @@ -442,7 +444,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs isCheckExempt = false; //clearing up the exemption we might have held from the previous turn, AFTER stepping if(charge < 0) - this.expire(EnumHadronState.ERROR_NO_CHARGE); + expire(this, EnumHadronState.ERROR_NO_CHARGE); if(cl0 > 0) cl0--; if(cl1 > 0) cl1--; @@ -505,7 +507,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if(te instanceof TileEntityHadron) { if(p.analysis != 3) - p.expire(EnumHadronState.ERROR_NO_ANALYSIS); + expire(p, EnumHadronState.ERROR_NO_ANALYSIS); else this.finishParticle(p); @@ -513,7 +515,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs } if(block.getMaterial() != Material.air && block != ModBlocks.hadron_diode) - p.expire(EnumHadronState.ERROR_OBSTRUCTED_CHANNEL); + expire(p, EnumHadronState.ERROR_OBSTRUCTED_CHANNEL); if(block == ModBlocks.hadron_diode) p.isCheckExempt = true; @@ -585,7 +587,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs //not a valid coil: kablam! if(!isValidCoil(block)) { - p.expire(EnumHadronState.ERROR_EXPECTED_COIL); + expire(p, EnumHadronState.ERROR_EXPECTED_COIL); } else { p.charge -= coilVal; p.incrementCharge(block, meta, coilVal); @@ -629,7 +631,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs continue; } - p.expire(EnumHadronState.ERROR_MALFORMED_SEGMENT); + expire(p, EnumHadronState.ERROR_MALFORMED_SEGMENT); } } } @@ -641,7 +643,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs //if the analysis chamber is too big, destroy if(p.analysis > 3) - p.expire(EnumHadronState.ERROR_ANALYSIS_TOO_LONG); + expire(p, EnumHadronState.ERROR_ANALYSIS_TOO_LONG); if(p.analysis == 2) { // Only pop for the first particle @@ -663,7 +665,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs //if the analysis stops despite being short of 3 steps in the analysis chamber, destroy if(p.analysis > 0 && p.analysis < 3) - p.expire(EnumHadronState.ERROR_ANALYSIS_TOO_SHORT); + expire(p, EnumHadronState.ERROR_ANALYSIS_TOO_SHORT); } } @@ -694,7 +696,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if(diode.getConfig(p.dir.getOpposite().ordinal()) != DiodeConfig.IN) { //it appears as if we have slammed into the side of a diode, ouch - p.expire(EnumHadronState.ERROR_DIODE_COLLISION); + expire(p, EnumHadronState.ERROR_DIODE_COLLISION); } //there's a diode ahead, turn off checks so we can make the curve @@ -761,7 +763,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs //it seems like there are two or more possible ways, which is not allowed without a diode //sorry kid, nothing personal } else { - p.expire(EnumHadronState.ERROR_BRANCHING_TURN); + expire(p, EnumHadronState.ERROR_BRANCHING_TURN); return; } } @@ -773,7 +775,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs return; } - p.expire(EnumHadronState.ERROR_OBSTRUCTED_CHANNEL); + expire(p, EnumHadronState.ERROR_OBSTRUCTED_CHANNEL); } /** From 3a611feff1c29f5cbcc1c620306b605a16f8944b Mon Sep 17 00:00:00 2001 From: George Paton Date: Sun, 17 Mar 2024 16:47:31 +1100 Subject: [PATCH 5/5] Ensure particles only travel through a given schottky direction ONCE. Also code cleanup --- .../tileentity/machine/TileEntityHadron.java | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java index 098bffdc8..213fc6d59 100644 --- a/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java +++ b/src/main/java/com/hbm/tileentity/machine/TileEntityHadron.java @@ -3,6 +3,7 @@ package com.hbm.tileentity.machine; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import com.hbm.blocks.ModBlocks; @@ -137,10 +138,10 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs particlesToRemove.clear(); - // Sort the virtual particles by momentum, and run through them until we have enough momentum to complete the recipe - // If we succeed, "collapse" the cheapest particle that had enough momentum - // If we fail to make anything, "collapse" the most expensive particle - if (particles.isEmpty() && !particlesCompleted.isEmpty()) { + //Sort the virtual particles by momentum, and run through them until we have enough momentum to complete the recipe + //If we succeed, "collapse" the cheapest particle that had enough momentum + //If we fail to make anything, "collapse" the most expensive particle + if(particles.isEmpty() && !particlesCompleted.isEmpty()) { ItemStack[] result = null; Particle particle = null; @@ -174,7 +175,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs } private void process(Particle p, ItemStack[] result) { - // Collapse this particle to real by consuming power + //Collapse this particle to real by consuming power p.consumePower(); if(result == null) { @@ -360,6 +361,9 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs } worldObj.newExplosion(null, particle.posX + 0.5, particle.posY + 0.5, particle.posZ + 0.5, 10, false, false); + //If any particles expire, cancel any succeeding particles, since they'll confuse the player + particlesCompleted.clear(); + TileEntityHadron.this.state = reason; TileEntityHadron.this.delay = delayError; TileEntityHadron.this.setExpireStats(reason, particle.momentum, particle.posX, particle.posY, particle.posZ); @@ -390,6 +394,10 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs //Virtual particles traverse the accelerator without consuming electrical power //The cheapest valid route to the analysis chamber is then turned into a real particle, consuming power List plugs = new ArrayList(); + + //Quantum particles should only traverse a schottky direction ONCE + //Keep a list of traversed diodes and directions + HashMap> history = new HashMap>(); public Particle(ItemStack item1, ItemStack item2, ForgeDirection dir, int posX, int posY, int posZ) { this.item1 = item1.copy(); @@ -416,6 +424,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs p.cl1 = cl1; p.expired = expired; p.plugs = new ArrayList(plugs); + p.history = new HashMap>(history); p.cloned = true; return p; } @@ -429,8 +438,8 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs if(expired) //just in case return; - // Recently cloned particles have already set direction, disabling this causes infinite recursion - if (cloned) { + //Recently cloned particles have already a set direction, this prevents infinite recursion + if(cloned) { cloned = false; } else { changeDirection(this); @@ -646,7 +655,7 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs expire(p, EnumHadronState.ERROR_ANALYSIS_TOO_LONG); if(p.analysis == 2) { - // Only pop for the first particle + //Only pop for the first particle if(this.state != EnumHadronState.ANALYSIS) { this.worldObj.playSoundEffect(p.posX + 0.5, p.posY + 0.5, p.posZ + 0.5, "fireworks.blast", 2.0F, 2F); NBTTagCompound data = new NBTTagCompound(); @@ -721,20 +730,30 @@ public class TileEntityHadron extends TileEntityMachineBase implements IEnergyUs boolean hasTurnedCurrent = false; + if(!p.history.containsKey(diode)) + p.history.put(diode, new ArrayList()); + + List usedDirections = p.history.get(diode); + //Instance a new particle for each required fork for(ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) { - if(diode.getConfig(d.ordinal()) == DiodeConfig.OUT) { + if(!usedDirections.contains(d) && diode.getConfig(d.ordinal()) == DiodeConfig.OUT) { if(!hasTurnedCurrent) { p.dir = d; hasTurnedCurrent = true; } else { - particlesToAdd.add(p.clone(d)); + Particle clone = p.clone(d); + clone.history.get(diode).add(d); + particlesToAdd.add(clone); } } } + //Add the used direction to the main particle AFTER cloning, so the clones don't get incorrect travel history + usedDirections.add(p.dir); + //If we managed to exit, keep going - if (hasTurnedCurrent) return; + if(hasTurnedCurrent) return; } //next step is air or the core, proceed