mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-28 10:36:43 -05:00
Simplify fabric-particles-v1 and resolve sprites not being added to the particle sprite atlas (#534)
This commit is contained in:
parent
bb1a063356
commit
da6c23c5f1
7 changed files with 190 additions and 208 deletions
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.particle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import net.minecraft.client.particle.ParticleTextureData;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
|
||||
import net.fabricmc.fabric.api.client.particle.v1.FabricSpriteProvider;
|
||||
|
||||
public final class FabricParticleManager {
|
||||
private final VanillaParticleManager manager;
|
||||
|
||||
private final Int2ObjectMap<FabricSpriteProviderImpl> providers = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
public FabricParticleManager(VanillaParticleManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void injectValues() {
|
||||
manager.getFactories().putAll(ParticleFactoryRegistryImpl.INSTANCE.factories);
|
||||
ParticleFactoryRegistryImpl.INSTANCE.constructors.forEach((id, factory) -> {
|
||||
FabricSpriteProviderImpl provider = new FabricSpriteProviderImpl();
|
||||
|
||||
providers.put((int) id, provider);
|
||||
manager.getFactories().put((int) id, factory.create(provider));
|
||||
});
|
||||
}
|
||||
|
||||
private FabricSpriteProviderImpl getProvider(Identifier id) {
|
||||
if (!ParticleFactoryRegistryImpl.INSTANCE.constructorsIdsMap.containsKey(id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return providers.get((int) ParticleFactoryRegistryImpl.INSTANCE.constructorsIdsMap.get(id));
|
||||
}
|
||||
|
||||
public boolean loadParticle(ResourceManager manager, Identifier id) {
|
||||
FabricSpriteProviderImpl provider = getProvider(id);
|
||||
|
||||
if (provider == null) {
|
||||
return false; // preserve vanilla behaviour (i don't got dis)
|
||||
}
|
||||
|
||||
Identifier file = new Identifier(id.getNamespace(), "particles/" + id.getPath() + ".json");
|
||||
|
||||
try (Reader reader = new InputStreamReader(manager.getResource(file).getInputStream(), StandardCharsets.UTF_8)) {
|
||||
List<Identifier> spriteIds = ParticleTextureData.load(JsonHelper.deserialize(reader)).getTextureList();
|
||||
|
||||
if (spriteIds == null) {
|
||||
// Particles should have a list of picks, even if it's just empty.
|
||||
throw new IllegalStateException("(Fabric) Missing texture list for particle " + id);
|
||||
}
|
||||
|
||||
provider.setSprites(spriteIds);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to load description for particle " + id, e);
|
||||
}
|
||||
|
||||
return true; // i got dis
|
||||
}
|
||||
|
||||
private final class FabricSpriteProviderImpl implements FabricSpriteProvider {
|
||||
private List<Identifier> spriteIds;
|
||||
|
||||
// @Nullable
|
||||
private List<Sprite> sprites;
|
||||
|
||||
@Override
|
||||
public Sprite getSprite(int min, int max) {
|
||||
return getSprites().get(min * (getSprites().size() - 1) / max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite(Random random_1) {
|
||||
return getSprites().get(random_1.nextInt(getSprites().size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteAtlasTexture getAtlas() {
|
||||
return manager.getAtlas();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sprite> getSprites() {
|
||||
if (sprites == null) {
|
||||
sprites = spriteIds.stream().map(getAtlas()::getSprite).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return sprites;
|
||||
}
|
||||
|
||||
public void setSprites(List<Identifier> sprites) {
|
||||
this.sprites = null;
|
||||
this.spriteIds = ImmutableList.copyOf(sprites);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.particle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.particle.SpriteProvider;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
|
||||
import net.fabricmc.fabric.api.client.particle.v1.FabricSpriteProvider;
|
||||
import net.fabricmc.fabric.mixin.client.particle.ParticleManagerAccessor;
|
||||
|
||||
public class FabricSpriteProviderImpl implements FabricSpriteProvider {
|
||||
private final ParticleManager particleManager;
|
||||
private final SpriteProvider delegate;
|
||||
|
||||
FabricSpriteProviderImpl(ParticleManager particleManager, SpriteProvider delegate) {
|
||||
this.particleManager = particleManager;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteAtlasTexture getAtlas() {
|
||||
return ((ParticleManagerAccessor) particleManager).getParticleAtlasTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Sprite> getSprites() {
|
||||
return ((ParticleManagerAccessor.SimpleSpriteProviderAccessor) delegate).getSprites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite(int i, int j) {
|
||||
return delegate.getSprite(i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getSprite(Random random) {
|
||||
return delegate.getSprite(random);
|
||||
}
|
||||
}
|
|
@ -16,37 +16,116 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.client.particle;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import net.minecraft.client.particle.ParticleFactory;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.particle.SpriteProvider;
|
||||
import net.minecraft.particle.ParticleEffect;
|
||||
import net.minecraft.particle.ParticleType;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.fabric.api.client.particle.v1.FabricSpriteProvider;
|
||||
import net.fabricmc.fabric.mixin.client.particle.ParticleManagerAccessor;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry;
|
||||
|
||||
public final class ParticleFactoryRegistryImpl implements ParticleFactoryRegistry {
|
||||
public static final ParticleFactoryRegistryImpl INSTANCE = new ParticleFactoryRegistryImpl();
|
||||
|
||||
final Int2ObjectMap<ParticleFactory<?>> factories = new Int2ObjectOpenHashMap<>();
|
||||
final Int2ObjectMap<PendingParticleFactory<?>> constructors = new Int2ObjectOpenHashMap<>();
|
||||
final Map<Identifier, Integer> constructorsIdsMap = new HashMap<>();
|
||||
static class DeferredParticleFactoryRegistry implements ParticleFactoryRegistry {
|
||||
private final Map<ParticleType<?>, ParticleFactory<?>> factories = new IdentityHashMap<>();
|
||||
private final Map<ParticleType<?>, PendingParticleFactory<?>> constructors = new IdentityHashMap<>();
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, ParticleFactory<T> factory) {
|
||||
factories.put(type, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, PendingParticleFactory<T> factory) {
|
||||
constructors.put(type, factory);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void applyTo(ParticleFactoryRegistry registry) {
|
||||
for (Map.Entry<ParticleType<?>, ParticleFactory<?>> entry : factories.entrySet()) {
|
||||
ParticleType type = entry.getKey();
|
||||
ParticleFactory factory = entry.getValue();
|
||||
registry.register(type, factory);
|
||||
}
|
||||
|
||||
for (Map.Entry<ParticleType<?>, PendingParticleFactory<?>> entry : constructors.entrySet()) {
|
||||
ParticleType type = entry.getKey();
|
||||
PendingParticleFactory constructor = entry.getValue();
|
||||
registry.register(type, constructor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class DirectParticleFactoryRegistry implements ParticleFactoryRegistry {
|
||||
private static final Constructor<? extends SpriteProvider> SIMPLE_SPRITE_PROVIDER_CONSTRUCTOR;
|
||||
static {
|
||||
try {
|
||||
String intermediaryClassName = "net.minecraft.class_702$class_4090";
|
||||
String currentClassName = FabricLoader.getInstance().getMappingResolver().mapClassName("intermediary", intermediaryClassName);
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends SpriteProvider> clazz = (Class<? extends SpriteProvider>) Class.forName(currentClassName);
|
||||
SIMPLE_SPRITE_PROVIDER_CONSTRUCTOR = clazz.getDeclaredConstructor(ParticleManager.class);
|
||||
SIMPLE_SPRITE_PROVIDER_CONSTRUCTOR.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to register particles", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static SpriteProvider createSimpleSpriteProvider(ParticleManager particleManager) {
|
||||
try {
|
||||
return SIMPLE_SPRITE_PROVIDER_CONSTRUCTOR.newInstance(particleManager);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to create SimpleSpriteProvider", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final ParticleManager particleManager;
|
||||
|
||||
DirectParticleFactoryRegistry(ParticleManager particleManager) {
|
||||
this.particleManager = particleManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, ParticleFactory<T> factory) {
|
||||
((ParticleManagerAccessor) particleManager).getFactories().put(Registry.PARTICLE_TYPE.getRawId(type), factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, PendingParticleFactory<T> constructor) {
|
||||
SpriteProvider delegate = createSimpleSpriteProvider(particleManager);
|
||||
FabricSpriteProvider fabricSpriteProvider = new FabricSpriteProviderImpl(particleManager, delegate);
|
||||
((ParticleManagerAccessor) particleManager).getSpriteAwareFactories().put(Registry.PARTICLE_TYPE.getId(type), delegate);
|
||||
register(type, constructor.create(fabricSpriteProvider));
|
||||
}
|
||||
}
|
||||
|
||||
ParticleFactoryRegistry internalRegistry = new DeferredParticleFactoryRegistry();
|
||||
|
||||
private ParticleFactoryRegistryImpl() { }
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, ParticleFactory<T> factory) {
|
||||
factories.put(Registry.PARTICLE_TYPE.getRawId(type), factory);
|
||||
internalRegistry.register(type, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, PendingParticleFactory<T> factory) {
|
||||
constructors.put(Registry.PARTICLE_TYPE.getRawId(type), factory);
|
||||
constructorsIdsMap.put(Registry.PARTICLE_TYPE.getId(type), Registry.PARTICLE_TYPE.getRawId(type));
|
||||
public <T extends ParticleEffect> void register(ParticleType<T> type, PendingParticleFactory<T> constructor) {
|
||||
internalRegistry.register(type, constructor);
|
||||
}
|
||||
|
||||
public void initialize(ParticleManager particleManager) {
|
||||
ParticleFactoryRegistry newRegistry = new DirectParticleFactoryRegistry(particleManager);
|
||||
DeferredParticleFactoryRegistry oldRegistry = (DeferredParticleFactoryRegistry) internalRegistry;
|
||||
oldRegistry.applyTo(newRegistry);
|
||||
internalRegistry = newRegistry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.impl.client.particle;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import net.minecraft.client.particle.ParticleFactory;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
|
||||
/**
|
||||
* Accessors for some private members of ParticleManager.
|
||||
*
|
||||
* <p>Usage:
|
||||
* <pre> {@code
|
||||
* SpriteAtlasTexture atlas = ((VanillaParticleManager)MinecraftClient.getInstance().particleManager).getAtlas()
|
||||
* }</pre>
|
||||
*/
|
||||
public interface VanillaParticleManager {
|
||||
SpriteAtlasTexture getAtlas();
|
||||
|
||||
Int2ObjectMap<ParticleFactory<?>> getFactories();
|
||||
}
|
|
@ -16,48 +16,19 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.client.particle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.particle.ParticleFactory;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.particle.FabricParticleManager;
|
||||
import net.fabricmc.fabric.impl.client.particle.VanillaParticleManager;
|
||||
import net.fabricmc.fabric.impl.client.particle.ParticleFactoryRegistryImpl;
|
||||
|
||||
@Mixin(ParticleManager.class)
|
||||
public abstract class MixinParticleManager implements VanillaParticleManager {
|
||||
private final FabricParticleManager fabricParticleManager = new FabricParticleManager(this);
|
||||
|
||||
@Override
|
||||
@Accessor("particleAtlasTexture")
|
||||
public abstract SpriteAtlasTexture getAtlas();
|
||||
|
||||
@Override
|
||||
@Accessor("factories")
|
||||
public abstract Int2ObjectMap<ParticleFactory<?>> getFactories();
|
||||
|
||||
public abstract class MixinParticleManager {
|
||||
@Inject(method = "registerDefaultFactories()V", at = @At("RETURN"))
|
||||
private void onRegisterDefaultFactories(CallbackInfo info) {
|
||||
fabricParticleManager.injectValues();
|
||||
}
|
||||
|
||||
@Inject(method = "loadTextureList(Lnet/minecraft/resource/ResourceManager;Lnet/minecraft/util/Identifier;Ljava/util/Map;)V",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true)
|
||||
private void onLoadTextureList(ResourceManager manager, Identifier id, Map<Identifier, List<Identifier>> output, CallbackInfo info) {
|
||||
if (fabricParticleManager.loadParticle(manager, id)) {
|
||||
info.cancel();
|
||||
}
|
||||
ParticleFactoryRegistryImpl.INSTANCE.initialize((ParticleManager) (Object) this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package net.fabricmc.fabric.mixin.client.particle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.particle.ParticleFactory;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.particle.SpriteProvider;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
@Mixin(ParticleManager.class)
|
||||
public interface ParticleManagerAccessor {
|
||||
@Accessor("particleAtlasTexture")
|
||||
SpriteAtlasTexture getParticleAtlasTexture();
|
||||
|
||||
@Accessor("factories")
|
||||
Int2ObjectMap<ParticleFactory<?>> getFactories();
|
||||
|
||||
// NOTE: The field signature is actually Map<Identifier, SimpleSpriteProvider>
|
||||
// This still works due to type erasure
|
||||
@Accessor("spriteAwareFactories")
|
||||
Map<Identifier, SpriteProvider> getSpriteAwareFactories();
|
||||
|
||||
@Mixin(targets = "net/minecraft/client/particle/ParticleManager$SimpleSpriteProvider")
|
||||
interface SimpleSpriteProviderAccessor {
|
||||
@Accessor("sprites")
|
||||
List<Sprite> getSprites();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,9 @@
|
|||
"package": "net.fabricmc.fabric.mixin.client.particle",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"client": [
|
||||
"MixinParticleManager"
|
||||
"MixinParticleManager",
|
||||
"ParticleManagerAccessor",
|
||||
"ParticleManagerAccessor$SimpleSpriteProviderAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
Loading…
Reference in a new issue