2021-03-22 23:06:40 +01:00
|
|
|
/*
|
|
|
|
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
|
2022-01-09 22:36:07 +01:00
|
|
|
* Copyright (C) 2016-2022 ViaVersion and contributors
|
2021-03-22 23:06:40 +01:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2021-04-26 20:52:34 +02:00
|
|
|
package com.viaversion.viaversion.util;
|
2016-09-30 01:34:16 +02:00
|
|
|
|
2021-06-21 14:55:49 +02:00
|
|
|
import com.google.gson.JsonElement;
|
2022-06-28 11:22:42 +02:00
|
|
|
import com.viaversion.viaversion.api.Via;
|
2021-04-27 13:41:39 +02:00
|
|
|
import com.viaversion.viaversion.api.configuration.ConfigurationProvider;
|
2021-06-21 14:55:49 +02:00
|
|
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
|
|
|
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
2021-04-02 14:15:30 +02:00
|
|
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
2016-10-02 20:40:38 +02:00
|
|
|
import org.yaml.snakeyaml.DumperOptions;
|
2016-09-30 01:34:16 +02:00
|
|
|
import org.yaml.snakeyaml.Yaml;
|
2016-10-02 21:50:34 +02:00
|
|
|
import org.yaml.snakeyaml.representer.Representer;
|
2016-09-30 01:34:16 +02:00
|
|
|
|
2022-06-28 11:22:42 +02:00
|
|
|
import java.io.*;
|
2016-09-30 01:34:16 +02:00
|
|
|
import java.net.URL;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2016-10-02 21:50:34 +02:00
|
|
|
import java.util.concurrent.ConcurrentSkipListMap;
|
2016-09-30 01:34:16 +02:00
|
|
|
|
|
|
|
public abstract class Config implements ConfigurationProvider {
|
2019-08-23 22:13:37 +02:00
|
|
|
private static final ThreadLocal<Yaml> YAML = ThreadLocal.withInitial(() -> {
|
|
|
|
DumperOptions options = new DumperOptions();
|
|
|
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
|
|
|
options.setPrettyFlow(false);
|
|
|
|
options.setIndent(2);
|
|
|
|
return new Yaml(new YamlConstructor(), new Representer(), options);
|
|
|
|
});
|
2017-07-31 16:24:25 +02:00
|
|
|
|
2019-08-23 22:13:37 +02:00
|
|
|
private final CommentStore commentStore = new CommentStore('.', 2);
|
2016-09-30 01:34:16 +02:00
|
|
|
private final File configFile;
|
2019-11-22 22:00:41 +01:00
|
|
|
private Map<String, Object> config;
|
2016-09-30 01:34:16 +02:00
|
|
|
|
2017-09-11 14:10:54 +02:00
|
|
|
/**
|
|
|
|
* Create a new Config instance, this will *not* load the config by default.
|
|
|
|
* To load config see {@link #reloadConfig()}
|
|
|
|
*
|
|
|
|
* @param configFile The location of where the config is loaded/saved.
|
|
|
|
*/
|
2016-09-30 01:34:16 +02:00
|
|
|
public Config(File configFile) {
|
|
|
|
this.configFile = configFile;
|
|
|
|
}
|
|
|
|
|
2022-01-09 18:30:51 +01:00
|
|
|
public URL getDefaultConfigURL() {
|
|
|
|
return getClass().getClassLoader().getResource("assets/viaversion/config.yml");
|
|
|
|
}
|
2017-09-11 14:10:54 +02:00
|
|
|
|
2016-11-14 19:46:27 +01:00
|
|
|
public synchronized Map<String, Object> loadConfig(File location) {
|
2016-09-30 01:34:16 +02:00
|
|
|
List<String> unsupported = getUnsupportedOptions();
|
2017-09-11 14:10:54 +02:00
|
|
|
URL jarConfigFile = getDefaultConfigURL();
|
2016-09-30 01:34:16 +02:00
|
|
|
try {
|
|
|
|
commentStore.storeComments(jarConfigFile.openStream());
|
|
|
|
for (String option : unsupported) {
|
|
|
|
List<String> comments = commentStore.header(option);
|
|
|
|
if (comments != null) {
|
|
|
|
comments.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
Map<String, Object> config = null;
|
|
|
|
if (location.exists()) {
|
|
|
|
try (FileInputStream input = new FileInputStream(location)) {
|
2018-09-30 20:48:23 +02:00
|
|
|
config = (Map<String, Object>) YAML.get().load(input);
|
2016-09-30 01:34:16 +02:00
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (config == null) {
|
|
|
|
config = new HashMap<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, Object> defaults = config;
|
|
|
|
try (InputStream stream = jarConfigFile.openStream()) {
|
2018-09-30 20:48:23 +02:00
|
|
|
defaults = (Map<String, Object>) YAML.get().load(stream);
|
2016-09-30 01:34:16 +02:00
|
|
|
for (String option : unsupported) {
|
|
|
|
defaults.remove(option);
|
|
|
|
}
|
|
|
|
// Merge with defaultLoader
|
2019-05-27 18:50:08 +02:00
|
|
|
for (Map.Entry<String, Object> entry : config.entrySet()) {
|
2016-09-30 01:34:16 +02:00
|
|
|
// Set option in new conf if exists
|
2019-05-27 18:50:08 +02:00
|
|
|
if (defaults.containsKey(entry.getKey()) && !unsupported.contains(entry.getKey())) {
|
|
|
|
defaults.put(entry.getKey(), entry.getValue());
|
2016-09-30 01:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2016-10-02 20:40:38 +02:00
|
|
|
// Call Handler
|
|
|
|
handleConfig(defaults);
|
2016-09-30 01:34:16 +02:00
|
|
|
// Save
|
|
|
|
saveConfig(location, defaults);
|
|
|
|
|
|
|
|
return defaults;
|
|
|
|
}
|
|
|
|
|
2016-10-02 20:40:38 +02:00
|
|
|
protected abstract void handleConfig(Map<String, Object> config);
|
|
|
|
|
2016-11-14 19:46:27 +01:00
|
|
|
public synchronized void saveConfig(File location, Map<String, Object> config) {
|
2016-09-30 01:34:16 +02:00
|
|
|
try {
|
2018-09-30 20:48:23 +02:00
|
|
|
commentStore.writeComments(YAML.get().dump(config), location);
|
2016-09-30 01:34:16 +02:00
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public abstract List<String> getUnsupportedOptions();
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void set(String path, Object value) {
|
2016-10-02 12:03:56 +02:00
|
|
|
config.put(path, value);
|
2016-09-30 01:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void saveConfig() {
|
|
|
|
this.configFile.getParentFile().mkdirs();
|
|
|
|
saveConfig(this.configFile, this.config);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void reloadConfig() {
|
|
|
|
this.configFile.getParentFile().mkdirs();
|
2016-10-02 21:50:34 +02:00
|
|
|
this.config = new ConcurrentSkipListMap<>(loadConfig(this.configFile));
|
2016-09-30 01:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Map<String, Object> getValues() {
|
|
|
|
return this.config;
|
|
|
|
}
|
|
|
|
|
2021-04-02 14:15:30 +02:00
|
|
|
public @Nullable <T> T get(String key, Class<T> clazz, T def) {
|
2018-09-30 20:48:23 +02:00
|
|
|
Object o = this.config.get(key);
|
|
|
|
if (o != null) {
|
|
|
|
return (T) o;
|
2016-10-02 20:40:38 +02:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-30 01:34:16 +02:00
|
|
|
public boolean getBoolean(String key, boolean def) {
|
2018-09-30 20:48:23 +02:00
|
|
|
Object o = this.config.get(key);
|
|
|
|
if (o != null) {
|
|
|
|
return (boolean) o;
|
2016-09-30 01:34:16 +02:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-02 14:15:30 +02:00
|
|
|
public @Nullable String getString(String key, @Nullable String def) {
|
2018-09-30 20:48:23 +02:00
|
|
|
final Object o = this.config.get(key);
|
|
|
|
if (o != null) {
|
|
|
|
return (String) o;
|
2016-09-30 01:34:16 +02:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getInt(String key, int def) {
|
2018-09-30 20:48:23 +02:00
|
|
|
Object o = this.config.get(key);
|
|
|
|
if (o != null) {
|
|
|
|
if (o instanceof Number) {
|
|
|
|
return ((Number) o).intValue();
|
2016-11-14 19:29:45 +01:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
2016-09-30 01:34:16 +02:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public double getDouble(String key, double def) {
|
2018-09-30 20:48:23 +02:00
|
|
|
Object o = this.config.get(key);
|
|
|
|
if (o != null) {
|
|
|
|
if (o instanceof Number) {
|
|
|
|
return ((Number) o).doubleValue();
|
2016-11-14 19:29:45 +01:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
2016-09-30 01:34:16 +02:00
|
|
|
} else {
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Integer> getIntegerList(String key) {
|
2018-09-30 20:48:23 +02:00
|
|
|
Object o = this.config.get(key);
|
2021-09-20 15:15:25 +02:00
|
|
|
return o != null ? (List<Integer>) o : new ArrayList<>();
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<String> getStringList(String key) {
|
|
|
|
Object o = this.config.get(key);
|
|
|
|
return o != null ? (List<String>) o : new ArrayList<>();
|
2016-09-30 01:34:16 +02:00
|
|
|
}
|
2021-06-21 14:55:49 +02:00
|
|
|
|
2022-06-28 11:22:42 +02:00
|
|
|
public <T> List<T> getListSafe(String key, Class<T> type, String invalidValueMessage) {
|
|
|
|
Object o = this.config.get(key);
|
|
|
|
if (o instanceof List) {
|
|
|
|
List<?> list = (List<?>) o;
|
|
|
|
List<T> filteredValues = new ArrayList<>();
|
|
|
|
for (Object o1 : list) {
|
|
|
|
if (type.isInstance(o1)) {
|
|
|
|
filteredValues.add(type.cast(o1));
|
|
|
|
} else if (invalidValueMessage != null) {
|
|
|
|
Via.getPlatform().getLogger().warning(String.format(invalidValueMessage, o1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return filteredValues;
|
|
|
|
}
|
|
|
|
return new ArrayList<>();
|
|
|
|
}
|
|
|
|
|
2021-06-21 14:55:49 +02:00
|
|
|
public @Nullable JsonElement getSerializedComponent(String key) {
|
|
|
|
final Object o = this.config.get(key);
|
|
|
|
if (o != null && !((String) o).isEmpty()) {
|
|
|
|
return GsonComponentSerializer.gson().serializeToTree(LegacyComponentSerializer.legacySection().deserialize((String) o));
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2016-09-30 01:34:16 +02:00
|
|
|
}
|