Spaces:
Build error
Build error
package net.minecraft.client.particle; | |
import com.google.common.collect.EvictingQueue; | |
import com.google.common.collect.ImmutableList; | |
import com.google.common.collect.Lists; | |
import com.google.common.collect.Maps; | |
import com.google.common.collect.Queues; | |
import com.mojang.blaze3d.vertex.PoseStack; | |
import com.mojang.blaze3d.vertex.VertexConsumer; | |
import com.mojang.logging.LogUtils; | |
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; | |
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; | |
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; | |
import java.io.IOException; | |
import java.io.Reader; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Objects; | |
import java.util.Optional; | |
import java.util.Queue; | |
import java.util.Set; | |
import java.util.concurrent.CompletableFuture; | |
import java.util.concurrent.Executor; | |
import java.util.stream.Collectors; | |
import javax.annotation.Nullable; | |
import net.minecraft.CrashReport; | |
import net.minecraft.CrashReportCategory; | |
import net.minecraft.ReportedException; | |
import net.minecraft.Util; | |
import net.minecraft.client.Camera; | |
import net.minecraft.client.multiplayer.ClientLevel; | |
import net.minecraft.client.renderer.MultiBufferSource; | |
import net.minecraft.client.renderer.texture.SpriteLoader; | |
import net.minecraft.client.renderer.texture.TextureAtlas; | |
import net.minecraft.client.renderer.texture.TextureAtlasSprite; | |
import net.minecraft.client.renderer.texture.TextureManager; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.core.Direction; | |
import net.minecraft.core.particles.ParticleGroup; | |
import net.minecraft.core.particles.ParticleOptions; | |
import net.minecraft.core.particles.ParticleType; | |
import net.minecraft.core.particles.ParticleTypes; | |
import net.minecraft.core.registries.BuiltInRegistries; | |
import net.minecraft.resources.FileToIdConverter; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.server.packs.resources.PreparableReloadListener; | |
import net.minecraft.server.packs.resources.Resource; | |
import net.minecraft.server.packs.resources.ResourceManager; | |
import net.minecraft.util.GsonHelper; | |
import net.minecraft.util.Mth; | |
import net.minecraft.util.RandomSource; | |
import net.minecraft.util.profiling.Profiler; | |
import net.minecraft.util.profiling.ProfilerFiller; | |
import net.minecraft.world.entity.Entity; | |
import net.minecraft.world.level.block.RenderShape; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.phys.AABB; | |
import net.minecraft.world.phys.shapes.VoxelShape; | |
import net.minecraftforge.api.distmarker.Dist; | |
import net.minecraftforge.api.distmarker.OnlyIn; | |
import org.slf4j.Logger; | |
public class ParticleEngine implements PreparableReloadListener { | |
private static final Logger LOGGER = LogUtils.getLogger(); | |
private static final FileToIdConverter PARTICLE_LISTER = FileToIdConverter.json("particles"); | |
private static final ResourceLocation PARTICLES_ATLAS_INFO = ResourceLocation.withDefaultNamespace("particles"); | |
private static final int MAX_PARTICLES_PER_LAYER = 16384; | |
private static final List<ParticleRenderType> RENDER_ORDER = List.of(ParticleRenderType.TERRAIN_SHEET, ParticleRenderType.PARTICLE_SHEET_OPAQUE, ParticleRenderType.PARTICLE_SHEET_TRANSLUCENT); | |
protected ClientLevel level; | |
private final Map<ParticleRenderType, Queue<Particle>> particles = Maps.newIdentityHashMap(); | |
private final Queue<TrackingEmitter> trackingEmitters = Queues.newArrayDeque(); | |
private final TextureManager textureManager; | |
private final RandomSource random = RandomSource.create(); | |
private final Int2ObjectMap<ParticleProvider<?>> providers = new Int2ObjectOpenHashMap<>(); | |
private final Queue<Particle> particlesToAdd = Queues.newArrayDeque(); | |
private final Map<ResourceLocation, ParticleEngine.MutableSpriteSet> spriteSets = Maps.newHashMap(); | |
private final TextureAtlas textureAtlas; | |
private final Object2IntOpenHashMap<ParticleGroup> trackedParticleCounts = new Object2IntOpenHashMap<>(); | |
public ParticleEngine(ClientLevel p_107299_, TextureManager p_107300_) { | |
this.textureAtlas = new TextureAtlas(TextureAtlas.LOCATION_PARTICLES); | |
p_107300_.register(this.textureAtlas.location(), this.textureAtlas); | |
this.level = p_107299_; | |
this.textureManager = p_107300_; | |
this.registerProviders(); | |
} | |
private void registerProviders() { | |
this.register(ParticleTypes.ANGRY_VILLAGER, HeartParticle.AngryVillagerProvider::new); | |
this.register(ParticleTypes.BLOCK_MARKER, new BlockMarker.Provider()); | |
this.register(ParticleTypes.BLOCK, new TerrainParticle.Provider()); | |
this.register(ParticleTypes.BUBBLE, BubbleParticle.Provider::new); | |
this.register(ParticleTypes.BUBBLE_COLUMN_UP, BubbleColumnUpParticle.Provider::new); | |
this.register(ParticleTypes.BUBBLE_POP, BubblePopParticle.Provider::new); | |
this.register(ParticleTypes.CAMPFIRE_COSY_SMOKE, CampfireSmokeParticle.CosyProvider::new); | |
this.register(ParticleTypes.CAMPFIRE_SIGNAL_SMOKE, CampfireSmokeParticle.SignalProvider::new); | |
this.register(ParticleTypes.CLOUD, PlayerCloudParticle.Provider::new); | |
this.register(ParticleTypes.COMPOSTER, SuspendedTownParticle.ComposterFillProvider::new); | |
this.register(ParticleTypes.CRIT, CritParticle.Provider::new); | |
this.register(ParticleTypes.CURRENT_DOWN, WaterCurrentDownParticle.Provider::new); | |
this.register(ParticleTypes.DAMAGE_INDICATOR, CritParticle.DamageIndicatorProvider::new); | |
this.register(ParticleTypes.DRAGON_BREATH, DragonBreathParticle.Provider::new); | |
this.register(ParticleTypes.DOLPHIN, SuspendedTownParticle.DolphinSpeedProvider::new); | |
this.register(ParticleTypes.DRIPPING_LAVA, DripParticle::createLavaHangParticle); | |
this.register(ParticleTypes.FALLING_LAVA, DripParticle::createLavaFallParticle); | |
this.register(ParticleTypes.LANDING_LAVA, DripParticle::createLavaLandParticle); | |
this.register(ParticleTypes.DRIPPING_WATER, DripParticle::createWaterHangParticle); | |
this.register(ParticleTypes.FALLING_WATER, DripParticle::createWaterFallParticle); | |
this.register(ParticleTypes.DUST, DustParticle.Provider::new); | |
this.register(ParticleTypes.DUST_COLOR_TRANSITION, DustColorTransitionParticle.Provider::new); | |
this.register(ParticleTypes.EFFECT, SpellParticle.Provider::new); | |
this.register(ParticleTypes.ELDER_GUARDIAN, new MobAppearanceParticle.Provider()); | |
this.register(ParticleTypes.ENCHANTED_HIT, CritParticle.MagicProvider::new); | |
this.register(ParticleTypes.ENCHANT, FlyTowardsPositionParticle.EnchantProvider::new); | |
this.register(ParticleTypes.END_ROD, EndRodParticle.Provider::new); | |
this.register(ParticleTypes.ENTITY_EFFECT, SpellParticle.MobEffectProvider::new); | |
this.register(ParticleTypes.EXPLOSION_EMITTER, new HugeExplosionSeedParticle.Provider()); | |
this.register(ParticleTypes.EXPLOSION, HugeExplosionParticle.Provider::new); | |
this.register(ParticleTypes.SONIC_BOOM, SonicBoomParticle.Provider::new); | |
this.register(ParticleTypes.FALLING_DUST, FallingDustParticle.Provider::new); | |
this.register(ParticleTypes.GUST, GustParticle.Provider::new); | |
this.register(ParticleTypes.SMALL_GUST, GustParticle.SmallProvider::new); | |
this.register(ParticleTypes.GUST_EMITTER_LARGE, new GustSeedParticle.Provider(3.0, 7, 0)); | |
this.register(ParticleTypes.GUST_EMITTER_SMALL, new GustSeedParticle.Provider(1.0, 3, 2)); | |
this.register(ParticleTypes.FIREWORK, FireworkParticles.SparkProvider::new); | |
this.register(ParticleTypes.FISHING, WakeParticle.Provider::new); | |
this.register(ParticleTypes.FLAME, FlameParticle.Provider::new); | |
this.register(ParticleTypes.INFESTED, SpellParticle.Provider::new); | |
this.register(ParticleTypes.SCULK_SOUL, SoulParticle.EmissiveProvider::new); | |
this.register(ParticleTypes.SCULK_CHARGE, SculkChargeParticle.Provider::new); | |
this.register(ParticleTypes.SCULK_CHARGE_POP, SculkChargePopParticle.Provider::new); | |
this.register(ParticleTypes.SOUL, SoulParticle.Provider::new); | |
this.register(ParticleTypes.SOUL_FIRE_FLAME, FlameParticle.Provider::new); | |
this.register(ParticleTypes.FLASH, FireworkParticles.FlashProvider::new); | |
this.register(ParticleTypes.HAPPY_VILLAGER, SuspendedTownParticle.HappyVillagerProvider::new); | |
this.register(ParticleTypes.HEART, HeartParticle.Provider::new); | |
this.register(ParticleTypes.INSTANT_EFFECT, SpellParticle.InstantProvider::new); | |
this.register(ParticleTypes.ITEM, new BreakingItemParticle.Provider()); | |
this.register(ParticleTypes.ITEM_SLIME, new BreakingItemParticle.SlimeProvider()); | |
this.register(ParticleTypes.ITEM_COBWEB, new BreakingItemParticle.CobwebProvider()); | |
this.register(ParticleTypes.ITEM_SNOWBALL, new BreakingItemParticle.SnowballProvider()); | |
this.register(ParticleTypes.LARGE_SMOKE, LargeSmokeParticle.Provider::new); | |
this.register(ParticleTypes.LAVA, LavaParticle.Provider::new); | |
this.register(ParticleTypes.MYCELIUM, SuspendedTownParticle.Provider::new); | |
this.register(ParticleTypes.NAUTILUS, FlyTowardsPositionParticle.NautilusProvider::new); | |
this.register(ParticleTypes.NOTE, NoteParticle.Provider::new); | |
this.register(ParticleTypes.POOF, ExplodeParticle.Provider::new); | |
this.register(ParticleTypes.PORTAL, PortalParticle.Provider::new); | |
this.register(ParticleTypes.RAIN, WaterDropParticle.Provider::new); | |
this.register(ParticleTypes.SMOKE, SmokeParticle.Provider::new); | |
this.register(ParticleTypes.WHITE_SMOKE, WhiteSmokeParticle.Provider::new); | |
this.register(ParticleTypes.SNEEZE, PlayerCloudParticle.SneezeProvider::new); | |
this.register(ParticleTypes.SNOWFLAKE, SnowflakeParticle.Provider::new); | |
this.register(ParticleTypes.SPIT, SpitParticle.Provider::new); | |
this.register(ParticleTypes.SWEEP_ATTACK, AttackSweepParticle.Provider::new); | |
this.register(ParticleTypes.TOTEM_OF_UNDYING, TotemParticle.Provider::new); | |
this.register(ParticleTypes.SQUID_INK, SquidInkParticle.Provider::new); | |
this.register(ParticleTypes.UNDERWATER, SuspendedParticle.UnderwaterProvider::new); | |
this.register(ParticleTypes.SPLASH, SplashParticle.Provider::new); | |
this.register(ParticleTypes.WITCH, SpellParticle.WitchProvider::new); | |
this.register(ParticleTypes.DRIPPING_HONEY, DripParticle::createHoneyHangParticle); | |
this.register(ParticleTypes.FALLING_HONEY, DripParticle::createHoneyFallParticle); | |
this.register(ParticleTypes.LANDING_HONEY, DripParticle::createHoneyLandParticle); | |
this.register(ParticleTypes.FALLING_NECTAR, DripParticle::createNectarFallParticle); | |
this.register(ParticleTypes.FALLING_SPORE_BLOSSOM, DripParticle::createSporeBlossomFallParticle); | |
this.register(ParticleTypes.SPORE_BLOSSOM_AIR, SuspendedParticle.SporeBlossomAirProvider::new); | |
this.register(ParticleTypes.ASH, AshParticle.Provider::new); | |
this.register(ParticleTypes.CRIMSON_SPORE, SuspendedParticle.CrimsonSporeProvider::new); | |
this.register(ParticleTypes.WARPED_SPORE, SuspendedParticle.WarpedSporeProvider::new); | |
this.register(ParticleTypes.DRIPPING_OBSIDIAN_TEAR, DripParticle::createObsidianTearHangParticle); | |
this.register(ParticleTypes.FALLING_OBSIDIAN_TEAR, DripParticle::createObsidianTearFallParticle); | |
this.register(ParticleTypes.LANDING_OBSIDIAN_TEAR, DripParticle::createObsidianTearLandParticle); | |
this.register(ParticleTypes.REVERSE_PORTAL, ReversePortalParticle.ReversePortalProvider::new); | |
this.register(ParticleTypes.WHITE_ASH, WhiteAshParticle.Provider::new); | |
this.register(ParticleTypes.SMALL_FLAME, FlameParticle.SmallFlameProvider::new); | |
this.register(ParticleTypes.DRIPPING_DRIPSTONE_WATER, DripParticle::createDripstoneWaterHangParticle); | |
this.register(ParticleTypes.FALLING_DRIPSTONE_WATER, DripParticle::createDripstoneWaterFallParticle); | |
this.register(ParticleTypes.CHERRY_LEAVES, FallingLeavesParticle.CherryProvider::new); | |
this.register(ParticleTypes.PALE_OAK_LEAVES, FallingLeavesParticle.PaleOakProvider::new); | |
this.register(ParticleTypes.DRIPPING_DRIPSTONE_LAVA, DripParticle::createDripstoneLavaHangParticle); | |
this.register(ParticleTypes.FALLING_DRIPSTONE_LAVA, DripParticle::createDripstoneLavaFallParticle); | |
this.register(ParticleTypes.VIBRATION, VibrationSignalParticle.Provider::new); | |
this.register(ParticleTypes.TRAIL, TrailParticle.Provider::new); | |
this.register(ParticleTypes.GLOW_SQUID_INK, SquidInkParticle.GlowInkProvider::new); | |
this.register(ParticleTypes.GLOW, GlowParticle.GlowSquidProvider::new); | |
this.register(ParticleTypes.WAX_ON, GlowParticle.WaxOnProvider::new); | |
this.register(ParticleTypes.WAX_OFF, GlowParticle.WaxOffProvider::new); | |
this.register(ParticleTypes.ELECTRIC_SPARK, GlowParticle.ElectricSparkProvider::new); | |
this.register(ParticleTypes.SCRAPE, GlowParticle.ScrapeProvider::new); | |
this.register(ParticleTypes.SHRIEK, ShriekParticle.Provider::new); | |
this.register(ParticleTypes.EGG_CRACK, SuspendedTownParticle.EggCrackProvider::new); | |
this.register(ParticleTypes.DUST_PLUME, DustPlumeParticle.Provider::new); | |
this.register(ParticleTypes.TRIAL_SPAWNER_DETECTED_PLAYER, TrialSpawnerDetectionParticle.Provider::new); | |
this.register(ParticleTypes.TRIAL_SPAWNER_DETECTED_PLAYER_OMINOUS, TrialSpawnerDetectionParticle.Provider::new); | |
this.register(ParticleTypes.VAULT_CONNECTION, FlyTowardsPositionParticle.VaultConnectionProvider::new); | |
this.register(ParticleTypes.DUST_PILLAR, new TerrainParticle.DustPillarProvider()); | |
this.register(ParticleTypes.RAID_OMEN, SpellParticle.Provider::new); | |
this.register(ParticleTypes.TRIAL_OMEN, SpellParticle.Provider::new); | |
this.register(ParticleTypes.OMINOUS_SPAWNING, FlyStraightTowardsParticle.OminousSpawnProvider::new); | |
this.register(ParticleTypes.BLOCK_CRUMBLE, new TerrainParticle.CrumblingProvider()); | |
} | |
private <T extends ParticleOptions> void register(ParticleType<T> p_107382_, ParticleProvider<T> p_107383_) { | |
this.providers.put(BuiltInRegistries.PARTICLE_TYPE.getId(p_107382_), p_107383_); | |
} | |
private <T extends ParticleOptions> void register(ParticleType<T> p_273423_, ParticleProvider.Sprite<T> p_273134_) { | |
this.register( | |
p_273423_, | |
p_272320_ -> (p_272323_, p_272324_, p_272325_, p_272326_, p_272327_, p_272328_, p_272329_, p_272330_) -> { | |
TextureSheetParticle texturesheetparticle = p_273134_.createParticle( | |
p_272323_, p_272324_, p_272325_, p_272326_, p_272327_, p_272328_, p_272329_, p_272330_ | |
); | |
if (texturesheetparticle != null) { | |
texturesheetparticle.pickSprite(p_272320_); | |
} | |
return texturesheetparticle; | |
} | |
); | |
} | |
private <T extends ParticleOptions> void register(ParticleType<T> p_107379_, ParticleEngine.SpriteParticleRegistration<T> p_107380_) { | |
ParticleEngine.MutableSpriteSet particleengine$mutablespriteset = new ParticleEngine.MutableSpriteSet(); | |
this.spriteSets.put(BuiltInRegistries.PARTICLE_TYPE.getKey(p_107379_), particleengine$mutablespriteset); | |
this.providers.put(BuiltInRegistries.PARTICLE_TYPE.getId(p_107379_), p_107380_.create(particleengine$mutablespriteset)); | |
} | |
public CompletableFuture<Void> reload( | |
PreparableReloadListener.PreparationBarrier p_107305_, ResourceManager p_107306_, Executor p_107309_, Executor p_107310_ | |
) { | |
record ParticleDefinition(ResourceLocation id, Optional<List<ResourceLocation>> sprites) { | |
} | |
CompletableFuture<List<ParticleDefinition>> completablefuture = CompletableFuture.<Map<ResourceLocation, Resource>>supplyAsync( | |
() -> PARTICLE_LISTER.listMatchingResources(p_107306_), p_107309_ | |
) | |
.thenCompose( | |
p_247914_ -> { | |
List<CompletableFuture<ParticleDefinition>> list = new ArrayList<>(p_247914_.size()); | |
p_247914_.forEach( | |
(p_247903_, p_247904_) -> { | |
ResourceLocation resourcelocation = PARTICLE_LISTER.fileToId(p_247903_); | |
list.add( | |
CompletableFuture.supplyAsync( | |
() -> new ParticleDefinition(resourcelocation, this.loadParticleDescription(resourcelocation, p_247904_)), p_107309_ | |
) | |
); | |
} | |
); | |
return Util.sequence(list); | |
} | |
); | |
CompletableFuture<SpriteLoader.Preparations> completablefuture1 = SpriteLoader.create(this.textureAtlas) | |
.loadAndStitch(p_107306_, PARTICLES_ATLAS_INFO, 0, p_107309_) | |
.thenCompose(SpriteLoader.Preparations::waitForUpload); | |
return CompletableFuture.allOf(completablefuture1, completablefuture).thenCompose(p_107305_::wait).thenAcceptAsync(p_357820_ -> { | |
this.clearParticles(); | |
ProfilerFiller profilerfiller = Profiler.get(); | |
profilerfiller.push("upload"); | |
SpriteLoader.Preparations spriteloader$preparations = completablefuture1.join(); | |
this.textureAtlas.upload(spriteloader$preparations); | |
profilerfiller.popPush("bindSpriteSets"); | |
Set<ResourceLocation> set = new HashSet<>(); | |
TextureAtlasSprite textureatlassprite = spriteloader$preparations.missing(); | |
completablefuture.join().forEach(p_247911_ -> { | |
Optional<List<ResourceLocation>> optional = p_247911_.sprites(); | |
if (!optional.isEmpty()) { | |
List<TextureAtlasSprite> list = new ArrayList<>(); | |
for (ResourceLocation resourcelocation : optional.get()) { | |
TextureAtlasSprite textureatlassprite1 = spriteloader$preparations.regions().get(resourcelocation); | |
if (textureatlassprite1 == null) { | |
set.add(resourcelocation); | |
list.add(textureatlassprite); | |
} else { | |
list.add(textureatlassprite1); | |
} | |
} | |
if (list.isEmpty()) { | |
list.add(textureatlassprite); | |
} | |
this.spriteSets.get(p_247911_.id()).rebind(list); | |
} | |
}); | |
if (!set.isEmpty()) { | |
LOGGER.warn("Missing particle sprites: {}", set.stream().sorted().map(ResourceLocation::toString).collect(Collectors.joining(","))); | |
} | |
profilerfiller.pop(); | |
}, p_107310_); | |
} | |
public void close() { | |
this.textureAtlas.clearTextureData(); | |
} | |
private Optional<List<ResourceLocation>> loadParticleDescription(ResourceLocation p_250648_, Resource p_248793_) { | |
if (!this.spriteSets.containsKey(p_250648_)) { | |
LOGGER.debug("Redundant texture list for particle: {}", p_250648_); | |
return Optional.empty(); | |
} else { | |
try { | |
Optional optional; | |
try (Reader reader = p_248793_.openAsReader()) { | |
ParticleDescription particledescription = ParticleDescription.fromJson(GsonHelper.parse(reader)); | |
optional = Optional.of(particledescription.getTextures()); | |
} | |
return optional; | |
} catch (IOException ioexception) { | |
throw new IllegalStateException("Failed to load description for particle " + p_250648_, ioexception); | |
} | |
} | |
} | |
public void createTrackingEmitter(Entity p_107330_, ParticleOptions p_107331_) { | |
this.trackingEmitters.add(new TrackingEmitter(this.level, p_107330_, p_107331_)); | |
} | |
public void createTrackingEmitter(Entity p_107333_, ParticleOptions p_107334_, int p_107335_) { | |
this.trackingEmitters.add(new TrackingEmitter(this.level, p_107333_, p_107334_, p_107335_)); | |
} | |
public Particle createParticle( | |
ParticleOptions p_107371_, double p_107372_, double p_107373_, double p_107374_, double p_107375_, double p_107376_, double p_107377_ | |
) { | |
Particle particle = this.makeParticle(p_107371_, p_107372_, p_107373_, p_107374_, p_107375_, p_107376_, p_107377_); | |
if (particle != null) { | |
this.add(particle); | |
return particle; | |
} else { | |
return null; | |
} | |
} | |
private <T extends ParticleOptions> Particle makeParticle( | |
T p_107396_, double p_107397_, double p_107398_, double p_107399_, double p_107400_, double p_107401_, double p_107402_ | |
) { | |
ParticleProvider<T> particleprovider = (ParticleProvider<T>)this.providers.get(BuiltInRegistries.PARTICLE_TYPE.getId(p_107396_.getType())); | |
return particleprovider == null | |
? null | |
: particleprovider.createParticle(p_107396_, this.level, p_107397_, p_107398_, p_107399_, p_107400_, p_107401_, p_107402_); | |
} | |
public void add(Particle p_107345_) { | |
Optional<ParticleGroup> optional = p_107345_.getParticleGroup(); | |
if (optional.isPresent()) { | |
if (this.hasSpaceInParticleLimit(optional.get())) { | |
this.particlesToAdd.add(p_107345_); | |
this.updateCount(optional.get(), 1); | |
} | |
} else { | |
this.particlesToAdd.add(p_107345_); | |
} | |
} | |
public void tick() { | |
this.particles.forEach((p_374602_, p_374603_) -> { | |
Profiler.get().push(p_374602_.toString()); | |
this.tickParticleList(p_374603_); | |
Profiler.get().pop(); | |
}); | |
if (!this.trackingEmitters.isEmpty()) { | |
List<TrackingEmitter> list = Lists.newArrayList(); | |
for (TrackingEmitter trackingemitter : this.trackingEmitters) { | |
trackingemitter.tick(); | |
if (!trackingemitter.isAlive()) { | |
list.add(trackingemitter); | |
} | |
} | |
this.trackingEmitters.removeAll(list); | |
} | |
Particle particle; | |
if (!this.particlesToAdd.isEmpty()) { | |
while ((particle = this.particlesToAdd.poll()) != null) { | |
this.particles.computeIfAbsent(particle.getRenderType(), p_107347_ -> EvictingQueue.create(16384)).add(particle); | |
} | |
} | |
} | |
private void tickParticleList(Collection<Particle> p_107385_) { | |
if (!p_107385_.isEmpty()) { | |
Iterator<Particle> iterator = p_107385_.iterator(); | |
while (iterator.hasNext()) { | |
Particle particle = iterator.next(); | |
this.tickParticle(particle); | |
if (!particle.isAlive()) { | |
particle.getParticleGroup().ifPresent(p_172289_ -> this.updateCount(p_172289_, -1)); | |
iterator.remove(); | |
} | |
} | |
} | |
} | |
private void updateCount(ParticleGroup p_172282_, int p_172283_) { | |
this.trackedParticleCounts.addTo(p_172282_, p_172283_); | |
} | |
private void tickParticle(Particle p_107394_) { | |
try { | |
p_107394_.tick(); | |
} catch (Throwable throwable) { | |
CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking Particle"); | |
CrashReportCategory crashreportcategory = crashreport.addCategory("Particle being ticked"); | |
crashreportcategory.setDetail("Particle", p_107394_::toString); | |
crashreportcategory.setDetail("Particle Type", p_107394_.getRenderType()::toString); | |
throw new ReportedException(crashreport); | |
} | |
} | |
public void render(Camera p_107340_, float p_107341_, MultiBufferSource.BufferSource p_377798_) { | |
for (ParticleRenderType particlerendertype : RENDER_ORDER) { | |
Queue<Particle> queue = this.particles.get(particlerendertype); | |
if (queue != null && !queue.isEmpty()) { | |
renderParticleType(p_107340_, p_107341_, p_377798_, particlerendertype, queue); | |
} | |
} | |
Queue<Particle> queue1 = this.particles.get(ParticleRenderType.CUSTOM); | |
if (queue1 != null && !queue1.isEmpty()) { | |
renderCustomParticles(p_107340_, p_107341_, p_377798_, queue1); | |
} | |
p_377798_.endBatch(); | |
} | |
private static void renderParticleType( | |
Camera p_376120_, float p_375470_, MultiBufferSource.BufferSource p_377543_, ParticleRenderType p_378369_, Queue<Particle> p_376283_ | |
) { | |
VertexConsumer vertexconsumer = p_377543_.getBuffer(Objects.requireNonNull(p_378369_.renderType())); | |
for (Particle particle : p_376283_) { | |
try { | |
particle.render(vertexconsumer, p_376120_, p_375470_); | |
} catch (Throwable throwable) { | |
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering Particle"); | |
CrashReportCategory crashreportcategory = crashreport.addCategory("Particle being rendered"); | |
crashreportcategory.setDetail("Particle", particle::toString); | |
crashreportcategory.setDetail("Particle Type", p_378369_::toString); | |
throw new ReportedException(crashreport); | |
} | |
} | |
} | |
private static void renderCustomParticles(Camera p_377913_, float p_376893_, MultiBufferSource.BufferSource p_376978_, Queue<Particle> p_375784_) { | |
PoseStack posestack = new PoseStack(); | |
for (Particle particle : p_375784_) { | |
try { | |
particle.renderCustom(posestack, p_376978_, p_377913_, p_376893_); | |
} catch (Throwable throwable) { | |
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering Particle"); | |
CrashReportCategory crashreportcategory = crashreport.addCategory("Particle being rendered"); | |
crashreportcategory.setDetail("Particle", particle::toString); | |
crashreportcategory.setDetail("Particle Type", "Custom"); | |
throw new ReportedException(crashreport); | |
} | |
} | |
} | |
public void setLevel( { ClientLevel p_107343_) | |
this.level = p_107343_; | |
this.clearParticles(); | |
this.trackingEmitters.clear(); | |
} | |
public void destroy(BlockPos p_107356_, BlockState p_107357_) { | |
if (!p_107357_.isAir() && p_107357_.shouldSpawnTerrainParticles()) { | |
VoxelShape voxelshape = p_107357_.getShape(this.level, p_107356_); | |
double d0 = 0.25; | |
voxelshape.forAllBoxes( | |
(p_172273_, p_172274_, p_172275_, p_172276_, p_172277_, p_172278_) -> { | |
double d1 = Math.min(1.0, p_172276_ - p_172273_); | |
double d2 = Math.min(1.0, p_172277_ - p_172274_); | |
double d3 = Math.min(1.0, p_172278_ - p_172275_); | |
int i = Math.max(2, Mth.ceil(d1 / 0.25)); | |
int j = Math.max(2, Mth.ceil(d2 / 0.25)); | |
int k = Math.max(2, Mth.ceil(d3 / 0.25)); | |
for (int l = 0; l < i; l++) { | |
for (int i1 = 0; i1 < j; i1++) { | |
for (int j1 = 0; j1 < k; j1++) { | |
double d4 = ((double)l + 0.5) / (double)i; | |
double d5 = ((double)i1 + 0.5) / (double)j; | |
double d6 = ((double)j1 + 0.5) / (double)k; | |
double d7 = d4 * d1 + p_172273_; | |
double d8 = d5 * d2 + p_172274_; | |
double d9 = d6 * d3 + p_172275_; | |
this.add( | |
new TerrainParticle( | |
this.level, | |
(double)p_107356_.getX() + d7, | |
(double)p_107356_.getY() + d8, | |
(double)p_107356_.getZ() + d9, | |
d4 - 0.5, | |
d5 - 0.5, | |
d6 - 0.5, | |
p_107357_, | |
p_107356_ | |
) | |
); | |
} | |
} | |
} | |
} | |
); | |
} | |
} | |
public void crack(BlockPos p_107368_, Direction p_107369_) { | |
BlockState blockstate = this.level.getBlockState(p_107368_); | |
if (blockstate.getRenderShape() != RenderShape.INVISIBLE && blockstate.shouldSpawnTerrainParticles()) { | |
int i = p_107368_.getX(); | |
int j = p_107368_.getY(); | |
int k = p_107368_.getZ(); | |
float f = 0.1F; | |
AABB aabb = blockstate.getShape(this.level, p_107368_).bounds(); | |
double d0 = (double)i + this.random.nextDouble() * (aabb.maxX - aabb.minX - 0.2F) + 0.1F + aabb.minX; | |
double d1 = (double)j + this.random.nextDouble() * (aabb.maxY - aabb.minY - 0.2F) + 0.1F + aabb.minY; | |
double d2 = (double)k + this.random.nextDouble() * (aabb.maxZ - aabb.minZ - 0.2F) + 0.1F + aabb.minZ; | |
if (p_107369_ == Direction.DOWN) { | |
d1 = (double)j + aabb.minY - 0.1F; | |
} | |
if (p_107369_ == Direction.UP) { | |
d1 = (double)j + aabb.maxY + 0.1F; | |
} | |
if (p_107369_ == Direction.NORTH) { | |
d2 = (double)k + aabb.minZ - 0.1F; | |
} | |
if (p_107369_ == Direction.SOUTH) { | |
d2 = (double)k + aabb.maxZ + 0.1F; | |
} | |
if (p_107369_ == Direction.WEST) { | |
d0 = (double)i + aabb.minX - 0.1F; | |
} | |
if (p_107369_ == Direction.EAST) { | |
d0 = (double)i + aabb.maxX + 0.1F; | |
} | |
this.add(new TerrainParticle(this.level, d0, d1, d2, 0.0, 0.0, 0.0, blockstate, p_107368_).setPower(0.2F).scale(0.6F)); | |
} | |
} | |
public String countParticles() { | |
return String.valueOf(this.particles.values().stream().mapToInt(Collection::size).sum()); | |
} | |
private boolean hasSpaceInParticleLimit(ParticleGroup p_172280_) { | |
return this.trackedParticleCounts.getInt(p_172280_) < p_172280_.getLimit(); | |
} | |
private void clearParticles() { | |
this.particles.clear(); | |
this.particlesToAdd.clear(); | |
this.trackingEmitters.clear(); | |
this.trackedParticleCounts.clear(); | |
} | |
static class MutableSpriteSet implements SpriteSet { | |
private List<TextureAtlasSprite> sprites; | |
public TextureAtlasSprite get(int p_107413_, int p_107414_) { | |
return this.sprites.get(p_107413_ * (this.sprites.size() - 1) / p_107414_); | |
} | |
public TextureAtlasSprite get(RandomSource p_233889_) { | |
return this.sprites.get(p_233889_.nextInt(this.sprites.size())); | |
} | |
public void rebind(List<TextureAtlasSprite> p_107416_) { | |
this.sprites = ImmutableList.copyOf(p_107416_); | |
} | |
} | |
interface SpriteParticleRegistration<T extends ParticleOptions> { | |
ParticleProvider<T> create(SpriteSet p_107420_); | |
} | |
} |