8000 Rework plugin config system by DerEchtePilz · Pull Request #596 · CommandAPI/CommandAPI · GitHub
[go: up one dir, main page]

Skip to content

Rework plugin config system #596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d4bdade
Rework plugin config system
DerEchtePilz Aug 20, 2024
2c698f8
Use a loop instead of a Stream
DerEchtePilz Aug 21, 2024
9ca2efe
We want stacktraces
DerEchtePilz Aug 21, 2024
77029d2
Include generated config.yml in the documentation
DerEchtePilz Aug 23, 2024
6bdc2fd
Address code review
DerEchtePilz Sep 5, 2024
86b3f27
Use a LinkedHashMap for config options
DerEchtePilz Sep 5, 2024
3140b23
First iteration of an extendable and testable config system
DerEchtePilz Sep 7, 2024
78b1f7c
Update config system to be platform agnostic
DerEchtePilz Sep 15, 2024
a21e635
Clean up dependencies
DerEchtePilz Sep 15, 2024
a0bd0ef
Fix stuff
DerEchtePilz Sep 22, 2024
90fac61
Annotations
DerEchtePilz Sep 22, 2024
5b8886a
Fix Annotations
DerEchtePilz Sep 22, 2024
460a466
Fix more stuff
DerEchtePilz Sep 23, 2024
25b040e
Fix defaults in config.md
DerEchtePilz Sep 23, 2024
7d2ef1e
Simplify a thing
DerEchtePilz Sep 23, 2024
beeca43
Fix VelocityConfigurationAdapter#getKeys()
DerEchtePilz Sep 23, 2024
32b7eed
Don't update the Velocity config if not necessary
DerEchtePilz Sep 23, 2024
e1c35d7
Clean up Velocity plugin class
DerEchtePilz Sep 24, 2024
be6dfa3
Create static method to create a dummy instance
DerEchtePilz Sep 25, 2024
0e0d2d5
Remove Velocity config file
DerEchtePilz Sep 25, 2024
2698520
Introduce common modules to not include config classes in API modules
DerEchtePilz Sep 26, 2024
aa0d977
Remove unnecessary dependency
DerEchtePilz Sep 28, 2024
bff49cd
Move more common classes into the common module
DerEchtePilz Sep 28, 2024
677d545
Inline some stuff
DerEchtePilz Sep 28, 2024
f66e16c
Address code review
DerEchtePilz Oct 7, 2024
392d77f
More code review
DerEchtePilz Oct 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update config system to be platform agnostic
  • Loading branch information
DerEchtePilz committed Oct 3, 2024
commit 78b1f7c29bdc6034cd165eacb629dabc17e27e9f
8 changes: 8 additions & 0 deletions commandapi-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,20 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

<!-- Other dependencies -->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<version>4.1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>


Expand Down
8000
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package dev.jorel.commandapi.config;

import org.jetbrains.annotations.ApiStatus;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

