[docs] Move to mdbook and document libjf-config v1 modules

This commit is contained in:
Johannes Frohnmeyer 2022-08-27 20:17:13 +02:00
parent af19515d0f
commit f434e8843a
Signed by: Johannes
GPG Key ID: E76429612C2929F4
39 changed files with 387 additions and 179 deletions

1
.gitignore vendored
View File

@ -122,3 +122,4 @@ run/
bin
.project
.settings
/public

View File

@ -2,11 +2,11 @@ include:
- remote: 'https://jfmods.gitlab.io/scripts/jfmod.yml'
pages:
image: python:3.8-buster
image: archlinux:latest
stage: deploy
script:
- pip install mkdocs
- mkdocs build
- pacman -Sy mdbook --noconfirm
- mdbook build
artifacts:
paths:
- public

16
book.toml Normal file
View File

@ -0,0 +1,16 @@
[book]
authors = ["JFronny"]
language = "en"
multilingual = false
src = "docs"
title = "LibJF"
description = "Documentation for the LibJF library"
[build]
build-dir = "public"
[output.html]
git-repository-url = "https://gitlab.com/jfmods/LibJF"
git-repository-icon = "fa-gitlab"
edit-url-template = "https://gitlab.com/jfmods/LibJF/edit/master/{path}"
site-url = "https://jfronny.gitlab.io/LibJF"

View File

