diff --git a/common/src/main/java/me/shedaniel/architectury/registry/ParticleFactories.java b/common/src/main/java/me/shedaniel/architectury/registry/ParticleFactories.java new file mode 100644 index 00000000..2230bedf --- /dev/null +++ b/common/src/main/java/me/shedaniel/architectury/registry/ParticleFactories.java @@ -0,0 +1,55 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry; + +import me.shedaniel.architectury.annotations.ExpectPlatform; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; + +import java.util.List; + +@Environment(EnvType.CLIENT) +public final class ParticleFactories { + public interface ExtendedSpriteSet extends SpriteSet { + TextureAtlas getAtlas(); + List getSprites(); + } + + @ExpectPlatform + void register(ParticleType type, ParticleProvider provider) { + throw new AssertionError(); + } + + @ExpectPlatform + void register(ParticleType type, PendingParticleProvider constructor) { + throw new AssertionError(); + } + + @FunctionalInterface + public interface PendingParticleProvider { + ParticleProvider create(ExtendedSpriteSet spriteSet); + } +} diff --git a/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ParticleFactoriesImpl.java b/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ParticleFactoriesImpl.java new file mode 100644 index 00000000..b261c426 --- /dev/null +++ b/fabric/src/main/java/me/shedaniel/architectury/registry/fabric/ParticleFactoriesImpl.java @@ -0,0 +1,70 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry.fabric; + +import me.shedaniel.architectury.registry.ParticleFactories; +import net.fabricmc.fabric.api.client.particle.v1.FabricSpriteProvider; +import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; + +import java.util.List; +import java.util.Random; + +public class ParticleFactoriesImpl { + public static class ExtendedSpriteSetImpl implements ParticleFactories.ExtendedSpriteSet { + private final FabricSpriteProvider delegate; + + public ExtendedSpriteSetImpl(FabricSpriteProvider delegate) { + this.delegate = delegate; + } + + @Override + public TextureAtlas getAtlas() { + return delegate.getAtlas(); + } + + @Override + public List getSprites() { + return delegate.getSprites(); + } + + @Override + public TextureAtlasSprite get(int i, int j) { + return delegate.get(i, j); + } + + @Override + public TextureAtlasSprite get(Random random) { + return delegate.get(random); + } + } + + public static void register(ParticleType type, ParticleProvider provider) { + ParticleFactoryRegistry.getInstance().register(type, provider); + } + + public static void register(ParticleType type, ParticleFactories.PendingParticleProvider constructor) { + ParticleFactoryRegistry.getInstance().register(type, provider -> constructor.create(new ExtendedSpriteSetImpl(provider))); + } +} diff --git a/forge/src/main/java/me/shedaniel/architectury/mixin/forge/ParticleEngineAccessor.java b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/ParticleEngineAccessor.java new file mode 100644 index 00000000..84c12bec --- /dev/null +++ b/forge/src/main/java/me/shedaniel/architectury/mixin/forge/ParticleEngineAccessor.java @@ -0,0 +1,47 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.mixin.forge; + +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.resources.ResourceLocation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; +import java.util.Map; + +@Mixin(ParticleEngine.class) +public interface ParticleEngineAccessor { + @Accessor + TextureAtlas getTextureAtlas(); + + // this is actually a Map, but luckily type erasure saves the day + @Accessor + Map getProviders(); + + @Mixin(targets = "net/minecraft/client/particle/ParticleEngine$MutableSpriteSet") + interface MutableSpriteSetAccessor { + @Accessor + List getSprites(); + } +} diff --git a/forge/src/main/java/me/shedaniel/architectury/registry/forge/ParticleFactoriesImpl.java b/forge/src/main/java/me/shedaniel/architectury/registry/forge/ParticleFactoriesImpl.java new file mode 100644 index 00000000..58f21f5b --- /dev/null +++ b/forge/src/main/java/me/shedaniel/architectury/registry/forge/ParticleFactoriesImpl.java @@ -0,0 +1,108 @@ +/* + * This file is part of architectury. + * Copyright (C) 2020, 2021 architectury + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package me.shedaniel.architectury.registry.forge; + +import me.shedaniel.architectury.forge.ArchitecturyForge; +import me.shedaniel.architectury.mixin.forge.ParticleEngineAccessor; +import me.shedaniel.architectury.registry.ParticleFactories; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.ParticleEngine; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraftforge.client.event.ParticleFactoryRegisterEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +@Mod.EventBusSubscriber(modid = ArchitecturyForge.MOD_ID) +public class ParticleFactoriesImpl { + private static final class ExtendedSpriteSetImpl implements ParticleFactories.ExtendedSpriteSet { + private final ParticleEngine engine; + private final SpriteSet delegate; + + private ExtendedSpriteSetImpl(ParticleEngine engine, SpriteSet delegate) { + this.engine = engine; + this.delegate = delegate; + } + + @Override + public TextureAtlas getAtlas() { + return ((ParticleEngineAccessor) engine).getTextureAtlas(); + } + + @Override + public List getSprites() { + return ((ParticleEngineAccessor.MutableSpriteSetAccessor) delegate).getSprites(); + } + + @Override + public TextureAtlasSprite get(int i, int j) { + return delegate.get(i, j); + } + + @Override + public TextureAtlasSprite get(Random random) { + return delegate.get(random); + } + } + + private static ArrayList deferred = new ArrayList<>(); + + private static void _register(ParticleType type, ParticleProvider provider) { + Minecraft.getInstance().particleEngine.register(type, provider); + } + + private static void _register(ParticleType type, ParticleFactories.PendingParticleProvider constructor) { + Minecraft.getInstance().particleEngine.register(type, arg -> + constructor.create(new ExtendedSpriteSetImpl(Minecraft.getInstance().particleEngine, arg))); + } + + public static void register(ParticleType type, ParticleProvider provider) { + if (deferred == null) + _register(type, provider); + else + deferred.add(() -> _register(type, provider)); + } + + public static void register(ParticleType type, ParticleFactories.PendingParticleProvider constructor) { + if (deferred == null) + _register(type, constructor); + else + deferred.add(() -> _register(type, constructor)); + } + + @SubscribeEvent + public static void onParticleFactoryRegister(ParticleFactoryRegisterEvent unused) { + if (deferred != null) { + // run all deferred registrations + for (Runnable r : deferred) + r.run(); + // yeet deferred list - register immediately from now on + deferred = null; + } + } +} diff --git a/forge/src/main/resources/architectury.mixins.json b/forge/src/main/resources/architectury.mixins.json index 5a59dda3..4277a9aa 100644 --- a/forge/src/main/resources/architectury.mixins.json +++ b/forge/src/main/resources/architectury.mixins.json @@ -20,7 +20,9 @@ "MixinItemExtension", "MixinRegistryEntry", "MixinWorldEvent", - "MobSpawnSettingsBuilderAccessor" + "MobSpawnSettingsBuilderAccessor", + "ParticleEngineAccessor", + "ParticleEngineAccessor$MutableSpriteSetAccessor" ], "injectors": { "defaultRequire": 1