Convert ModDependencies to an interface #15

Merged
owlsys merged 3 commits from TheKodeToad/mod-dependencies-iface into main 2024-09-02 12:09:57 -04:00
7 changed files with 118 additions and 108 deletions

View file

@ -1,43 +1,10 @@
package dev.frogmc.frogloader.api.mod;
import java.util.*;
import java.util.Collection;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
/**
* A mod's dependencies.
*
* <p>Mod dependencies are declared in four types:</p>
* <code>Type.DEPEND</code>, <code>Type.BREAK</code>, <code>Type.SUGGEST</code> and <code>Type.PROVIDE</code>
*
* <p>Note: The <code>Type.PROVIDE</code> is a bit of a special case in the way that it only supports a single SemVer version instead of a full version range.</p>
*
* @see ModDependencies.Type
* @see ModDependencies.Entry
* @see ModProperties
* @see SemVer
*/
public final class ModDependencies {
private final Map<Type, Collection<Entry>> entries = new HashMap<>();
/**
* Construct new mod dependencies for a mod.
* <p><strong>Internal use only.</strong></p>
*
* @param depends <code>Type.DEPEND</code> entries
* @param breaks <code>Type.BREAK</code> entries
* @param suggests <code>Type.SUGGEST</code> entries
* @param provides <code>Type.PROVIDE</code> entries
*/
@ApiStatus.Internal
public ModDependencies(Collection<Entry> depends, Collection<Entry> breaks, Collection<Entry> suggests, Collection<Entry> provides) {
entries.put(Type.DEPEND, depends);
entries.put(Type.BREAK, breaks);
entries.put(Type.SUGGEST, suggests);
entries.put(Type.PROVIDE, provides);
}
public interface ModDependencies {
/**
* Get dependencies of a specific mod for a specific type
@ -45,9 +12,7 @@ public final class ModDependencies {
* @param type the dependency type to query for
* @return a collection of dependency entries
*/
public Collection<Entry> getForType(Type type) {
return entries.get(type);
}
Collection<Entry> getForType(Type type);
/**
* Get entries that depend on a specific mod's id
@ -55,17 +20,7 @@ public final class ModDependencies {
* @param id the mod id to find dependency entries for
* @return a collection of entries that depend on the given mod id
*/
public Collection<ModEntry> getForModId(String id) {
List<ModEntry> entries = new ArrayList<>();
for (Type type : Type.values()) {
for (Entry entry : getForType(type)) {
if (entry.id.equals(id)) {
entries.add(new ModEntry(type, entry.range, entry.link, entry.name));
}
}
}
return entries;
}
Collection<Entry> getForModId(String id);
/**
* Dependency types to distinguish their variants.
@ -90,69 +45,45 @@ public final class ModDependencies {
}
kode marked this conversation as resolved Outdated

This class is missing javadocs

This class is missing javadocs
Outdated
Review

Added them, also hopefully added @Nullable on everything which can be null LMK if it's correct

Added them, also hopefully added @Nullable on everything which can be null LMK if it's correct
/**
* A data class to handle entries depending on a specific mod id
* Represents a mod's dependency.
*/
public static class ModEntry {
private final Type type;
private final String range;
private final String link;
private final String name;
private ModEntry(Type type, String range, String link, String name) {
this.type = type;
this.range = range;
this.link = link;
this.name = name;
}
interface Entry {
/**
* Get this dependency's type
* Get this dependency's type.
*
* @return This dependency's type
* @return This dependency's type.
*/
public Type type() {
return type;
}
Type type();
/**
* Get this dependency's version range
* Get this dependency's mod ID.
*
* @return This dependency's version range
* @return This dependency's mod ID.
*/
public String range() {
return range;
}
String id();
/**
* Get this dependency's link
* <p>May be null.</p>
* Get this dependency's version range.
*
* @return This dependency's link
* @return This dependency's version range.
*/
public @Nullable String link() {
return link;
}
@Nullable String range();
/**
* Get this dependency's (friendly) name
* <p>May be null.</p>
* Get this dependency's installation link.
*
* @return This dependency's name
* @return This dependency's installation link.
*/
public @Nullable String name() {
return name;
}
@Nullable String link();
/**
* Get this dependency's friendly name.
*
* @return This dependency's name.
*/
@Nullable String name();
}
/**
* General storage for dependencies
*
* @param id the mod's id
* @param range the dependency's version range
* @param link an optional link for information about this dependency
* @param name an optional (friendly) name for this dependency
*/
public record Entry(String id, String range, String link, String name) {
}
}

View file

@ -6,11 +6,13 @@ import java.util.Map;
import org.jetbrains.annotations.Nullable;
import dev.frogmc.frogloader.impl.mod.ModDependenciesImpl;
/**
* A mod's properties. This class represents a mod at runtime.
* It is read from each mod's <code>frog.mod.toml</code> file.
*
* @see ModDependencies
* @see ModDependenciesImpl
* @see ModExtensions
* @see SemVer
*/
@ -65,7 +67,7 @@ public interface ModProperties {
* Get this mod's dependencies.
*
* @return The mod's dependencies
* @see ModDependencies
* @see ModDependenciesImpl
*/
ModDependencies dependencies();

View file

@ -3,7 +3,6 @@ package dev.frogmc.frogloader.impl.mod;
import java.util.Collections;
import java.util.Map;
import dev.frogmc.frogloader.api.mod.ModDependencies;
import dev.frogmc.frogloader.api.mod.ModExtensions;
import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.impl.SemVerParseException;
@ -24,7 +23,7 @@ public class JavaModProperties {
SemVerImpl.parse(System.getProperty("java.runtime.version")),
"",
Map.of(System.getProperty("java.vm.vendor"), Collections.singleton("Vendor")),
new ModDependencies(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()),
new ModDependenciesImpl(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()),
new ModExtensionsImpl(Collections.emptyMap()), Collections.emptySet());
}
return INSTANCE;

View file

@ -0,0 +1,75 @@
package dev.frogmc.frogloader.impl.mod;
import java.util.*;
import dev.frogmc.frogloader.api.mod.ModDependencies;
import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.api.mod.SemVer;
/**
* A mod's dependencies.
*
* <p>Mod dependencies are declared in four types:</p>
* <code>Type.DEPEND</code>, <code>Type.BREAK</code>, <code>Type.SUGGEST</code> and <code>Type.PROVIDE</code>
*
* <p>Note: The <code>Type.PROVIDE</code> is a bit of a special case in the way that it only supports a single SemVer version instead of a full version range.</p>
*
* @see ModDependenciesImpl.Type
* @see ModDependenciesImpl.Entry
* @see ModProperties
* @see SemVer
*/
public final class ModDependenciesImpl implements ModDependencies {
private final Map<Type, Collection<ModDependencies.Entry>> entries = new HashMap<>();
/**
* Construct new mod dependencies for a mod.
* <p><strong>Internal use only.</strong></p>
*
* @param depends <code>Type.DEPEND</code> entries
* @param breaks <code>Type.BREAK</code> entries
* @param suggests <code>Type.SUGGEST</code> entries
* @param provides <code>Type.PROVIDE</code> entries
*/
public ModDependenciesImpl(Collection<ModDependencies.Entry> depends, Collection<ModDependencies.Entry> breaks, Collection<ModDependencies.Entry> suggests, Collection<ModDependencies.Entry> provides) {
entries.put(Type.DEPEND, depends);
entries.put(Type.BREAK, breaks);
entries.put(Type.SUGGEST, suggests);
entries.put(Type.PROVIDE, provides);
}
kode marked this conversation as resolved
Review

the @ApiStatus.Internal annotation can be removed

the `@ApiStatus.Internal` annotation can be removed
/**
* Get dependencies of a specific mod for a specific type
*
* @param type the dependency type to query for
* @return a collection of dependency entries
*/
@Override
public Collection<ModDependencies.Entry> getForType(Type type) {
return entries.get(type);
}
/**
* Get entries that depend on a specific mod's id
*
* @param id the mod id to find dependency entries for
* @return a collection of entries that depend on the given mod id
*/
@Override
public Collection<ModDependencies.Entry> getForModId(String id) {
List<ModDependencies.Entry> entries = new ArrayList<>();
for (Type type : Type.values()) {
for (ModDependencies.Entry entry : getForType(type)) {
if (entry.id().equals(id)) {
entries.add(entry);
}
}
}
return entries;
}
public record Entry(Type type, String id, String range, String link, String name) implements ModDependencies.Entry {
}
}

View file

@ -8,6 +8,7 @@ import java.util.stream.Collectors;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import dev.frogmc.frogloader.api.mod.ModDependencies;
import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.api.mod.SemVer;

View file

@ -7,6 +7,7 @@ import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -14,6 +15,7 @@ import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.electronwill.nightconfig.core.file.FileNotFoundAction;
import com.electronwill.nightconfig.toml.TomlParser;
import dev.frogmc.frogloader.api.mod.ModDependencies;
import dev.frogmc.frogloader.api.mod.ModExtensions;
import dev.frogmc.frogloader.api.mod.ModProperties;
@ -124,7 +126,7 @@ public class ModPropertiesReader {
}
}
Function<String, Collection<ModDependencies.Entry>> parseDependencies = key -> {
BiFunction<ModDependencies.Type, String, Collection<ModDependencies.Entry>> parseDependencies = (type, key) -> {
Collection<ModDependencies.Entry> result = new HashSet<>();
List<UnmodifiableConfig> dependenciesConfig = config.get("frog.dependencies." + key);
@ -138,7 +140,7 @@ public class ModPropertiesReader {
if (entryId == null || entryId.isEmpty())
badProperties.add("frog.dependencies." + key + '.' + i + ".id");
result.add(new ModDependencies.Entry(entryId, entryVersions, entry.get("link"), entry.get("name")));
result.add(new ModDependenciesImpl.Entry(type, entryId, entryVersions, entry.get("link"), entry.get("name")));
++i;
}
@ -148,10 +150,10 @@ public class ModPropertiesReader {
};
var depends = parseDependencies.apply("depends");
var breaks = parseDependencies.apply("breaks");
var suggests = parseDependencies.apply("suggests");
var provides = parseDependencies.apply("provides");
var depends = parseDependencies.apply(ModDependencies.Type.DEPEND, "depends");
var breaks = parseDependencies.apply(ModDependencies.Type.BREAK, "breaks");
var suggests = parseDependencies.apply(ModDependencies.Type.SUGGEST, "suggests");
var provides = parseDependencies.apply(ModDependencies.Type.PROVIDE, "provides");
UnmodifiableConfig extensionsConfig = config.get("frog.extensions");
Map<ModExtensionsImpl.Key, Object> extensions = new HashMap<>();
@ -169,7 +171,7 @@ public class ModPropertiesReader {
return new ModPropertiesImpl(id, name, icon, semVer, license, Collections.unmodifiableMap(credits),
new ModDependencies(depends, breaks, suggests, provides), new ModExtensionsImpl(extensions), sources);
new ModDependenciesImpl(depends, breaks, suggests, provides), new ModExtensionsImpl(extensions), sources);
});
private static final Map<String, Parser> versions = Arrays.stream(values()).collect(Collectors.toMap(v -> v.version, v -> v.parser));

View file

@ -16,11 +16,11 @@ import java.util.stream.Collectors;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import dev.frogmc.frogloader.api.FrogLoader;
import dev.frogmc.frogloader.api.mod.ModDependencies;
import dev.frogmc.frogloader.api.mod.ModExtensions;
import dev.frogmc.frogloader.api.mod.ModProperties;
import dev.frogmc.frogloader.api.plugin.GamePlugin;
import dev.frogmc.frogloader.impl.FrogLoaderImpl;
import dev.frogmc.frogloader.impl.mod.ModDependenciesImpl;
import dev.frogmc.frogloader.impl.mod.ModExtensionsImpl;
import dev.frogmc.frogloader.impl.mod.ModPropertiesImpl;
import dev.frogmc.frogloader.impl.util.SystemProperties;
@ -203,7 +203,7 @@ public class MinecraftGamePlugin implements GamePlugin {
return new ModPropertiesImpl("minecraft", "Minecraft", "/assets/minecraft/textures/block/grass_block_side.png",
MinecraftSemVerImpl.get(version), "MC-EULA",
Map.of("Mojang AB", Collections.singleton("Author")),
new ModDependencies(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()),
new ModDependenciesImpl(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()),
new ModExtensionsImpl(Collections.emptyMap()), Collections.emptySet());
}
}