Add id getter to ApiLookups and expose the BE in BlockApiCache ()

* Add id getter to ApiLookups and expose the BE in BlockApiCache

* identifier() -> getIdentifier(), and add some query methods to BlockApiCache

* getId
This commit is contained in:
Technici4n 2021-12-22 18:10:18 +01:00 committed by GitHub
parent 252fd7d614
commit 17be577f67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 134 additions and 18 deletions
fabric-api-lookup-api-v1/src

View file

@ -22,6 +22,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
@ -64,6 +65,30 @@ public interface BlockApiCache<A, C> {
@Nullable
A find(@Nullable BlockState state, C context);
/**
* Return the block entity at the target position of this lookup.
*
* <p>This is the most efficient way to query the block entity at the target position repeatedly:
* unless the block entity has been loaded or unloaded since the last query, the result will be cached.
*/
@Nullable
BlockEntity getBlockEntity();
/**
* Return the lookup this cache is bound to.
*/
BlockApiLookup<A, C> getLookup();
/**
* Return the world this cache is bound to.
*/
ServerWorld getWorld();
/**
* Return the position this cache is bound to.
*/
BlockPos getPos();
/**
* Create a new instance bound to the passed {@link ServerWorld} and position, and querying the same API as the passed lookup.
*/

View file

@ -236,6 +236,11 @@ public interface BlockApiLookup<A, C> {
*/
void registerFallback(BlockApiProvider<A, C> fallbackProvider);
/**
* Return the identifier of this lookup.
*/
Identifier getId();
/**
* Return the API class of this lookup.
*/

View file

@ -62,8 +62,9 @@ import net.fabricmc.fabric.impl.lookup.custom.ApiLookupMapImpl;
* return (ItemStackApiLookup<A, C>) LOOKUPS.getLookup(lookupId, apiClass, contextClass);
* }
*
* private ItemStackApiLookupImpl(Class<?> apiClass, Class<?> contextClass) {
* // We don't use these classes, so nothing to do here.
* private ItemStackApiLookupImpl(Identifier id, Class<?> apiClass, Class<?> contextClass) {
* // We don't use these parameters, so nothing to do here.
* // In practice, these parameters should be stored and exposed with identifier(), apiClass() and contextClass() getter functions.
* }
* // We will use an ApiProviderMap to store the providers.
* private final ApiProviderMap<Item, ItemStackApiProvider<A, C>> providerMap = ApiProviderMap.create();
@ -97,12 +98,12 @@ public interface ApiLookupMap<L> extends Iterable<L> {
/**
* Create a new instance.
*
* @param lookupFactory The factory that is used to create API lookup instances.
* @param lookupConstructor The constructor that is used to create API lookup instances.
*/
static <L> ApiLookupMap<L> create(LookupFactory<L> lookupFactory) {
Objects.requireNonNull(lookupFactory, "Lookup factory may not be null.");
static <L> ApiLookupMap<L> create(LookupConstructor<L> lookupConstructor) {
Objects.requireNonNull(lookupConstructor, "Lookup factory may not be null.");
return new ApiLookupMapImpl<>(lookupFactory);
return new ApiLookupMapImpl<>(lookupConstructor);
}
/**
@ -117,6 +118,33 @@ public interface ApiLookupMap<L> extends Iterable<L> {
*/
L getLookup(Identifier lookupId, Class<?> apiClass, Class<?> contextClass);
@FunctionalInterface
interface LookupConstructor<L> {
/**
* Create a new API lookup implementation.
*
* @param identifier The identifier of this lookup.
* @param apiClass The API class passed to {@link #getLookup}.
* @param contextClass The context class passed to {@link #getLookup}.
*/
L get(Identifier identifier, Class<?> apiClass, Class<?> contextClass);
}
/**
* Create a new instance.
*
* @param lookupFactory The factory that is used to create API lookup instances.
* @deprecated {@link LookupConstructor} should be used instead of lookup factory, to expose the identifier.
*/
@Deprecated(forRemoval = true)
static <L> ApiLookupMap<L> create(LookupFactory<L> lookupFactory) {
return create((id, apiClass, contextClass) -> lookupFactory.get(apiClass, contextClass));
}
/**
* @deprecated {@link LookupConstructor} should be used instead as it also passes the identifier.
*/
@Deprecated(forRemoval = true)
interface LookupFactory<L> {
/**
* Create a new API lookup implementation.

View file

@ -146,6 +146,11 @@ public interface EntityApiLookup<A, C> {
*/
void registerFallback(EntityApiProvider<A, C> fallbackProvider);
/**
* Return the identifier of this lookup.
*/
Identifier getId();
/**
* Returns the API class of this lookup.
*/

View file

@ -145,6 +145,11 @@ public interface ItemApiLookup<A, C> {
*/
void registerFallback(ItemApiProvider<A, C> fallbackProvider);
/**
* Return the identifier of this lookup.
*/
Identifier getId();
/**
* Return the API class of this lookup.
*/

View file

@ -61,11 +61,8 @@ public final class BlockApiCacheImpl<A, C> implements BlockApiCache<A, C> {
@Nullable
@Override
public A find(@Nullable BlockState state, C context) {
// Get block entity
if (!blockEntityCacheValid) {
cachedBlockEntity = world.getBlockEntity(pos);
blockEntityCacheValid = true;
}
// Update block entity cache
getBlockEntity();
// Get block state
if (state == null) {
@ -105,6 +102,32 @@ public final class BlockApiCacheImpl<A, C> implements BlockApiCache<A, C> {
return null;
}
@Override
@Nullable
public BlockEntity getBlockEntity() {
if (!blockEntityCacheValid) {
cachedBlockEntity = world.getBlockEntity(pos);
blockEntityCacheValid = true;
}
return cachedBlockEntity;
}
@Override
public BlockApiLookupImpl<A, C> getLookup() {
return lookup;
}
@Override
public ServerWorld getWorld() {
return world;
}
@Override
public BlockPos getPos() {
return pos;
}
static {
ServerBlockEntityEvents.BLOCK_ENTITY_LOAD.register((blockEntity, world) -> {
((ServerWorldCache) world).fabric_invalidateCache(blockEntity.getPos());

View file

@ -47,13 +47,15 @@ public final class BlockApiLookupImpl<A, C> implements BlockApiLookup<A, C> {
return (BlockApiLookup<A, C>) LOOKUPS.getLookup(lookupId, apiClass, contextClass);
}
private final Identifier identifier;
private final Class<A> apiClass;
private final Class<C> contextClass;
private final ApiProviderMap<Block, BlockApiProvider<A, C>> providerMap = ApiProviderMap.create();
private final List<BlockApiProvider<A, C>> fallbackProviders = new CopyOnWriteArrayList<>();
@SuppressWarnings("unchecked")
private BlockApiLookupImpl(Class<?> apiClass, Class<?> contextClass) {
private BlockApiLookupImpl(Identifier identifier, Class<?> apiClass, Class<?> contextClass) {
this.identifier = identifier;
this.apiClass = (Class<A>) apiClass;
this.contextClass = (Class<C>) contextClass;
}
@ -174,6 +176,11 @@ public final class BlockApiLookupImpl<A, C> implements BlockApiLookup<A, C> {
fallbackProviders.add(fallbackProvider);
}
@Override
public Identifier getId() {
return identifier;
}
@Override
public Class<A> apiClass() {
return apiClass;

View file

@ -28,10 +28,10 @@ import net.fabricmc.fabric.api.lookup.v1.custom.ApiLookupMap;
public final class ApiLookupMapImpl<L> implements ApiLookupMap<L> {
private final Map<Identifier, StoredLookup<L>> lookups = new HashMap<>();
private final LookupFactory<L> lookupFactory;
private final LookupConstructor<L> lookupConstructor;
public ApiLookupMapImpl(LookupFactory<L> lookupFactory) {
this.lookupFactory = lookupFactory;
public ApiLookupMapImpl(LookupConstructor<L> lookupConstructor) {
this.lookupConstructor = lookupConstructor;
}
@Override
@ -40,7 +40,7 @@ public final class ApiLookupMapImpl<L> implements ApiLookupMap<L> {
Objects.requireNonNull(apiClass, "API class may not be null.");
Objects.requireNonNull(contextClass, "Context class may not be null.");
StoredLookup<L> storedLookup = lookups.computeIfAbsent(lookupId, id -> new StoredLookup<>(lookupFactory.get(apiClass, contextClass), apiClass, contextClass));
StoredLookup<L> storedLookup = lookups.computeIfAbsent(lookupId, id -> new StoredLookup<>(lookupConstructor.get(id, apiClass, contextClass), apiClass, contextClass));
if (storedLookup.apiClass == apiClass && storedLookup.contextClass == contextClass) {
return storedLookup.lookup;

View file

@ -46,12 +46,14 @@ public class EntityApiLookupImpl<A, C> implements EntityApiLookup<A, C> {
private static final Map<Class<?>, Set<EntityType<?>>> REGISTERED_SELVES = new HashMap<>();
private static boolean checkEntityLookup = true;
private final Identifier identifier;
private final Class<A> apiClass;
private final Class<C> contextClass;
private final ApiProviderMap<EntityType<?>, EntityApiProvider<A, C>> providerMap = ApiProviderMap.create();
private final List<EntityApiProvider<A, C>> fallbackProviders = new CopyOnWriteArrayList<>();
private EntityApiLookupImpl(Class<A> apiClass, Class<C> contextClass) {
private EntityApiLookupImpl(Identifier identifier, Class<A> apiClass, Class<C> contextClass) {
this.identifier = identifier;
this.apiClass = apiClass;
this.contextClass = contextClass;
}
@ -153,6 +155,11 @@ public class EntityApiLookupImpl<A, C> implements EntityApiLookup<A, C> {
fallbackProviders.add(fallbackProvider);
}
@Override
public Identifier getId() {
return identifier;
}
@Override
public Class<A> apiClass() {
return apiClass;

View file

@ -43,13 +43,15 @@ public class ItemApiLookupImpl<A, C> implements ItemApiLookup<A, C> {
return (ItemApiLookup<A, C>) LOOKUPS.getLookup(lookupId, apiClass, contextClass);
}
private final Identifier identifier;
private final Class<A> apiClass;
private final Class<C> contextClass;
private final ApiProviderMap<Item, ItemApiProvider<A, C>> providerMap = ApiProviderMap.create();
private final List<ItemApiProvider<A, C>> fallbackProviders = new CopyOnWriteArrayList<>();
@SuppressWarnings("unchecked")
private ItemApiLookupImpl(Class<?> apiClass, Class<?> contextClass) {
private ItemApiLookupImpl(Identifier identifier, Class<?> apiClass, Class<?> contextClass) {
this.identifier = identifier;
this.apiClass = (Class<A>) apiClass;
this.contextClass = (Class<C>) contextClass;
}
@ -124,6 +126,11 @@ public class ItemApiLookupImpl<A, C> implements ItemApiLookup<A, C> {
fallbackProviders.add(fallbackProvider);
}
@Override
public Identifier getId() {
return identifier;
}
@Override
public Class<A> apiClass() {
return apiClass;

View file

@ -97,6 +97,10 @@ public class FabricApiLookupTest implements ModInitializer {
wrongInsertable.registerFallback((world, pos, state, be, nocontext) -> null);
}, "The registry should have prevented creation of another instance with different classes, but same id.");
if (!insertable2.getId().equals(new Identifier("testmod:item_insertable"))) {
throw new AssertionError("Incorrect identifier was returned.");
}
if (insertable2.apiClass() != ItemInsertable.class) {
throw new AssertionError("Incorrect API class was returned.");
}