Skip to content

Commit

Permalink
Add a bunch of docs
Browse files Browse the repository at this point in the history
  • Loading branch information
lukebemish committed Jul 15, 2023
1 parent bd96e48 commit c18094c
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@
import net.minecraft.server.packs.PackType;
import org.jetbrains.annotations.NotNull;

/**
* A {@link ResourceCache} meant to provide resources for data packs.
*/
public class DataResourceCache extends ResourceCache {
private final TagBakery tagBakery = new TagBakery();

/**
* @param name a unique identifier for this cache
*/
public DataResourceCache(ResourceLocation name) {
super(name);
this.planSource(tagBakery);
Expand All @@ -29,6 +35,9 @@ public boolean shouldCache() {
return PackType.SERVER_DATA;
}

/**
* @return a tool to easily add any number of tag entries to this cache
*/
@SuppressWarnings("unused")
public TagBakery tags() {
return tagBakery;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

import java.io.InputStream;

/**
* An object that can provide an input stream supplier at a given location.
*/
@FunctionalInterface
public interface InputStreamSource {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@

import java.util.Set;

/**
* An {@link InputStreamSource} that is aware of the locations it can provide input streams for.
*/
public interface PathAwareInputStreamSource extends InputStreamSource {


/**
* @return the locations that this {@link InputStreamSource} can provide resources at.
*/
@NotNull
Set<ResourceLocation> getLocations();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@

package dev.lukebemish.dynamicassetgenerator.api;

/**
* A listener called when a resource cache is reset.
*/
@FunctionalInterface
public interface Resettable {
/**
* Resets some state associated with sources registered to the resource cache.
*/
void reset();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import net.minecraft.server.packs.PackType;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.server.packs.resources.IoSupplier;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedInputStream;
Expand All @@ -24,31 +25,56 @@
import java.util.*;
import java.util.function.Supplier;

/**
* Caches instructions for producing resources, and generates them as packs are loaded.
*/
public abstract class ResourceCache {
protected static final String SOURCE_JSON_DIR = DynamicAssetGenerator.MOD_ID;
protected List<Supplier<? extends PathAwareInputStreamSource>> cache = new ArrayList<>();
private final List<Resettable> resetListeners = new ArrayList<>();

/**
* Register a new resource cache.
* @param cache the cache to register
* @param position the position to register the cache at
* @return the registered cache
* @param <T> the type of the cache
*/
public static <T extends ResourceCache> T register(T cache, Pack.Position position) {
DynamicAssetGenerator.registerCache(cache.getName(), cache, position);
return cache;
}

/**
* Register a new resource cache as the lowest priority resource pack.
* @param cache the cache to register
* @return the registered cache
* @param <T> the type of the cache
*/
@SuppressWarnings("unused")
public static <T extends ResourceCache> T register(T cache) {
return register(cache, Pack.Position.BOTTOM);
}

private final ResourceLocation name;

/**
* @return a unique identifier for this cache
*/
public ResourceLocation getName() {
return name;
}

/**
* @param name a unique identifier for this cache
*/
public ResourceCache(ResourceLocation name) {
this.name = name;
}

/**
* @return a map of all resources this pack can generate; calling this may resolve any given source cached to it
*/
public Map<ResourceLocation, IoSupplier<InputStream>> getResources() {
Map<ResourceLocation, IoSupplier<InputStream>> outputsSetup = new HashMap<>();
this.cache.forEach(p-> {
Expand All @@ -69,16 +95,26 @@ public Map<ResourceLocation, IoSupplier<InputStream>> getResources() {
return outputs;
}

/**
* @return a context for generating resources within this cache
*/
@NotNull
public ResourceGenerationContext getContext() {
return OldResourceGenerationContext.make(this.name, this.getPackType());
}

/**
* Adds a listener to be called when this cache is reset.
* @param listener the listener to add
*/
@SuppressWarnings("unused")
public void planResetListener(Resettable listener) {
this.resetListeners.add(listener);
}

/**
* Resets all listeners associated with this cache.
*/
@SuppressWarnings("unused")
public void reset() {
this.resetListeners.forEach(Resettable::reset);
Expand Down Expand Up @@ -131,40 +167,77 @@ private Map<ResourceLocation, IoSupplier<InputStream>> wrapCachedData(Map<Resour
return output;
}

/**
* @return whether this cache should be cached to disk
*/
public abstract boolean shouldCache();

/**
* @return the path on disk to cache this cache to, if it should be cached to the disk
*/
public Path cachePath() {
return Services.PLATFORM.getModDataFolder().resolve("cache").resolve(name.getNamespace()).resolve(name.getPath());
}

/**
* Plan a source to be generated at a given resource location when this cache is resolved.
* @param rl the resource location the generated source is located at
* @param source the source to generate
*/
@SuppressWarnings("unused")
public void planSource(ResourceLocation rl, InputStreamSource source) {
cache.add(wrap(()->Set.of(rl),source));
}

/**
* Plan to generate sources at a currently unresolved set of locations when this cache is resolved.
* @param locations the locations to generate; resolved when this cache is resolved
* @param source the source to generate
*/
@SuppressWarnings("unused")
public void planSource(Supplier<Set<ResourceLocation>> locations, InputStreamSource source) {
cache.add(wrap(locations, source));
}

/**
* Plan to generate sources at a set of locations when this cache is resolved.
* @param locations the locations to generate
* @param source the source to generate
*/
@SuppressWarnings("unused")
public void planSource(Set<ResourceLocation> locations, InputStreamSource source) {
cache.add(wrap(()->locations, source));
}

/**
* Plan to generate a source when this cache is resolved.
* @param source the source to generate
*/
public void planSource(PathAwareInputStreamSource source) {
cache.add(()->source);
if (source instanceof Resettable resettable)
planResetListener(resettable);
}

/**
* Plan to generate a currently unresulved source when this cache is resolved.
* @param source the source to generate; resulved when this cache is resolved
*/
public void planSource(Supplier<? extends PathAwareInputStreamSource> source) {
cache.add(source);
}

/**
* @return the type of pack this cache will generate resources for
*/
@NotNull
public abstract PackType getPackType();

/**
* This method should be considered internal, but to avoid breaking backwards compatibility, no breaking changes
* will be made until DynAssetGen 5.0.0 or later.
*/
@ApiStatus.Internal
public static Supplier<PathAwareInputStreamSource> wrap(Supplier<Set<ResourceLocation>> rls, InputStreamSource source) {
return () -> new PathAwareInputStreamSource() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,42 @@
import java.io.InputStream;
import java.util.Set;

/**
* Information available during resource generation, passed to {@link InputStreamSource} as they are generated.
*/
public abstract class ResourceGenerationContext {
/**
* @deprecated Use {@link #getCacheName()} instead.
*/
@Deprecated(forRemoval = true, since = "4.1.0")
@NotNull public ResourceLocation cacheName() {
return getCacheName();
}

/**
* @return a resource location unique to the {@link ResourceCache} this context is linked to
*/
@NotNull public abstract ResourceLocation getCacheName();

/**
* Attempts to get a resource at a given location, from the highest priority pack not provided by another {@link ResourceCache}.
* @param location the location to get the resource at
* @return a supplier for an input stream for the resource, or null if the resource does not exist
*/
@Nullable public abstract IoSupplier<InputStream> getResource(@NotNull ResourceLocation location);

/**
* Lists all resources within a given path, from highest to lowest priority.
* @param namespace the namespace to list resources from
* @param path the path to list resources from
* @param resourceOutput the output to write the resources to
*/
@SuppressWarnings("unused")
public abstract void listResources(@NotNull String namespace, @NotNull String path, @NotNull PackResources.ResourceOutput resourceOutput);

/**
* @return a set of all namespaces that have resources in this context
*/
@SuppressWarnings("unused")
@NotNull public abstract Set<String> getNamespaces();
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

import java.util.function.Function;

/**
* Represents a set of instructions to generate any number of resources, to be read from JSON.
*/
public interface ResourceGenerator extends PathAwareInputStreamSource {
Codec<ResourceGenerator> CODEC = ExtraCodecs.lazyInitializedCodec(() -> new Codec<Codec<? extends ResourceGenerator>>() {
@Override
Expand All @@ -36,10 +39,17 @@ public <T> DataResult<T> encode(Codec<? extends ResourceGenerator> input, Dynami
}
}).dispatch(ResourceGenerator::codec, Function.identity());

/**
* Registers a new resource generator type.
* @param rl The resource location to register the generator under; becomes the {@code "type"} field in JSON.
* @param reader The codec used to deserialize the generator from JSON.
*/
static void register(ResourceLocation rl, Codec<? extends ResourceGenerator> reader) {
CommonRegisters.RESOURCEGENERATORS.put(rl, reader);
}


/**
* @return A codec that can serialize this resource generator.
*/
Codec<? extends ResourceGenerator> codec();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@
import net.minecraft.server.packs.PackType;
import org.jetbrains.annotations.NotNull;

/**
* A {@link ResourceCache} meant to provide resources for resource packs. Texture sources should only be used within
* a class extending this, to ensure that caching is respected.
*/
public class AssetResourceCache extends ResourceCache {
@SuppressWarnings("unused")
public static final ResourceLocation EMPTY_TEXTURE = new ResourceLocation(DynamicAssetGenerator.MOD_ID, "textures/empty.png");

/**
* @param name a unique identifier for this cache
*/
public AssetResourceCache(ResourceLocation name) {
super(name);
this.planResetListener(() -> TexSourceCache.reset(this.getContext()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

import java.util.function.Function;

/**
* Contains instructions for generating a single texture. Many implementations allow for nesting of further sources
* within this; thus, to avoid the generation of duplicate sources, texture sources are cached, if possible, with their
* key being their serialized form in JSON. If this information is not enough to uniquely identify the texture a source
* will produce (for instance, if it uses information passed in a context), then a source should implement the caching
* API as needed.
*/
public interface TexSource {

String METADATA_CACHE_KEY = "__dynamic_asset_generator_metadata";
Expand Down Expand Up @@ -60,6 +67,12 @@ public <T1> DataResult<T1> encode(DynamicOps<T1> ops, TexSourceDataHolder data,
}
}, METADATA_CACHE_KEY, TexSourceDataHolder.class);

/**
* Register a new type of texture source, alongside a codec to decode from JSON and encode to a cache key.
* @param rl the identifier of this texture source type
* @param codec can serialize and deserialize this texture source type
* @param <T> the texture source type
*/
static <T extends TexSource> void register(ResourceLocation rl, Codec<T> codec) {
ClientRegisters.TEXSOURCES.put(rl, codec);
}
Expand All @@ -77,11 +90,27 @@ default <T> DataResult<T> cacheMetadata(DynamicOps<T> ops, TexSourceDataHolder d
return DataResult.success(ops.empty());
}

/**
* @return a codec which can be used to serialize this source
*/
Codec<? extends TexSource> codec();

/**
*
* @param data context information passed by outer nesting texture sources; if you depend on this, you will want to
* implement the caching API (see {@link #cacheMetadata})
* @param context context about the environment the texture is generating in
* @return a supplier able to produce the texture, or null if the texture could not be produced.
*/
@Nullable
IoSupplier<NativeImage> getSupplier(TexSourceDataHolder data, ResourceGenerationContext context);

/**
* If you are using texture sources directly through the java API, you will likely want to call this on sources you
* construct. In the future, this may become more redundant as tools are integrated to cache all sources in this way
* automatically.
* @return a version of this texture source that utilizes the cache.
*/
@ApiStatus.Experimental
default TexSource cached() {
if (this instanceof TexSourceCachingWrapper) return this;
Expand Down
Loading

0 comments on commit c18094c

Please sign in to comment.