@ -4,14 +4,14 @@ This modularization is inspired by Fabric API.
LibJF is only maintained for the latest version of minecraft and tries to provide a stable ABI during its lifespan
but is open for breaking changes between versions.
Be aware that modules may depend on another and maven builds do not include dependencies.
Be aware that modules may depend on another and that those transitive dependencies must be JiJd separately.
Modules may also require fabric-api to be present to work properly
### Using LibJF
The recommended way to use LibJF is using the JfMods scripts, which include the LibJF maven repository
and simplify building fabric mods. My own mods (including LibJF) use these.
Otherwise you can add the repository as follows:
Otherwise, you can add the repository as follows:
```groovy
repositories {
maven { url 'https://gitlab.com/api/v4/projects/25805200/packages/maven' }
@ -20,10 +20,12 @@ repositories {
and include LibJF modules like this:
```groovy
dependencies {
include modImplementation("io.gitlab.jfronny.libjf:libjf-config-v1:${project.jfapi_version}")
include("io.gitlab.jfronny.libjf:libjf-unsafe-v0:${project.jfapi_version}")
include("io.gitlab.jfronny.libjf:libjf-base:${project.jfapi_version}")
modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-devutil-v0:${project.jfapi_version}")
include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${project.libjf_version}")
include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${project.libjf_version}")
include("io.gitlab.jfronny.libjf:libjf-base:${project.libjf_version}")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-reflect-v1:${project.libjf_version}")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil-v0:${project.libjf_version}")
}
```

19
docs/SUMMARY.md Normal file
View File

@ -0,0 +1,19 @@
# Summary
- [About](./README.md)
# Modules
- [libjf-base](./libjf-base.md)
- [Config](./config/README.md)
- [libjf-config-core-v1](./config/libjf-config-core-v1.md)
- [libjf-config-reflect-v1](./config/libjf-config-reflect-v1.md)
- [libjf-config-compiler-plugin](./config/libjf-config-compiler-plugin.md)
- [libjf-config-commands-v1](./config/libjf-config-commands-v1.md)
- [libjf-config-ui-tiny-v1](./config/libjf-config-ui-tiny-v1.md)
- [libjf-devutil](./libjf-devutil.md)
- [libjf-data-v0](./libjf-data-v0.md)
- [libjf-data-manipulation-v0](./libjf-data-manipulation-v0.md)
- [libjf-translate-v1](./libjf-translate-v1.md)
- [libjf-unsafe-v0](./libjf-unsafe-v0.md)
- [libjf-web-v0](./libjf-web-v0.md)

88
docs/config/README.md Normal file
View File

@ -0,0 +1,88 @@
# About
LibJF Config is a modular config library.
Generally, using a combination of its modules is recommended.
On the following pages, the modules of libjf-config are explained in more detail.
If you just want to get started, a quick setup example for a client-side mod using the compiler plugin can be seen below:
settings.gradle:
```groovy
pluginManagement {
repositories {
maven {
name = 'JF Commons'
url = 'https://gitlab.com/api/v4/projects/35745143/packages/maven'
}
maven {
name = 'LibJF'
url = 'https://gitlab.com/api/v4/projects/25805200/packages/maven'
}
}
}
```
build.gradle:
```groovy
plugins {
id 'io.gitlab.jfronny.libjf.libjf-config-compiler-plugin' version 'VERSION'
}
repositories {
maven { url 'https://gitlab.com/api/v4/projects/25805200/packages/maven' }
}
dependencies {
include modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v1:${project.libjf_version}")
include modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-config-ui-tiny-v1:${project.libjf_version}")
include("io.gitlab.jfronny.libjf:libjf-base:${project.libjf_version}")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-reflect-v1:${project.libjf_version}")
}
task injectCompiledConfig(type: io.gitlab.jfronny.libjf.config.plugin.ConfigInjectTask, dependsOn: jar) {
from jar
modId = archivesBaseName
archiveClassifier = 'config-inject'
destinationDirectory = file("${project.buildDir}/devlibs")
}
remapJar {
dependsOn injectCompiledConfig
input = injectCompiledConfig.archiveFile
}
loom {
mods {
register(name, {
sourceSet sourceSets.main
})
}
}
```
fabric.mod.json:
```json
{
"entrypoints": {
"libjf:config": ["Your config class here"]
}
}
```
Config class:
```java
@JfConfig
public class ConfigExample {
@Entry public static boolean someEntry = true;
}
```
en_us.json:
```json
{
"modid.jfconfig.title": "Your Mod",
"modid.jfconfig.someEntry": "Some Entry",
"modid.jfconfig.someEntry.tooltip": "Some comment"
}
```
I also recommend adding [ModMenu](https://github.com/TerraformersMC/ModMenu/wiki/API) in order to more easily test your config in dev.

View File

@ -0,0 +1,4 @@
# libjf-config-commands-v1
This serverside module provides commands for modifying configs using this library.
If you are developing a serverside mod, you may wish to include it to enable easier configuration.
The commands are available under `/libjf config`, using auto-complete is recommended.

View File

@ -0,0 +1,9 @@
# libjf-config-compiler-plugin
This gradle plugin provides a task that identifies any config files in a jar and produces the necessary code and registration for it.
Using this is the recommended way to use libjf-config.
Please be aware that the restrictions of [the reflection implementation](./libjf-config-reflect-v1) in regard to class loading
will also apply to configs using the plugin if it is loaded during runtime.
Using the reflection implementation as `modRuntimeLocal` is also recommended since the compiler plugin will be unable to affect loom dev envs otherwise.
The code necessary for using this plugin is available [here](./README.md)

View File

@ -0,0 +1,52 @@
# libjf-config-core-v1
The core module contains the abstractions and annotations used by other modules to interact with configs.
It also contains the code for registering configs to mods, serialization and automatic reloads on change.
## DSL
The DSL is used to create or register instances of ConfigInstance.
You may obtain an instance via `DSL.create()`
## ConfigHolder
You can use this class to obtain your registered config instance or those of other mods.
To do so, use `ConfigHolder.getInstance().get("modId")` and `ConfigHolder.getInstance().getRegistered()`
## Annotations
This module also provides the annotations used in other modules.
Use them as follows:
```java
@JfConfig // This class is a config. Also takes the optional parameter referencedConfigs to add a button to go to the config of another mod
class SomeConfig {
@Entry // This field is an entry. Also takes the optional parameters min and max for clamping number values
public static int someEntry = 15; // Any type can be used, but only int, long, float, double, boolean, their Boxes, Strings and enums are supported in ui-tiny
@Preset // This method is a preset. A UI entry for it will be created. When it is pressed, this method will be called
public static void somePreset() { // Must return void and take no arguments. The method name will be used as the preset name
someEntry = 12; // You may modify the entries of the config here
}
@Verifier // This method is a verifier. It will be called whenever a config is changed or loaded.
public static void someVerifier() {
if (someEntry % 2 != 0) someEntry++; // You can enforce additional constraints on values
}
@Category // This is a category. Just like JfConfig, you may specify referencedConfigs
public static class SomeCategory {
// A category can contain anything supported by the main config class, including fields, presets, verifiers and subcategories
}
}
```
## Custom config registration
In order to register mods without the compiler plugin or runtime module,
you can use a `libjf:config` entrypoint implementing JfCustomConfig.
As a parameter, you will be provided with a defaulted DSL with which you must interact to do so.
## Comments
For enums, the possible values will automatically be written to the config as comments.
You can add additional comments for entries by registering tooltips in your language file as follows:
```json
{
"<mod id>.jfconfig.<entry>.tooltip": "Some comment"
}
```

View File

@ -0,0 +1,8 @@
# libjf-config-reflect-v1
This module uses reflection to register configs from files using the annotations as presented [here](./libjf-config-core-v1.md)
In order to register a config, simply add the class annotated as `@JfConfig` to the `libjf:config` entrypoint.
Please be aware that this module may load your config class before the game classes are available.
Using them there WILL result in problems!
You should use this module in dev when relying on the [compiler plugin](./libjf-config-compiler-plugin.md) for prod,
as it is not applied in your dev env, and you will be unable to change configs without it.

View File

@ -0,0 +1,4 @@
# libjf-config-ui-tiny-v1
This module provides an automatically registered, TinyConfig-based UI for all mods using libjf-config.
Embedding this is recommended when developing client-side mods.
Manually generating config screens is also possible through `ConfigScreen.create(config, parent)`

View File

@ -1,97 +0,0 @@
# libjf-config-v0
LibJF config provides config screens and is partially based on TinyConfig and MidnightLib
It depends on libjf-unsafe-v0 to ensure configs are loaded before you use them and libjf-base
To add a config create a class using only static fields with default values like this:
```java
import io.gitlab.jfronny.libjf.config.api.JfConfig;
import io.gitlab.jfronny.libjf.config.api.Entry;
import io.gitlab.jfronny.commons.serialize.gson.GsonIgnore;
public class TestConfig implements JfConfig {
@Entry public static boolean disablePacks = false;
@Entry public static Boolean disablePacks2 = false;
@Entry public static int intTest = 20;
@Entry(min = -6) public static float floatTest = -5;
@Entry(max = 21) public static double doubleTest = 20;
@Entry public static String dieStr = "lolz";
@Entry @GsonIgnore public static String guiOnlyStr = "lolz";
public static String gsonOnlyStr = "lolz";
@Entry public static Test enumTest = Test.Test;
public enum Test {
Test, ER
}
}
```
You MUST annotate any field configurable through the UI as @Entry and the class MUST extend JfConfig.
You MAY annotate fields as @GsonHidden, @ClientOnly or @ServerOnly to hide them from the file as well them (-> [libjf-base](libjf-base.md)).
Numeric values MAY have a min and max value specified in their @Entry.
To register a config, add a `libjf:config` entrypoint pointing to its class to your fabric.mod.json.
To manually register a config or save changes, use `io.gitlab.jfronny.libjf.config.api.ConfigInstance`
For example, to save a config for a mod titled `yourmod`:
```java
// Directly using ConfigInstance
ConfigInstance.get("yourmod").write();
// Using ConfigHolder
ConfigHolder.getInstance().get("yourmod").write();
```
LibJF config is intentionally designed to be easy to implement, pleasant for the user and somewhat lightweight.
It is not intended to be used as a general purpose solution for everything, other libraries are better suited for that.
## Translations
Config keys are translated as `<mod id>.jfconfig.<field name>`.
You may add a tooltip as follows: `<mod id>.jfconfig.<field name>.tooltip`.
Enum keys are translated as follows: `<mod id>.jfconfig.enum.<enum class name>.<entry name>`
## Categories
Categories can be added by creating public static subclasses in your config class and annotating them with @Category.
Entries will be read as before, however the translation prefix will be `jfconfig.<category>.` instead of `jfconfig.`
## Presets
libjf-config-v0 provides a preset system to automatically fill in certain values based on a function.
To add a snippet, add a public static method to your config class and annotate it with @Preset.
If your preset is selected, the method will be executed.
You may assign a name by using your language file, the format for names is `<mod id>.jfconfig.<method name>`
Example:
```java
@Preset
public static void moskau() {
disablePacks = true;
disablePacks2 = true;
intTest = -5;
floatTest = -6;
doubleTest = 4;
dieStr = "Moskau";
}
```
## Verifiers
If you need to manually validate config values outside of minimums or maximums, you may add a public static method
and annotate it with @Verifier. This method will be executed whenever your config changes, which might happen often.
Be careful to write performant code here!
Example:
```java
@Verifier
public static void setIntTestIfDisable() {
if (disablePacks) intTest = 0;
}
```
## References
Sometimes, your mod interacts with other mods (such as libjf-web-v0), and you may wish to display their config screens as well.
If that other mod utilizes libjf-config-v0, you can simply add a json block as seen below to your fabric.mod.json
and it will be mentioned in the GUI.
```json
"custom": {
"libjf": {
"config": {
"referencedConfigs": ["libjf-web-v0"]
}
}
}
```

View File

@ -1,6 +1,5 @@
# libjf-data-manipulation-v0
libjf-data-manipulation-v0 provides code for modifying existing resources.
It depends on libjf-unsafe-v0 to patch ResourcePack implementations, libjf-base and fabric-api-base
libjf-data-manipulation-v0 provides code for modifying existing resources
### RecipeUtil
RecipeUtil provides to methods to end users:

View File

@ -2,6 +2,4 @@
libjf-data-v0 provides two additional tags for use in other mods or datapacks:
- `libjf:shulker_boxes_illegal` prevents items from being placed in shulker boxes (intended for backpacks)
- `libjf:overpowered` makes entities wearing four or more armor items with this tag invincible
It depends on libjf-base and fabric-resource-loader-v0
- `libjf:overpowered` makes entities wearing four or more armor items with this tag invincible

View File

@ -1,7 +1,5 @@
# libjf-devutil-v0
LibJF devutil is intended to be used as `runtimeOnly`.
# libjf-devutil
LibJF devutil is intended to be used as `modLocalRuntime`.
It marks the running minecraft instance as a development instance (for example, this removes the need for eula.txt)
and disables the UserApi (removing that Yggdrasil error message)
It does not provide any useful functionality to end users
It depends on libjf-base
It does not provide any useful functionality to end users

View File

@ -5,22 +5,3 @@ To use this, first obtain a TranslateService instance. You can use `TranslateSer
Please be aware that due to the nature of java generics, using var instead of a specific type for instances is recommended.
You can also directly access implementations, however, this is not recommended and is not subject to the API stability promise.
The TranslateService interface exposes all relevant functionality.
TranslateService::
| Name | Explanation |
|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
| `static TranslateService<?> getConfigured()` | Returns the TranslateService the user configured. Implementations may change without notice. |
| `static List<TranslateService<?>> getAvailable()` | Returns all available TranslateServices. Please use getConfigured() instead where possible. |
| `String translate(String textToTranslate, T translateFrom, T translateTo` | Translates a string from the specified source language (or null to auto-detect) to the target language. |
| `T detect(String text)` | Detects the language used in the specified string. |
| `T parseLang(Stirng lang)` | Gets the language for the specified ID |
| `List<T> getAvailableLanguages()` | Get all available languages for the configured service. |
| `String getName()` | Get the name of this translate service. |
Language:
| Name | Explanation |
|---------------------------|--------------------------------------------------------------------------|
| `String getDisplayName()` | Returns the string to show in UIs for this language |
| `String getIdentifier()` | Returns the ID for internal use (TranslateService.parseLang for example) |

