Merge remote-tracking branch 'origin/1.15' into 1.15

This commit is contained in:
modmuss50 2020-06-21 13:41:53 +01:00
commit 563421ed11
7 changed files with 190 additions and 208 deletions

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -3,7 +3,9 @@
"package": "net.fabricmc.fabric.mixin.client.particle",
"compatibilityLevel": "JAVA_8",
"client": [
"MixinParticleManager"
"MixinParticleManager",
"ParticleManagerAccessor",
"ParticleManagerAccessor$SimpleSpriteProviderAccessor"
],
"injectors": {
"defaultRequire": 1