@ApiStatus.Internal
public class ConfigGenerator {

private final DefaultedConfig defaultedConfig;

private ConfigGenerator(DefaultedConfig defaultedConfig) {
this.defaultedConfig = defaultedConfig;
}

public static ConfigGenerator createNew(DefaultedConfig defaultedConfig) {
return new ConfigGenerator(defaultedConfig);
}

public <T, C extends DefaultedConfig> void populateDefaultConfig(ConfigurationAdapter<T, C> adapter) {
for (Map.Entry<String, CommentedConfigOption<?>> commentedConfigOption : defaultedConfig.getAllOptions().entrySet()) {
adapter.setValue(commentedConfigOption.getKey(), commentedConfigOption.getValue().option());
adapter.setComment(commentedConfigOption.getKey(), commentedConfigOption.getValue().comment().toArray(new String[0]));
}
}

@SuppressWarnings("unchecked")
public <T, C extends DefaultedConfig> ConfigurationAdapter<T, C> generateWithNewValues(ConfigurationAdapter<T, C> existingConfig) {
ConfigurationAdapter<T, C> updatedConfig = existingConfig.createNew();

boolean shouldRemoveValues = shouldRemoveOptions(existingConfig);

boolean wasConfigUpdated = false;
for (Map.Entry<String, CommentedConfigOption<?>> commentedConfigOption : defaultedConfig.getAllOptions().entrySet()) {
String path = commentedConfigOption.getKey();

// Update config option
if (existingConfig.contains(path)) {
updatedConfig.tryCreateSection(path, (C) defaultedConfig);
updatedConfig.setValue(path, existingConfig.getValue(path));
} else {
wasConfigUpdated = true;
updatedConfig.tryCreateSection(path, (C) defaultedConfig);
updatedConfig.setValue(path, commentedConfigOption.getValue().option());
}

// Update config option comment
String[] defaultComment = commentedConfigOption.getValue().comment().toArray(new String[0]);
String[] configComment = existingConfig.getComment(path);

if (!Arrays.equals(defaultComment, configComment)) {
wasConfigUpdated = true;
}

updatedConfig.setComment(path, commentedConfigOption.getValue().comment().toArray(new String[0]));
}
if (shouldRemoveValues) {
wasConfigUpdated = true;
}
return (wasConfigUpdated) ? updatedConfig : null;
}

private <T, C extends DefaultedConfig> boolean shouldRemoveOptions(ConfigurationAdapter<T, C> config) {
Set<String> configOptions = config.getKeys();
Set<String> defaultConfigOptions = defaultedConfig.getAllOptions().keySet();

boolean shouldRemoveOptions = false;
for (String option : configOptions) {
if (!defaultConfigOptions.contains(option)) {
shouldRemoveOptions = true;
break;
}
}
return shouldRemoveOptions;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.jorel.commandapi.config;

import org.jetbrains.annotations.ApiStatus;

import java.util.Set;

@ApiStatus.Internal
public interface ConfigurationAdapter<Configuration, DefaultConfiguration extends DefaultedConfig> {

void setValue(String key, Object value);

void setComment(String key, String[] comment);

Object getValue(String key);

String[] getComment(String key);

Set<String> getKeys();

boolean contains(String key);

void tryCreateSection(String key, DefaultConfiguration defaultConfiguration);

Configuration config();

ConfigurationAdapter<Configuration, DefaultConfiguration> createNew();

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
@ApiStatus.Internal
public abstract class DefaultedConfig {

final Map<String, CommentedConfigOption<?>> allOptions = new LinkedHashMap<>();
final Map<String, CommentedSection> allSections = new LinkedHashMap<>();
protected final Map<String, CommentedConfigOption<?>> allOptions = new LinkedHashMap<>();
protected final Map<String, CommentedSection> allSections = new LinkedHashMap<>();

public static final CommentedConfigOption<Boolean> VERBOSE_OUTPUTS = new CommentedConfigOption<>(
List.of(
Expand Down Expand Up @@ -46,4 +46,19 @@ public abstract class DefaultedConfig {
), false
);

public static final CommentedSection SECTION_MESSAGE = new CommentedSection(
List.of(
"Messages",
"Controls messages that the CommandAPI displays to players"
)
);

public final Map<String, CommentedConfigOption<?>> getAllOptions() {
return allOptions;
}

public final Map<String, CommentedSection> getAllSections() {
return allSections;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package dev.jorel.commandapi.config;

import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.ApiStatus;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@ApiStatus.Internal
public record BukkitConfigurationAdapter(YamlConfiguration config) implements ConfigurationAdapter<YamlConfiguration, DefaultedBukkitConfig> {

@Override
public void setValue(String key, Object value) {
config.set(key, value);
}

@Override
public void setComment(String key, String[] comment) {
config.setComments(key, Arrays.asList(comment));
}

@Override
public Object getValue(String key) {
return config.get(key);
}

@Override
public String[] getComment(String key) {
List<String> comments = config.getStringList(key);
comments.removeIf(Objects::isNull);
return comments.toArray(new String[0]);
}

@Override
public Set<String> getKeys() {
return config.getKeys(false);
}

@Override
public boolean contains(String key) {
return config.contains(key);
}

@Override
public void tryCreateSection(String key, DefaultedBukkitConfig defaultedBukkitConfig) {
if (!key.contains(".")) {
return;
}

// Collect config keys
Set<String> keys = getKeys();
keys.removeIf(k -> !config.isConfigurationSection(k));

// Collect sections
String[] paths = key.split("\\.");
List<String> sectionCandidates = new ArrayList<>(Arrays.asList(paths).subList(0, paths.length - 1));

// Create new sections
ConfigurationSection root = null;
StringBuilder pathSoFar = new StringBuilder();
for (String sectionCandidate : sectionCandidates) {
if (pathSoFar.isEmpty()) {
pathSoFar.append(sectionCandidate);
} else {
pathSoFar.append(".").append(sectionCandidate);
}
if (keys.contains(sectionCandidate) && root == null) {
root = config.getConfigurationSection(sectionCandidate);
} else if (root == null) {
root = config.createSection(sectionCandidate);
root.setComments(sectionCandidate, defaultedBukkitConfig.getAllSections().get(pathSoFar.toString()).comment());
} else {
ConfigurationSection section = root.getConfigurationSection(sectionCandidate);
if (section == null) {
root = root.createSection(sectionCandidate);
root.setComments(sectionCandidate, defaultedBukkitConfig.getAllSections().get(pathSoFar.toString()).comment());
} else {
root = section;
}
}
}
}

@Override
public ConfigurationAdapter<YamlConfiguration, DefaultedBukkitConfig> createNew() {
return new BukkitConfigurationAdapter(new YamlConfiguration());
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BukkitConfigurationAdapter that = (BukkitConfigurationAdapter) o;
String thisConfigString = config.saveToString();
String thatConfigString = that.config.saveToString();
return thisConfigString.equals(thatConfigString);
}

}
Loading
0