View File

@ -1,7 +1,8 @@
# libjf-unsafe-v0
libjf-unsafe-v0 provides an entrypoint which is called extremely early and ASM modification.
It also ensures dependency libraries are on the classpath during both.
libjf-unsafe-v0 only depends on libjf-base, though using it with the fabric loader version it was developed for is recommended
Due to the fact that it accesses several internal components of fabric loader,
it is probably incompatible with versions of fabric loader it was not explicitly developed for.
### UltraEarlyInit
Implement `UltraEarlyInit` on your entrypoint and add it as a `libjf:early` entrypoint
@ -30,11 +31,13 @@ Examples can be found in libjf-data-manipulation-v0 and GWWHIT
Debugging ASM is difficult, but you can use the asm.log/asm.export flags to get additional output.
You can do so either by adding `-Plibjf.asm.log -Plibjf.asm.export` to your JVM args or the following to your fabric.mod.json:
```json
"custom": {
{
"custom": {
"libjf": {
"asm.log": true,
"asm.export": true
"asm.log": true,
"asm.export": true
}
}
}
```
I also recommend using IDEAs bytecode viewer on resulting classes to understand the bytecode

View File

@ -6,11 +6,13 @@ libjf-web-v0 depends on libjf-config-v1 to provide its config, libjf-base, fabri
### Getting started
Implement WebInit and register it as a libjf:web entrypoint. To enable the server, also add the following to your fabric.mod.json:
```json
"custom": {
{
"custom": {
"libjf": {
"web": true
}
}
}
```
Please be aware that your entrypoint may be called multiple times during one session.
You can register content providers using the register* methods on the WebServer parameter of your entrypoint.

