mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-08 21:14:41 -04:00
Add event for preventing particle tinting for colored blocks (#3146)
- Adds an event, `ParticleRenderEvents.ALLOW_BLOCK_DUST_TINT`, that checks if a block dust particle of a specific block can be tinted. - Bumps Fabric Loader requirement of fabric-particles-v1 to latest to disable Loader's mixin compatibility mode that ignores slices for certain At annotations. Signed-off-by: modmuss50 <modmuss50@gmail.com>
This commit is contained in:
parent
c956c0e61d
commit
86d48884d3
18 changed files with 354 additions and 1 deletions
fabric-particles-v1
build.gradle
src
client
java/net/fabricmc/fabric
resources
main/resources
testmod
java/net/fabricmc/fabric/test/particle
resources
testmodClient/java/net/fabricmc/fabric/test/particle/client
|
@ -7,6 +7,12 @@ loom {
|
|||
|
||||
moduleDependencies(project, ['fabric-api-base'])
|
||||
|
||||
testDependencies(project, [
|
||||
':fabric-command-api-v2',
|
||||
':fabric-rendering-v1',
|
||||
':fabric-resource-loader-v0'
|
||||
])
|
||||
|
||||
validateMixinNames {
|
||||
// Loom needs to handle inner mixins better
|
||||
exclude "**/ParticleManagerAccessor\$SimpleSpriteProviderAccessor.class"
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.api.client.particle.v1;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Events related to particle rendering.
|
||||
*/
|
||||
public final class ParticleRenderEvents {
|
||||
private ParticleRenderEvents() {
|
||||
}
|
||||
|
||||
/**
|
||||
* An event that checks if a {@linkplain net.minecraft.client.particle.BlockDustParticle block dust particle}
|
||||
* can be tinted using the corresponding block's {@linkplain net.minecraft.client.color.block.BlockColorProvider color provider}.
|
||||
*
|
||||
* <p>The default return value of this event is {@code true}. If any callback returns {@code false} for a given call,
|
||||
* further iteration will be canceled and the event invoker will return {@code false}.
|
||||
*/
|
||||
public static final Event<AllowBlockDustTint> ALLOW_BLOCK_DUST_TINT = EventFactory.createArrayBacked(AllowBlockDustTint.class, callbacks -> (state, world, pos) -> {
|
||||
for (AllowBlockDustTint callback : callbacks) {
|
||||
if (!callback.allowBlockDustTint(state, world, pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AllowBlockDustTint {
|
||||
/**
|
||||
* Checks whether a {@linkplain net.minecraft.client.particle.BlockDustParticle block dust particle} can be
|
||||
* tinted using the corresponding block's {@linkplain net.minecraft.client.color.block.BlockColorProvider color provider}.
|
||||
*
|
||||
* @param state the block state that the particle represents
|
||||
* @param world the world the particle is created in
|
||||
* @param pos the position of the particle
|
||||
* @return {@code true} if color provider tinting should be allowed, {@code false} otherwise
|
||||
*/
|
||||
boolean allowBlockDustTint(BlockState state, ClientWorld world, BlockPos pos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.mixin.client.particle;
|
||||
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.client.particle.BlockDustParticle;
|
||||
import net.minecraft.client.particle.SpriteBillboardParticle;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import net.fabricmc.fabric.api.client.particle.v1.ParticleRenderEvents;
|
||||
|
||||
// Implements ParticleRenderEvents.ALLOW_BLOCK_DUST_TINT
|
||||
@Mixin(BlockDustParticle.class)
|
||||
abstract class BlockDustParticleMixin extends SpriteBillboardParticle {
|
||||
@Shadow
|
||||
@Final
|
||||
private BlockPos blockPos;
|
||||
|
||||
private BlockDustParticleMixin() {
|
||||
super(null, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ModifyVariable(
|
||||
method = "<init>(Lnet/minecraft/client/world/ClientWorld;DDDDDDLnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;)V",
|
||||
at = @At("LOAD"),
|
||||
argsOnly = true,
|
||||
slice = @Slice(
|
||||
from = @At(value = "FIELD", target = "Lnet/minecraft/client/particle/BlockDustParticle;blue:F", ordinal = 0),
|
||||
to = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z")
|
||||
),
|
||||
allow = 1
|
||||
)
|
||||
private BlockState removeUntintableParticles(BlockState state) {
|
||||
if (!ParticleRenderEvents.ALLOW_BLOCK_DUST_TINT.invoker().allowBlockDustTint(state, world, blockPos)) {
|
||||
// As of 1.20.1, vanilla hardcodes grass block particles to not get tinted.
|
||||
return Blocks.GRASS_BLOCK.getDefaultState();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"package": "net.fabricmc.fabric.mixin.client.particle",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"client": [
|
||||
"BlockDustParticleMixin",
|
||||
"ParticleManagerMixin",
|
||||
"ParticleManagerAccessor",
|
||||
"ParticleManagerAccessor$SimpleSpriteProviderAccessor"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"FabricMC"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0"
|
||||
"fabricloader": ">=0.14.21"
|
||||
},
|
||||
"description": "Hooks for registering custom particles.",
|
||||
"mixins": [
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.test.particle;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
|
||||
public final class ParticleTestSetup implements ModInitializer {
|
||||
// The dust particles of this block are always tinted (default).
|
||||
public static final Block ALWAYS_TINTED = new ParticleTintTestBlock(AbstractBlock.Settings.of(Material.STONE).breakInstantly(), 0xFF00FF);
|
||||
// The dust particles of this block are only tinted when the block is broken over water.
|
||||
public static final Block TINTED_OVER_WATER = new ParticleTintTestBlock(AbstractBlock.Settings.of(Material.STONE).breakInstantly(), 0xFFFF00);
|
||||
// The dust particles of this block are never tinted.
|
||||
public static final Block NEVER_TINTED = new ParticleTintTestBlock(AbstractBlock.Settings.of(Material.STONE).breakInstantly(), 0x00FFFF);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
registerBlock("always_tinted", ALWAYS_TINTED);
|
||||
registerBlock("tinted_over_water", TINTED_OVER_WATER);
|
||||
registerBlock("never_tinted", NEVER_TINTED);
|
||||
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
dispatcher.register(CommandManager.literal("addparticletestblocks").executes(context -> {
|
||||
PlayerInventory inventory = context.getSource().getPlayer().getInventory();
|
||||
inventory.offerOrDrop(new ItemStack(ALWAYS_TINTED));
|
||||
inventory.offerOrDrop(new ItemStack(TINTED_OVER_WATER));
|
||||
inventory.offerOrDrop(new ItemStack(NEVER_TINTED));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerBlock(String path, Block block) {
|
||||
Identifier id = new Identifier("fabric-particles-v1-testmod", path);
|
||||
Registry.register(Registries.BLOCK, id, block);
|
||||
Registry.register(Registries.ITEM, id, new BlockItem(block, new Item.Settings()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.test.particle;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
public class ParticleTintTestBlock extends Block {
|
||||
public final int color;
|
||||
|
||||
public ParticleTintTestBlock(Settings settings, int color) {
|
||||
super(settings);
|
||||
this.color = color;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-particles-v1-testmod:block/tint_test" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-particles-v1-testmod:block/tint_test" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "fabric-particles-v1-testmod:block/tint_test" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"block.fabric-particles-v1-testmod.always_tinted": "Dust Particles Always Tinted",
|
||||
"block.fabric-particles-v1-testmod.never_tinted": "Dust Particles Never Tinted",
|
||||
"block.fabric-particles-v1-testmod.tinted_over_water": "Dust Particles Only Tinted Over Water"
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"all": "fabric-particles-v1-testmod:block/tint_test",
|
||||
"particle": "fabric-particles-v1-testmod:block/tint_test"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": { "texture": "#all", "cullface": "north", "tintindex": 0 },
|
||||
"east": { "texture": "#all", "cullface": "east", "tintindex": 0 },
|
||||
"south": { "texture": "#all", "cullface": "south", "tintindex": 0 },
|
||||
"west": { "texture": "#all", "cullface": "west", "tintindex": 0 },
|
||||
"up": { "texture": "#all", "cullface": "up", "tintindex": 0 },
|
||||
"down": { "texture": "#all", "cullface": "down", "tintindex": 0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "fabric-particles-v1-testmod:block/tint_test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "fabric-particles-v1-testmod:block/tint_test"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "fabric-particles-v1-testmod:block/tint_test"
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 645 B |
19
fabric-particles-v1/src/testmod/resources/fabric.mod.json
Normal file
19
fabric-particles-v1/src/testmod/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-particles-v1-testmod",
|
||||
"name": "Fabric Particles (v1) Test Mod",
|
||||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-particles-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.particle.ParticleTestSetup"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.particle.client.ParticleRenderEventTests"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.test.particle.client;
|
||||
|
||||
import net.minecraft.registry.tag.FluidTags;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.particle.v1.ParticleRenderEvents;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
||||
import net.fabricmc.fabric.test.particle.ParticleTestSetup;
|
||||
import net.fabricmc.fabric.test.particle.ParticleTintTestBlock;
|
||||
|
||||
public final class ParticleRenderEventTests implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ColorProviderRegistry.BLOCK.register((state, world, pos, tintIndex) -> {
|
||||
if (tintIndex == 0) {
|
||||
return ((ParticleTintTestBlock) state.getBlock()).color;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}, ParticleTestSetup.ALWAYS_TINTED, ParticleTestSetup.TINTED_OVER_WATER, ParticleTestSetup.NEVER_TINTED);
|
||||
|
||||
ParticleRenderEvents.ALLOW_BLOCK_DUST_TINT.register((state, world, pos) -> {
|
||||
if (state.isOf(ParticleTestSetup.NEVER_TINTED)) {
|
||||
return false;
|
||||
} else if (state.isOf(ParticleTestSetup.TINTED_OVER_WATER)) {
|
||||
return world.getFluidState(pos.down()).isIn(FluidTags.WATER);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue