mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-15 00:14:28 -04:00
Add AllowElytraFlight event (#1815)
Use explicit casts instead of .class.cast in mixins Reorganize API class, and make it work for any living entity add LivingEntityFeatureRenderEvents to disable cape rendering Reorganize/rename hook, and add ALLOW event Fix missing mixin return & cosmetic adjustements
This commit is contained in:
parent
f7c1d59979
commit
6b21378a26
14 changed files with 527 additions and 0 deletions
fabric-entity-events-v1
build.gradle
src
main
java/net/fabricmc/fabric
api/entity/event/v1
mixin/entity/event/elytra
resources
testmod
java/net/fabricmc/fabric/test/entity/event
resources
fabric-rendering-v1/src/main
java/net/fabricmc/fabric
api/client/rendering/v1
mixin/client/rendering
resources
|
@ -9,4 +9,5 @@ dependencies {
|
|||
testmodImplementation project(path: ':fabric-command-api-v1', configuration: 'namedElements')
|
||||
testmodImplementation project(path: ':fabric-networking-api-v1', configuration: 'namedElements')
|
||||
testmodImplementation project(path: ':fabric-registry-sync-v0', configuration: 'namedElements')
|
||||
testmodImplementation project(path: ':fabric-rendering-v1', configuration: 'namedElements')
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.entity.event.v1;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Events related to elytra flight for living entities. Elytra flight is also known as "fall flying".
|
||||
*/
|
||||
public final class EntityElytraEvents {
|
||||
/**
|
||||
* An event to check if elytra flight (both through normal and custom elytras) is allowed.
|
||||
* All listeners need to return true to allow the entity to fly, otherwise elytra flight will be blocked/stopped.
|
||||
*/
|
||||
public static final Event<Allow> ALLOW = EventFactory.createArrayBacked(Allow.class, listeners -> entity -> {
|
||||
for (Allow listener : listeners) {
|
||||
if (!listener.allowElytraFlight(entity)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* An event to grant elytra flight to living entities when some condition is met.
|
||||
* Will be called when players try to start elytra flight by pressing space in mid-air, and every tick for all flying living entities to check if elytra flight is still allowed.
|
||||
*
|
||||
* <p>Items that wish to enable custom elytra flight when worn in the chest equipment slot can simply implement {@link FabricElytraItem} instead of registering a listener.
|
||||
*/
|
||||
public static final Event<Custom> CUSTOM = EventFactory.createArrayBacked(Custom.class, listeners -> (entity, tickElytra) -> {
|
||||
for (Custom listener : listeners) {
|
||||
if (listener.useCustomElytra(entity, tickElytra)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
static {
|
||||
CUSTOM.register((entity, tickElytra) -> {
|
||||
ItemStack chestStack = entity.getEquippedStack(EquipmentSlot.CHEST);
|
||||
|
||||
if (chestStack.getItem() instanceof FabricElytraItem fabricElytraItem) {
|
||||
return fabricElytraItem.useCustomElytra(entity, chestStack, tickElytra);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Allow {
|
||||
/**
|
||||
* @return false to block elytra flight, true to allow it (unless another listener returns false)
|
||||
*/
|
||||
boolean allowElytraFlight(LivingEntity entity);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Custom {
|
||||
/**
|
||||
* Try to use a custom elytra for an entity.
|
||||
* A custom elytra is anything that allows an entity to enter and continue elytra flight when some condition is met.
|
||||
* Listeners should follow the following pattern:
|
||||
* <pre>{@code
|
||||
* EntityElytraEvents.CUSTOM.register((entity, tickElytra) -> {
|
||||
* if (check if condition for custom elytra is met) {
|
||||
* if (tickElytra) {
|
||||
* // Optionally consume some resources that are being used up in order to fly, for example damaging an item.
|
||||
* // Optionally perform other side effects of elytra flight, for example playing a sound.
|
||||
* }
|
||||
* // Allow entering/continuing elytra flight with this custom elytra
|
||||
* return true;
|
||||
* }
|
||||
* // Condition for the custom elytra is not met: don't let players enter or continue elytra flight (unless another elytra is available).
|
||||
* return false;
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param tickElytra false if this is just to check if the custom elytra can be used, true if the custom elytra should also be ticked, i.e. perform side-effects of flying such as using resources.
|
||||
* @return true to use a custom elytra, enabling elytra flight for the entity and cancelling subsequent handlers
|
||||
*/
|
||||
boolean useCustomElytra(LivingEntity entity, boolean tickElytra);
|
||||
}
|
||||
|
||||
private EntityElytraEvents() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.entity.event.v1;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.item.ElytraItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.event.GameEvent;
|
||||
|
||||
/**
|
||||
* An interface that can be implemented on an item to provide custom elytra flight when it is worn in the {@link EquipmentSlot#CHEST} slot.
|
||||
*
|
||||
* <p>To disable cape rendering when this item is worn (like the vanilla elytra item), have a look at {@code LivingEntityFeatureRenderEvents}.
|
||||
*/
|
||||
public interface FabricElytraItem {
|
||||
/**
|
||||
* Try to use this custom elytra.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param chestStack the stack currently worn in the chest slot, will always be of this item
|
||||
* @param tickElytra true to tick the elytra, false to only perform the check; vanilla-like elytras can use {@link #doVanillaElytraTick} to handle ticking
|
||||
* @return true to enable elytra flight for the entity
|
||||
*/
|
||||
default boolean useCustomElytra(LivingEntity entity, ItemStack chestStack, boolean tickElytra) {
|
||||
if (ElytraItem.isUsable(chestStack)) {
|
||||
if (tickElytra) {
|
||||
doVanillaElytraTick(entity, chestStack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to perform the default vanilla elytra tick logic: damage the elytra every 20 ticks, and send a game event every 10 ticks.
|
||||
*/
|
||||
default void doVanillaElytraTick(LivingEntity entity, ItemStack chestStack) {
|
||||
int nextRoll = entity.getRoll() + 1;
|
||||
|
||||
if (!entity.world.isClient && nextRoll % 10 == 0) {
|
||||
if ((nextRoll / 10) % 2 == 0) {
|
||||
chestStack.damage(1, entity, p -> p.sendEquipmentBreakStatus(EquipmentSlot.CHEST));
|
||||
}
|
||||
|
||||
entity.emitGameEvent(GameEvent.ELYTRA_FREE_FALL);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.entity.event.elytra;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
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.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity {
|
||||
ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) {
|
||||
super(world, profile);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ClientPlayNetworkHandler networkHandler;
|
||||
|
||||
/**
|
||||
* Call {@link #checkFallFlying()} even if the player is not wearing {@link Items#ELYTRA} to allow custom elytra flight.
|
||||
*/
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/EquipmentSlot;CHEST:Lnet/minecraft/entity/EquipmentSlot;"), method = "tickMovement", slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isClimbing()Z"), to = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;checkFallFlying()Z")), allow = 1)
|
||||
void injectElytraStart(CallbackInfo info) {
|
||||
// Note that if fall flying is not ALLOWed, checkFallFlying will return false and nothing will happen.
|
||||
if (this.checkFallFlying()) {
|
||||
networkHandler.sendPacket(new ClientCommandC2SPacket(this, ClientCommandC2SPacket.Mode.START_FALL_FLYING));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.entity.event.elytra;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.entity.event.v1.EntityElytraEvents;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Mixin(LivingEntity.class)
|
||||
abstract class LivingEntityMixin extends Entity {
|
||||
LivingEntityMixin(EntityType<?> type, World world) {
|
||||
super(type, world);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ALLOW and CUSTOM {@link EntityElytraEvents} when an entity is fall flying.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/EquipmentSlot;CHEST:Lnet/minecraft/entity/EquipmentSlot;"), method = "tickFallFlying()V", allow = 1, cancellable = true)
|
||||
void injectElytraTick(CallbackInfo info) {
|
||||
LivingEntity self = (LivingEntity) (Object) this;
|
||||
|
||||
if (!EntityElytraEvents.ALLOW.invoker().allowElytraFlight(self)) {
|
||||
// The entity is already fall flying by now, we just need to stop it.
|
||||
if (!world.isClient) {
|
||||
setFlag(Entity.FALL_FLYING_FLAG_INDEX, false);
|
||||
}
|
||||
|
||||
info.cancel();
|
||||
}
|
||||
|
||||
if (EntityElytraEvents.CUSTOM.invoker().useCustomElytra(self, true)) {
|
||||
// The entity is already fall flying by now, so all we need to do is an early return to bypass vanilla's own elytra check.
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.entity.event.elytra;
|
||||
|
||||
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.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.entity.event.v1.EntityElytraEvents;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Mixin(PlayerEntity.class)
|
||||
abstract class PlayerEntityMixin extends LivingEntity {
|
||||
PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
|
||||
super(entityType, world);
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract void startFallFlying();
|
||||
|
||||
/**
|
||||
* Allow the server-side and client-side elytra checks to fail when {@link EntityElytraEvents#ALLOW} blocks flight,
|
||||
* and otherwise to succeed for elytra flight through {@link EntityElytraEvents#CUSTOM}.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/EquipmentSlot;CHEST:Lnet/minecraft/entity/EquipmentSlot;"), method = "checkFallFlying()Z", allow = 1, cancellable = true)
|
||||
void injectElytraCheck(CallbackInfoReturnable<Boolean> cir) {
|
||||
PlayerEntity self = (PlayerEntity) (Object) this;
|
||||
|
||||
if (!EntityElytraEvents.ALLOW.invoker().allowElytraFlight(self)) {
|
||||
cir.setReturnValue(false);
|
||||
return; // Return to prevent the rest of this injector from running.
|
||||
}
|
||||
|
||||
if (EntityElytraEvents.CUSTOM.invoker().useCustomElytra(self, false)) {
|
||||
startFallFlying();
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
"package": "net.fabricmc.fabric.mixin.entity.event",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"mixins": [
|
||||
"elytra/LivingEntityMixin",
|
||||
"elytra/PlayerEntityMixin",
|
||||
"BedBlockMixin",
|
||||
"EntityMixin",
|
||||
"LivingEntityMixin",
|
||||
|
@ -11,6 +13,9 @@
|
|||
"ServerPlayerEntityMixin",
|
||||
"TeleportCommandMixin"
|
||||
],
|
||||
"client": [
|
||||
"elytra/ClientPlayerEntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1,
|
||||
"maxShiftBy": 3
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.entity.event;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.item.ArmorItem;
|
||||
import net.minecraft.item.ArmorMaterials;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
|
||||
import net.fabricmc.fabric.api.entity.event.v1.FabricElytraItem;
|
||||
|
||||
public class DiamondElytraItem extends ArmorItem implements FabricElytraItem {
|
||||
public DiamondElytraItem() {
|
||||
super(ArmorMaterials.DIAMOND, EquipmentSlot.CHEST, new Settings().maxCount(1).group(ItemGroup.COMBAT));
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@ import net.minecraft.util.registry.Registry;
|
|||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.EntityElytraEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityCombatEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
|
||||
|
@ -49,11 +50,13 @@ import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
|||
public final class EntityEventTests implements ModInitializer {
|
||||
private static final Logger LOGGER = LogManager.getLogger(EntityEventTests.class);
|
||||
public static final Block TEST_BED = new TestBedBlock(AbstractBlock.Settings.of(Material.WOOL).strength(1, 1));
|
||||
public static final Item DIAMOND_ELYTRA = new DiamondElytraItem();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Registry.register(Registry.BLOCK, new Identifier("fabric-entity-events-v1-testmod", "test_bed"), TEST_BED);
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-entity-events-v1-testmod", "test_bed"), new BlockItem(TEST_BED, new Item.Settings().group(ItemGroup.DECORATIONS)));
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-entity-events-v1-testmod", "diamond_elytra"), DIAMOND_ELYTRA);
|
||||
|
||||
ServerEntityCombatEvents.AFTER_KILLED_OTHER_ENTITY.register((world, entity, killed) -> {
|
||||
LOGGER.info("Entity Killed: {}", killed);
|
||||
|
@ -172,6 +175,11 @@ public final class EntityEventTests implements ModInitializer {
|
|||
return 0;
|
||||
}));
|
||||
});
|
||||
|
||||
// Block elytra flight when holding a torch in the off-hand.
|
||||
EntityElytraEvents.ALLOW.register(entity -> {
|
||||
return !entity.getOffHandStack().isOf(Items.TORCH);
|
||||
});
|
||||
}
|
||||
|
||||
private static void addSleepWools(PlayerEntity player) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.entity.event.client;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRenderEvents;
|
||||
import net.fabricmc.fabric.test.entity.event.EntityEventTests;
|
||||
|
||||
public class EntityEventTestsClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
LivingEntityFeatureRenderEvents.ALLOW_CAPE_RENDER.register(player -> {
|
||||
return !player.getEquippedStack(EquipmentSlot.CHEST).isOf(EntityEventTests.DIAMOND_ELYTRA);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -13,6 +13,9 @@
|
|||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.entity.event.EntityEventTests"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.test.entity.event.client.EntityEventTestsClient"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.rendering.v1;
|
||||
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Events related to living entity {@link FeatureRenderer}s.
|
||||
* To register a renderer, see {@link LivingEntityFeatureRendererRegistrationCallback} instead.
|
||||
*/
|
||||
public final class LivingEntityFeatureRenderEvents {
|
||||
/**
|
||||
* An event that can prevent capes from rendering.
|
||||
*/
|
||||
public static final Event<AllowCapeRender> ALLOW_CAPE_RENDER = EventFactory.createArrayBacked(AllowCapeRender.class, listeners -> player -> {
|
||||
for (AllowCapeRender listener : listeners) {
|
||||
if (!listener.allowCapeRender(player)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AllowCapeRender {
|
||||
/**
|
||||
* @return false to prevent rendering the cape
|
||||
*/
|
||||
boolean allowCapeRender(AbstractClientPlayerEntity player);
|
||||
}
|
||||
|
||||
private LivingEntityFeatureRenderEvents() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.rendering;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.CapeFeatureRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRenderEvents;
|
||||
|
||||
@Mixin(CapeFeatureRenderer.class)
|
||||
public class CapeFeatureRendererMixin {
|
||||
@Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/entity/EquipmentSlot;CHEST:Lnet/minecraft/entity/EquipmentSlot;"), method = "render", require = 1, allow = 1, cancellable = true)
|
||||
public void injectCapeRenderCheck(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, AbstractClientPlayerEntity abstractClientPlayerEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
|
||||
if (!LivingEntityFeatureRenderEvents.ALLOW_CAPE_RENDER.invoker().allowCapeRender(abstractClientPlayerEntity)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"package": "net.fabricmc.fabric.mixin.client.rendering",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"client": [
|
||||
"CapeFeatureRendererMixin",
|
||||
"MixinArmorFeatureRenderer",
|
||||
"MixinBlockColorMap",
|
||||
"MixinBuiltinModelItemRenderer",
|
||||
|
|
Loading…
Add table
Reference in a new issue