View File

@ -128,7 +128,7 @@ public class JfConfigCommand implements ModInitializer {
}
private <T> ArgumentType<?> getType(EntryInfo<T> info) {
Type<T> type = info.getValueType();
Type type = info.getValueType();
if (type.isInt()) return IntegerArgumentType.integer((int) info.getMinValue(), (int) info.getMaxValue());
else if (type.isLong()) return LongArgumentType.longArg((long) info.getMinValue(), (long) info.getMaxValue());
else if (type.isFloat()) return FloatArgumentType.floatArg((float) info.getMinValue(), (float) info.getMaxValue());

View File

@ -5,6 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for config subclasses, which are to be shown as categories
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Category {

View File

@ -5,6 +5,9 @@ import io.gitlab.jfronny.libjf.LibJf;
import java.util.List;
import java.util.Map;
/**
* This class represents a config category. Do not implement manually!
*/
public interface ConfigCategory {
String getId();
String getCategoryPath();

View File

@ -5,15 +5,62 @@ import io.gitlab.jfronny.libjf.config.impl.ConfigHolderImpl;
import java.nio.file.Path;
import java.util.Map;
/**
* An interface for interacting with the class responsible for holding registered configs
*/
public interface ConfigHolder {
/**
* Obtain an instance of ConfigHolder with which to interact
* @return The config holder
*/
static ConfigHolder getInstance() {
return ConfigHolderImpl.INSTANCE;
}
/**
* Register a config to a mod
* @param modId The ID of the mod for which to register the config
* @param config The config
*/
void register(String modId, ConfigInstance config);
/**
* Get all registered configs by their mod id
* @return the configs
*/
Map<String, ConfigInstance> getRegistered();
/**
* Obtain a config for a specific mod
* @param modId The mod to obtain a config for
* @return The config or null
*/
ConfigInstance get(String modId);
/**
* Obtain a config by its file path
* @param configPath The file path
* @return The config or null
*/
ConfigInstance get(Path configPath);
/**
* Check whether this mod has registered a config
* @param modId The ID of the mod
* @return Whether a config is registered
*/
boolean isRegistered(String modId);
/**
* Check whether this path belongs to a registered config
* @param configPath The path to check
* @return Whether the path belongs to a registered config
*/
boolean isRegistered(Path configPath);
/**
* Migrate config for a mod from old locations (obtained through provides)
* @param modId The mod to migrate configs for
*/
void migrateFiles(String modId);
}

View File

@ -3,6 +3,9 @@ package io.gitlab.jfronny.libjf.config.api.v1;
import java.nio.file.Path;
import java.util.*;
/**
* This class represents a configuration. An instance may be obtained through ConfigHolder or the DSL. Do not implement manually!
*/
public interface ConfigInstance extends ConfigCategory {
static ConfigInstance get(String modId) {
return ConfigHolder.getInstance().get(modId);

View File

@ -5,6 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for fields in configs or categories which are to be shown
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Entry {

View File

@ -50,7 +50,7 @@ public interface EntryInfo<T> {
* Get the value type of this entry. Will use the class definition, not the current value
* @return The type of this entry
*/
Type<T> getValueType();
Type getValueType();
/**
* Ensure the current value is within expected bounds.

View File

@ -2,6 +2,9 @@ package io.gitlab.jfronny.libjf.config.api.v1;
import java.lang.annotation.*;
/**
* An annotation for config classes
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface JfConfig {

View File

@ -2,6 +2,9 @@ package io.gitlab.jfronny.libjf.config.api.v1;
import io.gitlab.jfronny.libjf.config.api.v1.dsl.DSL;
/**
* The interface for entrypoints performing custom config registrations
*/
public interface JfCustomConfig {
void register(DSL.Defaulted dsl);
}

View File

@ -5,6 +5,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for static methods in config classes which may be called when the user selects them in-game
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Preset {

View File

@ -5,6 +5,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for methods which are called every time a config is loaded or changed.
* Use these to implement additional bounds for values et cetera
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Verifier {

View File

@ -3,10 +3,13 @@ package io.gitlab.jfronny.libjf.config.api.v1.dsl;
import io.gitlab.jfronny.libjf.config.api.v1.*;
import io.gitlab.jfronny.libjf.config.api.v1.type.Type;
import java.lang.reflect.Field;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* An interface obtained through DSL or ConfigBuilder.category(), used for building config categories
* @param <Builder> The class implementing this builder
*/
public interface CategoryBuilder<Builder extends CategoryBuilder<Builder>> {
Builder setTranslationPrefix(String translationPrefix);
String getTranslationPrefix();
@ -25,7 +28,7 @@ public interface CategoryBuilder<Builder extends CategoryBuilder<Builder>> {
Builder value(String id, boolean def, Supplier<Boolean> get, Consumer<Boolean> set);
Builder value(String id, String def, String[] options, Supplier<String> get, Consumer<String> set);
<T extends Enum<T>> Builder value(String id, T def, Class<T> klazz, Supplier<T> get, Consumer<T> set);
<T> Builder value(String id, T def, double min, double max, Type<T> type, int width, Supplier<T> get, Consumer<T> set);
<T> Builder value(String id, T def, double min, double max, Type type, int width, Supplier<T> get, Consumer<T> set);
<T> Builder value(EntryInfo<T> entry);
String getId();

View File

@ -5,6 +5,10 @@ import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import java.nio.file.Path;
import java.util.function.Consumer;
/**
* An interface obtained through DSL, used to create config instances
* @param <Builder> The class implementing this builder
*/
public interface ConfigBuilder<Builder extends ConfigBuilder<Builder>> extends CategoryBuilder<Builder> {
Builder setLoadMethod(Consumer<ConfigInstance> load);
Builder setWriteMethod(Consumer<ConfigInstance> write);

View File

@ -4,6 +4,9 @@ import io.gitlab.jfronny.libjf.config.api.v1.ConfigHolder;
import io.gitlab.jfronny.libjf.config.api.v1.ConfigInstance;
import io.gitlab.jfronny.libjf.config.impl.dsl.DSLImpl;
/**
* An interface to allow easy creation or registration of configs
*/
public interface DSL {
static DSL create() {
return new DSLImpl();
@ -17,6 +20,10 @@ public interface DSL {
ConfigInstance register(String configId, ConfigBuilder.ConfigBuilderFunction builder);
ConfigInstance register(ConfigHolder config, String configId, ConfigBuilder.ConfigBuilderFunction builder);
/**
* A sub-interface of DSL with a default ID and override methods using said ID.
* Passed to entrypoints, so they don't need to specify their ID in code manually.
*/
interface Defaulted extends DSL {
ConfigInstance config(ConfigBuilder.ConfigBuilderFunction builder);
ConfigInstance register(ConfigBuilder.ConfigBuilderFunction builder);

View File

@ -2,8 +2,11 @@ package io.gitlab.jfronny.libjf.config.api.v1.type;
import org.jetbrains.annotations.Nullable;
public sealed interface Type<T> {
static Type<?> ofClass(java.lang.reflect.Type klazz) {
/**
* An internal representation of types for the purpose of identifying field types
*/
public sealed interface Type {
static Type ofClass(java.lang.reflect.Type klazz) {
if (klazz == int.class || klazz == Integer.class) return TInt.INSTANCE;
else if (klazz == long.class || klazz == Long.class) return TLong.INSTANCE;
else if (klazz == float.class || klazz == Float.class) return TFloat.INSTANCE;
@ -40,7 +43,7 @@ public sealed interface Type<T> {
String getName();
final class TInt implements Type<Integer> {
final class TInt implements Type {
public static TInt INSTANCE = new TInt();
private TInt() {}
@Override
@ -59,7 +62,7 @@ public sealed interface Type<T> {
}
}
final class TLong implements Type<Long> {
final class TLong implements Type {
public static TLong INSTANCE = new TLong();
private TLong() {}
@Override
@ -78,7 +81,7 @@ public sealed interface Type<T> {
}
}
final class TFloat implements Type<Float> {
final class TFloat implements Type {
public static TFloat INSTANCE = new TFloat();
private TFloat() {}
@Override
@ -97,7 +100,7 @@ public sealed interface Type<T> {
}
}
final class TDouble implements Type<Double> {
final class TDouble implements Type {
public static TDouble INSTANCE = new TDouble();
private TDouble() {}
@Override
@ -116,7 +119,7 @@ public sealed interface Type<T> {
}
}
final class TString implements Type<String> {
final class TString implements Type {
public static TString INSTANCE = new TString();
private TString() {}
@Override
@ -135,7 +138,7 @@ public sealed interface Type<T> {
}
}
final class TBool implements Type<Boolean> {
final class TBool implements Type {
public static TBool INSTANCE = new TBool();
private TBool() {}
@Override
@ -154,7 +157,7 @@ public sealed interface Type<T> {
}
}
final record TEnum<T>(@Nullable Class<T> klazz, String name, T[] options) implements Type<T> {
final record TEnum<T>(@Nullable Class<T> klazz, String name, T[] options) implements Type {
public TEnum(Class<T> klazz) {
this(klazz, klazz.getSimpleName(), klazz.getEnumConstants());
}
@ -186,7 +189,7 @@ public sealed interface Type<T> {
}
}
final record TUnknown<T>(java.lang.reflect.Type klazz) implements Type<T> {
final record TUnknown<T>(java.lang.reflect.Type klazz) implements Type {
@Override
public @Nullable java.lang.reflect.Type asClass() {
return klazz;

View File

@ -141,7 +141,7 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
}
@Override
public <T> Builder value(String id, T def, double min, double max, Type<T> type, int width, Supplier<T> get, Consumer<T> set) {
public <T> Builder value(String id, T def, double min, double max, Type type, int width, Supplier<T> get, Consumer<T> set) {
checkBuilt();
entries.add(new DslEntryInfo<>(id, def, get::get, set::accept, type, width, min, max));
return asBuilder();

View File

@ -22,7 +22,7 @@ public class DslEntryInfo<T> implements EntryInfo<T> {
private final T defaultValue;
private final ThrowingSupplier<T, IllegalAccessException> get;
private final ThrowingConsumer<T, IllegalAccessException> set;
private final Type<T> type;
private final Type type;
private final int width;
private final double minValue;
private final double maxValue;
@ -31,7 +31,7 @@ public class DslEntryInfo<T> implements EntryInfo<T> {
T defaultValue,
ThrowingSupplier<T, IllegalAccessException> get,
ThrowingConsumer<T, IllegalAccessException> set,
Type<T> type,
Type type,
int width,
double minValue,
double maxValue) {
@ -49,7 +49,7 @@ public class DslEntryInfo<T> implements EntryInfo<T> {
T def,
ThrowingSupplier<T, IllegalAccessException> get,
ThrowingConsumer<T, IllegalAccessException> set,
Type<T> type) {
Type type) {
this(name, def, get, set, type, 100, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
}
@ -94,7 +94,7 @@ public class DslEntryInfo<T> implements EntryInfo<T> {
}
@Override
public Type<T> getValueType() {
public Type getValueType() {
return type;
}

View File

@ -34,7 +34,7 @@ public class EntryInfoWidgetBuilder {
}
private static <T> WidgetState<T> initEntry(ConfigCategory config, EntryInfo<T> info, List<WidgetState<?>> knownStates) {
Type<T> type = info.getValueType();
Type type = info.getValueType();
WidgetState<T> state = new WidgetState<>();
WidgetFactory factory;

View File

@ -1,6 +1,18 @@
package io.gitlab.jfronny.libjf.translate.api;
/**
* A language for use in TranslateService.translate
*/
public interface Language {
/**
* Returns the string to show in UIs for this language
* @return The display name
*/
String getDisplayName();
/**
* Returns the ID for internal use (like TranslateService.parseLang)
* @return The ID of this language
*/
String getIdentifier();
}

View File

@ -11,6 +11,10 @@ import java.net.*;
import java.util.*;
public interface TranslateService<T extends Language> {
/**
* Returns the TranslateService the user configured. Implementations may change without notice.
* @return configured translation service
*/
static TranslateService<?> getConfigured() {
return switch (TranslateConfig.translationService) {
case Noop -> NoopTranslateService.INSTANCE;
@ -33,6 +37,10 @@ public interface TranslateService<T extends Language> {
};
}
/**
* Returns all available TranslateServices. Please use getConfigured() instead where possible.
* @return available services
*/
static List<TranslateService<?>> getAvailable() {
List<TranslateService<?>> result = new LinkedList<>();
try {
@ -46,9 +54,40 @@ public interface TranslateService<T extends Language> {
return List.copyOf(result);
}
/**
* Translates a string from the specified source language (or null to auto-detect) to the target language.
* @param textToTranslate text to translate
* @param translateFrom language to translate from. Use parseLang("auto") to detect automatically.
* @param translateTo language to translate to. Use parseLang() to get a language by its ID
* @return translated text
* @throws TranslateException Something went wrong during the translation
*/
String translate(String textToTranslate, T translateFrom, T translateTo) throws TranslateException;
/**
* Detects the language used in the specified string. May return "auto" if detection is unavailable.
* @param text The text of which to detect the language
* @return detected language
* @throws TranslateException Something went wrong during the detection
*/
T detect(String text) throws TranslateException;
/**
* Gets the language for the specified ID
* @param lang the ID
* @return language for the specified ID or null
*/
T parseLang(String lang);
/**
* Get all available languages for the configured service.
* @return available languages
*/
List<T> getAvailableLanguages();
/**
* Get the name of this translate service.
* @return name
*/
String getName();
}

View File

@ -1,19 +0,0 @@
site_name: LibJF Docs
site_url: https://jfmods.gitlab.io/LibJF
theme:
name: readthedocs
site_dir: public
repo_url: https://gitlab.com/jfmods/LibJF
site_description: Documentation for the LibJF library
site_author: JFronny
nav:
- 'README.md'
- 'Modules':
- 'libjf-base.md'
- 'libjf-config-v0.md'
- 'libjf-devutil-v0.md'
- 'libjf-data-v0.md'
- 'libjf-data-manipulation-v0.md'
- 'libjf-translate-v1.md'
- 'libjf-unsafe-v0.md'
- 'libjf-web-v0.md'