Respackopts/src/main/java/io/gitlab/jfronny/respackopts/model/tree/ConfigBranch.java

225 lines
8.2 KiB
Java

package io.gitlab.jfronny.respackopts.model.tree;
import com.google.common.collect.ImmutableMap;
import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter;
import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken;
import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder;
import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder;
import io.gitlab.jfronny.muscript.data.additional.DFinal;
import io.gitlab.jfronny.muscript.data.additional.DelegateDynamic;
import io.gitlab.jfronny.muscript.data.additional.context.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
import io.gitlab.jfronny.respackopts.Respackopts;
import io.gitlab.jfronny.respackopts.RespackoptsConfig;
import io.gitlab.jfronny.respackopts.gson.entry.ConfigBranchSerializer;
import io.gitlab.jfronny.respackopts.integration.SaveHook;
import io.gitlab.jfronny.respackopts.model.enums.ConfigSyncMode;
import io.gitlab.jfronny.respackopts.model.enums.PackReloadType;
import io.gitlab.jfronny.respackopts.util.IndentingStringBuilder;
import io.gitlab.jfronny.respackopts.util.MetaCache;
import java.nio.file.Path;
import java.util.*;
@SerializeWithAdapter(adapter = ConfigBranchSerializer.class)
public class ConfigBranch extends ConfigEntry<Map<String, ConfigEntry<?>>> implements DelegateDynamic {
public ConfigBranch() {
super(new TypeToken<Map<String, ConfigEntry<?>>>(){}.getRawType());
setValue(new LinkedHashMap<>());
}
private void checkValue() {
if (version < 10) return;
for (Iterator<String> iterator = getValue().keySet().iterator(); iterator.hasNext(); ) {
String s = iterator.next();
if (!Respackopts.isLegal(s)) {
Respackopts.LOGGER.error("Illegal entry for " + getName() + ", skipping: " + s);
iterator.remove();
}
}
}
@Override
public Map<String, ConfigEntry<?>> setValue(Map<String, ConfigEntry<?>> value) {
var res = super.setValue(value);
checkValue();
return res;
}
@Override
public void sync(ConfigEntry<Map<String, ConfigEntry<?>>> source, ConfigSyncMode mode) {
for (Map.Entry<String, ConfigEntry<?>> e : source.getValue().entrySet()) {
if (!has(e.getKey())) {
if (mode == ConfigSyncMode.RESPACK_LOAD) {
add(e.getKey(), e.getValue().clone());
}
} else {
ConfigEntry<?> current = get(e.getKey());
if (e.getValue().getEntryClass().equals(current.getEntryClass())) {
syncSub(current, (ConfigEntry)e.getValue(), mode);
}
else {
if (mode == ConfigSyncMode.RESPACK_LOAD) {
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), overwriting");
add(e.getKey(), e.getValue().clone());
} else
Respackopts.LOGGER.warn("Type mismatch in config (" + getName() + "), ignoring");
}
}
}
if (mode == ConfigSyncMode.RESPACK_LOAD) {
getValue().forEach((key, value) -> {
if (!source.getValue().containsKey(key)) {
super.getValue().remove(key);
}
});
}
}
private <T> void syncSub(ConfigEntry<T> current, ConfigEntry<T> next, ConfigSyncMode mode) {
current.sync(next, mode);
}
public <T> void add(String name, ConfigEntry<T> val) {
if (version >= 10 && !Respackopts.isLegal(name)) {
Respackopts.LOGGER.error("Illegal entry for " + getName() + ", skipping: " + name);
return;
}
val.setVersion(version);
val.parent = this;
super.getValue().put(name, val);
}
public ConfigEntry<?> get(String key) {
return super.getValue().get(key);
}
public String getEntryName(ConfigEntry<?> entry) {
for (Map.Entry<String, ConfigEntry<?>> e : getValue().entrySet()) {
if (e.getValue() == entry) {
return e.getKey();
}
}
throw new IndexOutOfBoundsException();
}
public boolean has(String key) {
return super.getValue().containsKey(key);
}
@Override
public Map<String, ConfigEntry<?>> getValue() {
return ImmutableMap.copyOf(super.getValue());
}
@Override
public void buildShader(StringBuilder sb, String valueName) {
super.getValue().forEach((key, value) -> {
value.buildShader(sb, valueName + "_" + Respackopts.sanitizeString(key));
});
}
@Override
public Dynamic getDelegate() {
Map<String, ConfigEntry<?>> map = new HashMap<>();
super.getValue().forEach((key, value) -> {
if (Respackopts.isLegal(key)) map.put(key, value);
else if (version >= 10) {
Respackopts.LOGGER.error("Illegal key in " + getName() + ", skipping: " + key);
} else map.put(Respackopts.sanitizeString(key), value);
});
return DFinal.of(map);
}
public Scope addTo(Scope scope) {
super.getValue().forEach((key, value) -> {
scope.set(version >= 10 ? key : Respackopts.sanitizeString(key), value);
});
return scope;
}
@Override
public CategoryBuilder<?> buildEntry(GuiEntryBuilderParam builder) {
return builder.builder().category(builder.name(), cb -> {
getValue().forEach((key, value) -> {
value.buildEntry(new GuiEntryBuilderParam(cb, key, builder.onSave()));
});
return cb;
});
}
public <T extends ConfigBuilder<?>> T buildConfig(T builder, String packId, Path dataLocation) {
builder.setTranslationPrefix("rpo." + packId + ".");
PackReloadType.Aggregator agg = new PackReloadType.Aggregator();
getValue().forEach((key, value) -> {
value.buildEntry(
new GuiEntryBuilderParam(
builder,
key,
() -> agg.accept(value.getReloadType())
)
);
});
builder.executeAfterWrite(cfg -> {
if (RespackoptsConfig.debugLogs) Respackopts.LOGGER.info("GuiFactory SavingRunnable " + agg.get());
MetaCache.save(new SaveHook.Arguments(agg.get() == PackReloadType.Resource, false, true));
});
builder.setPath(dataLocation);
return builder;
}
@Override
public void appendString(IndentingStringBuilder sb) {
IndentingStringBuilder ind = sb.indent();
getValue().forEach((key, value) -> {
ind.line("- " + value.getName() + ":");
value.appendString(ind);
});
}
@Override
public ConfigBranch clone() {
ConfigBranch branch = new ConfigBranch();
getValue().forEach((key, value) -> {
ConfigEntry<?> entry = value.clone();
entry.setReloadType(value.getReloadType());
branch.add(key, entry);
});
branch.setVersion(getVersion());
return branch;
}
@Override
public void setVersion(int version) {
super.setVersion(version);
for (ConfigEntry<?> value : getValue().values()) {
value.setVersion(version);
}
checkValue();
}
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
if (!(o instanceof ConfigBranch other)) return false;
Map<String, ConfigEntry<?>> otherMap = other.getValue();
if (otherMap.size() != getValue().size()) return false;
for (Map.Entry<String, ConfigEntry<?>> entry : getValue().entrySet()) {
if (!otherMap.containsKey(entry.getKey())) return false;
if (!otherMap.get(entry.getKey()).equals(entry.getValue())) return false;
}
return true;
}
@Override
public int hashCode() {
List<Object> source = new ArrayList<>();
getValue().forEach((key, value) -> {
source.add(key);
source.add(value);
});
source.add(super.hashCode());
return Objects.hash(source.toArray());
}
}