mirror of
https://github.com/FabricMC/fabric.git
synced 2025-04-21 03:10:54 -04:00
Merge remote-tracking branch 'origin/1.19.2' into 1.19.3
# Conflicts: # gradle.properties
This commit is contained in:
commit
28cc6cc789
29 changed files with 727 additions and 29 deletions
fabric-block-api-v1
fabric-entity-events-v1/src
main/java/net/fabricmc/fabric
api/entity/event/v1
mixin/entity/event
testmod/java/net/fabricmc/fabric/test/entity/event
fabric-object-builder-api-v1/src/main/java/net/fabricmc/fabric/api/object/builder/v1/entity
fabric-renderer-api-v1
build.gradle
src/testmod
java/net/fabricmc/fabric/test/renderer/simple
resources/assets/fabric-renderer-api-v1-testmod/textures/block
fabric-rendering-data-attachment-v1/src/main/java/net/fabricmc/fabric/api/rendering/data/v1
fabric-resource-loader-v0/src/main/resources/assets/fabric-resource-loader-v0/lang
gradle.propertiessettings.gradle
2
fabric-block-api-v1/build.gradle
Normal file
2
fabric-block-api-v1/build.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
archivesBaseName = "fabric-block-api-v1"
|
||||
version = getSubprojectVersion(project)
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.block.v1;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* General-purpose Fabric-provided extensions for {@link Block} subclasses.
|
||||
*
|
||||
* <p>Note: This interface is automatically implemented on all blocks via Mixin and interface injection.
|
||||
*/
|
||||
// Note to maintainers: Functions should only be added to this interface if they are general-purpose enough,
|
||||
// to be evaluated on a case-by-case basis. Otherwise, they are better suited for more specialized APIs.
|
||||
public interface FabricBlock {
|
||||
/**
|
||||
* Return the current appearance of the block, i.e. which block state this block reports to look like on a given side.
|
||||
*
|
||||
* <p>Common implementors are covers and facades, or any other mimic blocks that proxy another block's model.
|
||||
* These will want to override this method. In that case, make sure to carefully read the implementation guidelines below.
|
||||
*
|
||||
* <p>Common consumers are models with connected textures that wish to seamlessly connect to mimic blocks.
|
||||
* These will want to check the apparent block state using {@link FabricBlockState#getAppearance}.
|
||||
*
|
||||
* <p>Generally, the appearance will be queried from a nearby block,
|
||||
* identified by the optional {@code sourcePos} and {@code sourceState} parameters.
|
||||
*
|
||||
* <p>When a block changes appearance, it should trigger a chunk remesh for itself and the adjacent blocks,
|
||||
* for example by calling {@link World#updateListeners}.
|
||||
*
|
||||
* <p>Note: Overriding this method for a block does <strong>not</strong> change how it renders.
|
||||
* It's up to modded models to check for the appearance of nearby blocks and adjust accordingly.
|
||||
*
|
||||
* <h3>Implementation guidelines</h3>
|
||||
*
|
||||
* <p>This can be called on the server, where block entity data can be safely accessed,
|
||||
* and on the client, possibly in a meshing thread, where block entity data is not safe to access!
|
||||
* Here is an example of how data from a block entity can be handled safely.
|
||||
* The block entity needs to implement {@code RenderAttachmentBlockEntity} for this to work.
|
||||
* <pre>{@code @Override
|
||||
* public BlockState getAppearance(BlockState state, BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
|
||||
* if (renderView instanceof ServerWorld serverWorld) {
|
||||
* // Server side, ok to use block entity directly!
|
||||
* BlockEntity blockEntity = serverWorld.getBlockEntity(pos);
|
||||
*
|
||||
* if (blockEntity instanceof ...) {
|
||||
* // Get data from block entity
|
||||
* return ...;
|
||||
* }
|
||||
* } else {
|
||||
* // Client side, need to use the render attachment!
|
||||
* RenderAttachedBlockView attachmentView = (RenderAttachedBlockView) renderView;
|
||||
* Object data = attachmentView.getBlockEntityRenderAttachment(pos);
|
||||
*
|
||||
* // Check if data is not null and of the correct type, and use that to determine the appearance
|
||||
* if (data instanceof ...) {
|
||||
* // get appearance for side ...
|
||||
* return ...;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Example of varying the appearance based on the source pos
|
||||
* if (sourcePos != null) {
|
||||
* // get appearance for side ...
|
||||
* return ...;
|
||||
* }
|
||||
*
|
||||
* // If there is no other appearance, just return the original block state
|
||||
* return state;
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param state state of this block, whose appearance is being queried
|
||||
* @param renderView the world this block is in
|
||||
* @param pos position of this block, whose appearance is being queried
|
||||
* @param side the side for which the appearance is being queried
|
||||
* @param sourceState (optional) state of the block that is querying the appearance, or null if unknown
|
||||
* @param sourcePos (optional) position of the block that is querying the appearance, or null if unknown
|
||||
* @return the appearance of the block on the given side; the original {@code state} can be returned if there is no better option
|
||||
*/
|
||||
default BlockState getAppearance(BlockState state, BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.block.v1;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
/**
|
||||
* General-purpose Fabric-provided extensions for {@link BlockState}, matching the functionality provided in {@link FabricBlock}.
|
||||
*
|
||||
* <p>Note: This interface is automatically implemented on all block states via Mixin and interface injection.
|
||||
*/
|
||||
public interface FabricBlockState {
|
||||
/**
|
||||
* Return the current appearance of the block, i.e. which block state this block reports to look like on a given side.
|
||||
*
|
||||
* @param renderView the world this block is in
|
||||
* @param pos position of this block, whose appearance is being queried
|
||||
* @param side the side for which the appearance is being queried
|
||||
* @param sourceState (optional) state of the block that is querying the appearance, or null if unknown
|
||||
* @param sourcePos (optional) position of the block that is querying the appearance, or null if unknown
|
||||
* @return the appearance of the block on the given side; the original {@code state} can be returned if there is no better option
|
||||
* @see FabricBlock#getAppearance
|
||||
*/
|
||||
default BlockState getAppearance(BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
|
||||
BlockState self = (BlockState) this;
|
||||
return self.getBlock().getAppearance(self, renderView, pos, side, sourceState, sourcePos);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.block;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
|
||||
import net.fabricmc.fabric.api.block.v1.FabricBlock;
|
||||
|
||||
@Mixin(Block.class)
|
||||
public class BlockMixin implements FabricBlock { }
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.block;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
|
||||
import net.fabricmc.fabric.api.block.v1.FabricBlockState;
|
||||
|
||||
@Mixin(BlockState.class)
|
||||
public class BlockStateMixin implements FabricBlockState { }
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"required": true,
|
||||
"package": "net.fabricmc.fabric.mixin.block",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"BlockMixin",
|
||||
"BlockStateMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Binary file not shown.
After ![]() (image error) Size: 1.5 KiB |
34
fabric-block-api-v1/src/main/resources/fabric.mod.json
Normal file
34
fabric-block-api-v1/src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-block-api-v1",
|
||||
"name": "Fabric Block API (v1)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-block-api-v1/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.9"
|
||||
},
|
||||
"entrypoints": {
|
||||
},
|
||||
"description": "Hooks for blocks",
|
||||
"mixins": [
|
||||
"fabric-block-api-v1.mixins.json"
|
||||
],
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "stable",
|
||||
"loom:injected_interfaces": {
|
||||
"net/minecraft/class_2248": ["net/fabricmc/fabric/api/block/v1/FabricBlock"],
|
||||
"net/minecraft/class_2680": ["net/fabricmc/fabric/api/block/v1/FabricBlockState"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Various server-side only events related to living entities.
|
||||
*/
|
||||
public final class ServerLivingEntityEvents {
|
||||
/**
|
||||
* An event that is called when a living entity is going to take damage.
|
||||
* This is fired from {@link LivingEntity#damage}, before armor or any other mitigation are applied.
|
||||
* Mods can cancel this to prevent the damage entirely.
|
||||
*/
|
||||
public static final Event<AllowDamage> ALLOW_DAMAGE = EventFactory.createArrayBacked(AllowDamage.class, callbacks -> (entity, source, amount) -> {
|
||||
for (AllowDamage callback : callbacks) {
|
||||
if (!callback.allowDamage(entity, source, amount)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* An event that is called when an entity takes fatal damage.
|
||||
*
|
||||
* <p>Mods can cancel this to keep the entity alive.
|
||||
*
|
||||
* <p>Vanilla checks for entity health {@code <= 0} each tick (with {@link LivingEntity#isDead()}), and kills if true -
|
||||
* so the entity will still die next tick if this event is cancelled.
|
||||
* It's assumed that the listener will do something to prevent this, for example, if the entity is a player:
|
||||
* <ul>
|
||||
* <li>a minigame mod teleporting the player into a 'respawn room' and setting their health to 20.0</li>
|
||||
* <li>a mod that changes death mechanics switching the player over to the mod's play-mode, where death doesn't apply</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final Event<AllowDeath> ALLOW_DEATH = EventFactory.createArrayBacked(AllowDeath.class, callbacks -> (entity, damageSource, damageAmount) -> {
|
||||
for (AllowDeath callback : callbacks) {
|
||||
if (!callback.allowDeath(entity, damageSource, damageAmount)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
/**
|
||||
* An event that is called when a living entity dies.
|
||||
*/
|
||||
public static final Event<AfterDeath> AFTER_DEATH = EventFactory.createArrayBacked(AfterDeath.class, callbacks -> (entity, damageSource) -> {
|
||||
for (AfterDeath callback : callbacks) {
|
||||
callback.afterDeath(entity, damageSource);
|
||||
}
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AllowDamage {
|
||||
/**
|
||||
* Called when a living entity is going to take damage. Can be used to cancel the damage entirely.
|
||||
*
|
||||
* <p>The amount corresponds to the "incoming" damage amount, before armor and other mitigations have been applied.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param source the source of the damage
|
||||
* @param amount the amount of damage that the entity will take (before mitigations)
|
||||
* @return true if the damage should go ahead, false to cancel the damage.
|
||||
*/
|
||||
boolean allowDamage(LivingEntity entity, DamageSource source, float amount);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AllowDeath {
|
||||
/**
|
||||
* Called when a living entity takes fatal damage (before totems of undying can take effect).
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param damageSource the source of the fatal damage
|
||||
* @param damageAmount the amount of damage that has killed the entity
|
||||
* @return true if the death should go ahead, false to cancel the death.
|
||||
*/
|
||||
boolean allowDeath(LivingEntity entity, DamageSource damageSource, float damageAmount);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AfterDeath {
|
||||
/**
|
||||
* Called when a living entity dies. The death cannot be canceled at this point.
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param damageSource the source of the fatal damage
|
||||
*/
|
||||
void afterDeath(LivingEntity entity, DamageSource damageSource);
|
||||
}
|
||||
|
||||
private ServerLivingEntityEvents() {
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package net.fabricmc.fabric.api.entity.event.v1;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
|
@ -50,18 +49,9 @@ public final class ServerPlayerEvents {
|
|||
/**
|
||||
* An event that is called when a player takes fatal damage.
|
||||
*
|
||||
* <p>Mods can cancel this to keep the player alive.
|
||||
*
|
||||
* <p>Vanilla checks for player health {@code <= 0} each tick (with {@link LivingEntity#isDead()}), and kills if true -
|
||||
* so the player will still die next tick if this event is cancelled. It's assumed that the listener will do
|
||||
* something to prevent this, for example:
|
||||
*
|
||||
* <ul>
|
||||
* <li>a minigame mod teleporting the player into a 'respawn room' and setting their health to 20.0</li>
|
||||
* <li>a mod that changes death mechanics switching the player over to the mod's play-mode, where death doesn't
|
||||
* apply</li>
|
||||
* </ul>
|
||||
* @deprecated Use the more general {@link ServerLivingEntityEvents#ALLOW_DEATH} event instead and check for {@code instanceof ServerPlayerEntity}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Event<AllowDeath> ALLOW_DEATH = EventFactory.createArrayBacked(AllowDeath.class, callbacks -> (player, damageSource, damageAmount) -> {
|
||||
for (AllowDeath callback : callbacks) {
|
||||
if (!callback.allowDeath(player, damageSource, damageAmount)) {
|
||||
|
@ -96,6 +86,10 @@ public final class ServerPlayerEvents {
|
|||
void afterRespawn(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer, boolean alive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the more general {@link ServerLivingEntityEvents#ALLOW_DEATH} event instead and check for {@code instanceof ServerPlayerEntity}.
|
||||
*/
|
||||
@Deprecated
|
||||
@FunctionalInterface
|
||||
public interface AllowDeath {
|
||||
/**
|
||||
|
@ -111,4 +105,15 @@ public final class ServerPlayerEvents {
|
|||
|
||||
private ServerPlayerEvents() {
|
||||
}
|
||||
|
||||
static {
|
||||
// Forward general living entity event to (older) player-specific event.
|
||||
ServerLivingEntityEvents.ALLOW_DEATH.register((entity, damageSource, damageAmount) -> {
|
||||
if (entity instanceof ServerPlayerEntity player) {
|
||||
return ServerPlayerEvents.ALLOW_DEATH.invoker().allowDeath(player, damageSource, damageAmount);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import net.minecraft.entity.Entity;
|
|||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -48,7 +47,7 @@ import net.minecraft.world.World;
|
|||
|
||||
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.ServerPlayerEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
abstract class LivingEntityMixin {
|
||||
|
@ -65,13 +64,21 @@ abstract class LivingEntityMixin {
|
|||
ServerEntityCombatEvents.AFTER_KILLED_OTHER_ENTITY.invoker().afterKilledOtherEntity((ServerWorld) ((LivingEntity) (Object) this).world, attacker, (LivingEntity) (Object) this);
|
||||
}
|
||||
|
||||
@Redirect(method = "damage", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;isDead()Z", ordinal = 1))
|
||||
boolean beforePlayerKilled(LivingEntity livingEntity, DamageSource source, float amount) {
|
||||
if (livingEntity instanceof ServerPlayerEntity) {
|
||||
return isDead() && ServerPlayerEvents.ALLOW_DEATH.invoker().allowDeath((ServerPlayerEntity) livingEntity, source, amount);
|
||||
}
|
||||
@Inject(method = "onDeath", at = @At(value = "INVOKE", target = "net/minecraft/world/World.sendEntityStatus(Lnet/minecraft/entity/Entity;B)V"))
|
||||
private void notifyDeath(DamageSource source, CallbackInfo ci) {
|
||||
ServerLivingEntityEvents.AFTER_DEATH.invoker().afterDeath((LivingEntity) (Object) this, source);
|
||||
}
|
||||
|
||||
return isDead();
|
||||
@Redirect(method = "damage", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;isDead()Z", ordinal = 1))
|
||||
boolean beforeEntityKilled(LivingEntity livingEntity, DamageSource source, float amount) {
|
||||
return isDead() && ServerLivingEntityEvents.ALLOW_DEATH.invoker().allowDeath(livingEntity, source, amount);
|
||||
}
|
||||
|
||||
@Inject(method = "damage", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.isSleeping()Z"), cancellable = true)
|
||||
private void beforeDamage(DamageSource source, float amount, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!ServerLivingEntityEvents.ALLOW_DAMAGE.invoker().allowDamage((LivingEntity) (Object) this, source, amount)) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "sleep", at = @At("RETURN"))
|
||||
|
|
|
@ -48,6 +48,7 @@ import net.minecraft.world.World;
|
|||
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;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
|
@ -71,6 +72,11 @@ abstract class ServerPlayerEntityMixin extends LivingEntityMixin {
|
|||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onDeath", at = @At("TAIL"))
|
||||
private void notifyDeath(DamageSource source, CallbackInfo ci) {
|
||||
ServerLivingEntityEvents.AFTER_DEATH.invoker().afterDeath((ServerPlayerEntity) (Object) this, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by both "moveToWorld" and "teleport".
|
||||
* So this is suitable to handle the after event from both call sites.
|
||||
|
|
|
@ -23,6 +23,7 @@ import net.minecraft.block.AbstractBlock;
|
|||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.BlockItem;
|
||||
|
@ -44,6 +45,7 @@ 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;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
|
||||
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
|
||||
|
||||
public final class EntityEventTests implements ModInitializer {
|
||||
|
@ -77,9 +79,29 @@ public final class EntityEventTests implements ModInitializer {
|
|||
LOGGER.info("Respawned {}, [{}, {}]", oldPlayer.getGameProfile().getName(), oldPlayer.getWorld().getRegistryKey().getValue(), newPlayer.getWorld().getRegistryKey().getValue());
|
||||
});
|
||||
|
||||
ServerPlayerEvents.ALLOW_DEATH.register((player, source, amount) -> {
|
||||
LOGGER.info("{} is going to die to {} damage from {} damage source", player.getGameProfile().getName(), amount, source.getName());
|
||||
// No fall damage if holding a feather in the main hand
|
||||
ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> {
|
||||
if (source == DamageSource.FALL && entity.getStackInHand(Hand.MAIN_HAND).isOf(Items.FEATHER)) {
|
||||
LOGGER.info("Avoided {} of fall damage by holding a feather", amount);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
ServerLivingEntityEvents.ALLOW_DEATH.register((entity, source, amount) -> {
|
||||
LOGGER.info("{} is going to die to {} damage from {} damage source", entity.getName().getString(), amount, source.getName());
|
||||
|
||||
if (entity.getStackInHand(Hand.MAIN_HAND).getItem() == Items.CARROT) {
|
||||
entity.setHealth(3.0f);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Test that the legacy event still works
|
||||
ServerPlayerEvents.ALLOW_DEATH.register((player, source, amount) -> {
|
||||
if (player.getStackInHand(Hand.MAIN_HAND).getItem() == Items.APPLE) {
|
||||
player.setHealth(3.0f);
|
||||
return false;
|
||||
|
@ -88,6 +110,10 @@ public final class EntityEventTests implements ModInitializer {
|
|||
return true;
|
||||
});
|
||||
|
||||
ServerLivingEntityEvents.AFTER_DEATH.register((entity, source) -> {
|
||||
LOGGER.info("{} died due to {} damage source", entity.getName().getString(), source.getName());
|
||||
});
|
||||
|
||||
EntitySleepEvents.ALLOW_SLEEPING.register((player, sleepingPos) -> {
|
||||
// Can't sleep if holds blue wool
|
||||
if (player.getStackInHand(Hand.MAIN_HAND).isOf(Items.BLUE_WOOL)) {
|
||||
|
|
|
@ -48,6 +48,17 @@ public final class FabricDefaultAttributeRegistry {
|
|||
private FabricDefaultAttributeRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a default attribute for a type of living entity.
|
||||
*
|
||||
* @param type the entity type
|
||||
* @param builder the builder that creates the default attribute
|
||||
* @see FabricDefaultAttributeRegistry#register(EntityType, DefaultAttributeContainer)
|
||||
*/
|
||||
public static void register(EntityType<? extends LivingEntity> type, DefaultAttributeContainer.Builder builder) {
|
||||
register(type, builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a default attribute for a type of living entity.
|
||||
*
|
||||
|
@ -62,12 +73,12 @@ public final class FabricDefaultAttributeRegistry {
|
|||
*
|
||||
* <p>For convenience, this can also be done on the {@link FabricEntityTypeBuilder} to simplify the building process.
|
||||
*
|
||||
* @param type the entity type
|
||||
* @param builder the builder that creates the default attribute
|
||||
* @param type the entity type
|
||||
* @param container the container for the default attribute
|
||||
* @see FabricEntityTypeBuilder.Living#defaultAttributes(Supplier)
|
||||
*/
|
||||
public static void register(EntityType<? extends LivingEntity> type, DefaultAttributeContainer.Builder builder) {
|
||||
if (DefaultAttributeRegistryAccessor.getRegistry().put(type, builder.build()) != null) {
|
||||
public static void register(EntityType<? extends LivingEntity> type, DefaultAttributeContainer container) {
|
||||
if (DefaultAttributeRegistryAccessor.getRegistry().put(type, container) != null) {
|
||||
LOGGER.debug("Overriding existing registration for entity type {}", Registry.ENTITY_TYPE.getId(type));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ moduleDependencies(project, [
|
|||
])
|
||||
|
||||
testDependencies(project, [
|
||||
':fabric-block-api-v1',
|
||||
':fabric-blockrenderlayer-v1',
|
||||
':fabric-models-v0',
|
||||
':fabric-object-builder-api-v1',
|
||||
|
|
|
@ -30,11 +30,16 @@ import net.minecraft.util.Hand;
|
|||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.block.v1.FabricBlock;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
|
||||
|
||||
public final class FrameBlock extends Block implements BlockEntityProvider {
|
||||
// Need to implement FabricBlock manually because this is a testmod for another Fabric module, otherwise it would be injected.
|
||||
public final class FrameBlock extends Block implements BlockEntityProvider, FabricBlock {
|
||||
public final Identifier id;
|
||||
|
||||
public FrameBlock(Identifier id) {
|
||||
|
@ -94,4 +99,16 @@ public final class FrameBlock extends Block implements BlockEntityProvider {
|
|||
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new FrameBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
// The frames don't look exactly like the block they are mimicking,
|
||||
// but the goal here is just to test the behavior with the pillar's connected textures. ;-)
|
||||
@Override
|
||||
public BlockState getAppearance(BlockState state, BlockRenderView renderView, BlockPos pos, Direction side, @Nullable BlockState sourceState, @Nullable BlockPos sourcePos) {
|
||||
// For this specific block, the render attachment works on both the client and the server, so let's use that.
|
||||
if (((RenderAttachedBlockView) renderView).getBlockEntityRenderAttachment(pos) instanceof Block mimickedBlock) {
|
||||
return mimickedBlock.getDefaultState();
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package net.fabricmc.fabric.test.renderer.simple;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.Item;
|
||||
|
@ -23,6 +25,7 @@ import net.minecraft.util.Identifier;
|
|||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +43,9 @@ public final class RendererTest implements ModInitializer {
|
|||
};
|
||||
public static final BlockEntityType<FrameBlockEntity> FRAME_BLOCK_ENTITY = FabricBlockEntityTypeBuilder.create(FrameBlockEntity::new, FRAMES).build(null);
|
||||
|
||||
public static final Identifier PILLAR_ID = id("pillar");
|
||||
public static final Block PILLAR = new Block(FabricBlockSettings.of(Material.STONE));
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
for (FrameBlock frameBlock : FRAMES) {
|
||||
|
@ -47,6 +53,12 @@ public final class RendererTest implements ModInitializer {
|
|||
Registry.register(Registry.ITEM, frameBlock.id, new BlockItem(frameBlock, new Item.Settings()));
|
||||
}
|
||||
|
||||
// To anyone testing this: pillars are supposed to connect vertically with each other.
|
||||
// Additionally, they should also connect vertically to frame blocks containing a pillar.
|
||||
// (The frame block will not change, but adjacent pillars should adjust their textures).
|
||||
Registry.register(Registry.BLOCK, PILLAR_ID, PILLAR);
|
||||
Registry.register(Registry.ITEM, PILLAR_ID, new BlockItem(PILLAR, new Item.Settings()));
|
||||
|
||||
Registry.register(Registry.BLOCK_ENTITY_TYPE, id("frame"), FRAME_BLOCK_ENTITY);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.renderer.simple.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import net.fabricmc.fabric.api.block.v1.FabricBlockState;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
|
||||
|
||||
/**
|
||||
* Very crude implementation of a pillar block model that connects with pillars above and below.
|
||||
*/
|
||||
public class PillarBakedModel implements BakedModel, FabricBakedModel {
|
||||
private enum ConnectedTexture {
|
||||
ALONE, BOTTOM, MIDDLE, TOP
|
||||
}
|
||||
|
||||
// alone, bottom, middle, top
|
||||
private final Sprite[] sprites;
|
||||
|
||||
public PillarBakedModel(Sprite[] sprites) {
|
||||
this.sprites = sprites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
emitQuads(context.getEmitter(), blockView, state, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
emitQuads(context.getEmitter(), null, null, null);
|
||||
}
|
||||
|
||||
private void emitQuads(QuadEmitter emitter, @Nullable BlockRenderView blockView, @Nullable BlockState state, @Nullable BlockPos pos) {
|
||||
for (Direction side : Direction.values()) {
|
||||
ConnectedTexture texture = ConnectedTexture.ALONE;
|
||||
|
||||
if (side.getAxis().isHorizontal() && blockView != null && state != null && pos != null) {
|
||||
boolean connectAbove = canConnect(blockView, pos.offset(Direction.UP), side, state, pos);
|
||||
boolean connectBelow = canConnect(blockView, pos.offset(Direction.DOWN), side, state, pos);
|
||||
|
||||
if (connectAbove && connectBelow) {
|
||||
texture = ConnectedTexture.MIDDLE;
|
||||
} else if (connectAbove) {
|
||||
texture = ConnectedTexture.BOTTOM;
|
||||
} else if (connectBelow) {
|
||||
texture = ConnectedTexture.TOP;
|
||||
}
|
||||
}
|
||||
|
||||
emitter.square(side, 0, 0, 1, 1, 0);
|
||||
emitter.spriteBake(0, sprites[texture.ordinal()], MutableQuadView.BAKE_LOCK_UV);
|
||||
emitter.spriteColor(0, -1, -1, -1, -1);
|
||||
emitter.emit();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canConnect(BlockRenderView blockView, BlockPos pos, Direction side, BlockState sourceState, BlockPos sourcePos) {
|
||||
// In this testmod we can't rely on injected interfaces - in normal mods the (FabricBlockState) cast will be unnecessary
|
||||
return ((FabricBlockState) blockView.getBlockState(pos)).getAppearance(blockView, pos, side, sourceState, sourcePos).isOf(RendererTest.PILLAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return sprites[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return ModelHelper.MODEL_TRANSFORM_BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.renderer.simple.client;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.util.ModelIdentifier;
|
||||
|
||||
import net.fabricmc.fabric.api.client.model.ModelProviderContext;
|
||||
import net.fabricmc.fabric.api.client.model.ModelVariantProvider;
|
||||
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
|
||||
|
||||
public class PillarModelVariantProvider implements ModelVariantProvider {
|
||||
@Override
|
||||
@Nullable
|
||||
public UnbakedModel loadModelVariant(ModelIdentifier modelId, ModelProviderContext context) {
|
||||
if (RendererTest.PILLAR_ID.equals(modelId)) {
|
||||
return new PillarUnbakedModel();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.test.renderer.simple.client;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.Baker;
|
||||
import net.minecraft.client.render.model.ModelBakeSettings;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.test.renderer.simple.RendererTest;
|
||||
|
||||
public class PillarUnbakedModel implements UnbakedModel {
|
||||
private static final List<SpriteIdentifier> SPRITES = Stream.of("alone", "bottom", "middle", "top")
|
||||
.map(suffix -> new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, RendererTest.id("block/pillar_" + suffix)))
|
||||
.toList();
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getModelDependencies() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParents(Function<Identifier, UnbakedModel> modelLoader) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(Baker baker, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
|
||||
Sprite[] sprites = new Sprite[SPRITES.size()];
|
||||
|
||||
for (int i = 0; i < sprites.length; ++i) {
|
||||
sprites[i] = textureGetter.apply(SPRITES.get(i));
|
||||
}
|
||||
|
||||
return new PillarBakedModel(sprites);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ public final class RendererClientTest implements ClientModInitializer {
|
|||
@Override
|
||||
public void onInitializeClient() {
|
||||
ModelLoadingRegistry.INSTANCE.registerResourceProvider(manager -> new FrameModelResourceProvider());
|
||||
ModelLoadingRegistry.INSTANCE.registerVariantProvider(manager -> new PillarModelVariantProvider());
|
||||
|
||||
for (FrameBlock frameBlock : RendererTest.FRAMES) {
|
||||
BlockRenderLayerMap.INSTANCE.putBlock(frameBlock, RenderLayer.getCutoutMipped());
|
||||
|
|
Binary file not shown.
After ![]() (image error) Size: 201 B |
Binary file not shown.
After ![]() (image error) Size: 194 B |
Binary file not shown.
After ![]() (image error) Size: 189 B |
Binary file not shown.
After ![]() (image error) Size: 196 B |
|
@ -48,7 +48,7 @@ import net.minecraft.world.BlockRenderView;
|
|||
* and then use {@link #getBlockEntityRenderAttachment(BlockPos)} to retrieve it. When called from the
|
||||
* main thread, that method will simply retrieve the data directly.
|
||||
*
|
||||
* <p>This interface is only guaranteed to be present in the client environment.
|
||||
* <p>This interface is guaranteed to be implemented on every {@link BlockRenderView} subclass.
|
||||
*/
|
||||
// XXX can not link net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel
|
||||
public interface RenderAttachedBlockView extends BlockRenderView {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"pack.source.fabricmod": "Fabric 모드",
|
||||
"pack.source.builtinMod": "%s에 내장됨"
|
||||
"pack.source.builtinMod": "%s에 내장"
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ prerelease=true
|
|||
fabric-api-base-version=0.4.15
|
||||
fabric-api-lookup-api-v1-version=1.6.13
|
||||
fabric-biome-api-v1-version=11.0.0
|
||||
fabric-block-api-v1-version=1.0.0
|
||||
fabric-blockrenderlayer-v1-version=1.1.24
|
||||
fabric-command-api-v1-version=1.2.15
|
||||
fabric-command-api-v2-version=2.1.11
|
||||
|
|
|
@ -15,6 +15,7 @@ include 'fabric-api-base'
|
|||
|
||||
include 'fabric-api-lookup-api-v1'
|
||||
include 'fabric-biome-api-v1'
|
||||
include 'fabric-block-api-v1'
|
||||
include 'fabric-blockrenderlayer-v1'
|
||||
include 'fabric-command-api-v2'
|
||||
include 'fabric-content-registries-v0'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue