Config.java 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package me.lortseam.completeconfig.data;
  2. import lombok.EqualsAndHashCode;
  3. import lombok.Getter;
  4. import lombok.NonNull;
  5. import lombok.ToString;
  6. import lombok.extern.log4j.Log4j2;
  7. import me.lortseam.completeconfig.CompleteConfig;
  8. import me.lortseam.completeconfig.api.ConfigContainer;
  9. import me.lortseam.completeconfig.extension.BaseExtension;
  10. import me.lortseam.completeconfig.text.TranslationKey;
  11. import net.fabricmc.api.EnvType;
  12. import net.fabricmc.api.Environment;
  13. import net.fabricmc.loader.api.FabricLoader;
  14. import net.fabricmc.loader.api.metadata.ModMetadata;
  15. import org.apache.commons.lang3.ArrayUtils;
  16. import org.spongepowered.configurate.CommentedConfigurationNode;
  17. import org.spongepowered.configurate.ConfigurateException;
  18. import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
  19. import org.spongepowered.configurate.serialize.TypeSerializerCollection;
  20. import java.nio.file.Path;
  21. import java.util.Arrays;
  22. import java.util.Objects;
  23. /**
  24. * The base config class. Instantiate or inherit this class to create a config for your mod.
  25. */
  26. @Log4j2(topic = "CompleteConfig")
  27. @EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
  28. @ToString(onlyExplicitlyIncluded = true)
  29. public class Config extends BaseCollection {
  30. @EqualsAndHashCode.Include
  31. @ToString.Include
  32. @Getter
  33. private final String modId;
  34. @EqualsAndHashCode.Include
  35. @ToString.Include
  36. @Getter
  37. private final String[] branch;
  38. private final HoconConfigurationLoader loader;
  39. private Runnable resolver;
  40. @Environment(EnvType.CLIENT)
  41. private TranslationKey translation;
  42. /**
  43. * Creates a config with the specified branch.
  44. *
  45. * <p>The branch determines the location of the config's save file and has to be mod-unique.
  46. *
  47. * @param modId the ID of the mod creating the config
  48. * @param branch the branch
  49. */
  50. public Config(@NonNull String modId, @NonNull String[] branch, @NonNull ConfigContainer... containers) {
  51. if (!FabricLoader.getInstance().isModLoaded(modId)) {
  52. throw new IllegalArgumentException("Mod " + modId + " is not loaded");
  53. }
  54. Arrays.stream(branch).forEach(Objects::requireNonNull);
  55. Arrays.stream(containers).forEach(Objects::requireNonNull);
  56. this.modId = modId;
  57. this.branch = branch;
  58. Path path = FabricLoader.getInstance().getConfigDir();
  59. String[] subPath = ArrayUtils.add(branch, 0, modId);
  60. subPath[subPath.length - 1] = subPath[subPath.length - 1] + ".conf";
  61. for (String child : subPath) {
  62. path = path.resolve(child);
  63. }
  64. loader = HoconConfigurationLoader.builder()
  65. .path(path)
  66. .defaultOptions(options -> options.serializers(builder -> {
  67. for (TypeSerializerCollection typeSerializers : CompleteConfig.collectExtensions(BaseExtension.class, BaseExtension::getTypeSerializers)) {
  68. builder.registerAll(typeSerializers);
  69. }
  70. }))
  71. .build();
  72. resolver = () -> {
  73. if (this instanceof ConfigContainer) {
  74. resolve((ConfigContainer) this);
  75. }
  76. resolve(containers);
  77. if (isEmpty()) {
  78. logger.warn(this + " is empty");
  79. }
  80. };
  81. ConfigRegistry.register(this);
  82. }
  83. /**
  84. * Creates a config with the default branch.
  85. *
  86. * @param modId the ID of the mod creating the config
  87. */
  88. public Config(String modId, ConfigContainer... containers) {
  89. this(modId, new String[0], containers);
  90. }
  91. public final ModMetadata getMod() {
  92. return FabricLoader.getInstance().getModContainer(modId).get().getMetadata();
  93. }
  94. @Override
  95. public final TranslationKey getTranslation() {
  96. return getTranslation(false);
  97. }
  98. @Environment(EnvType.CLIENT)
  99. public final TranslationKey getTranslation(boolean includeBranch) {
  100. if (translation == null) {
  101. translation = TranslationKey.from(this);
  102. }
  103. if (includeBranch) {
  104. return translation.append(branch);
  105. }
  106. return translation;
  107. }
  108. /**
  109. * Loads the config.
  110. *
  111. * <p>On first load, this also resolves the config's children.
  112. */
  113. public final void load() {
  114. if (resolver != null) {
  115. resolver.run();
  116. resolver = null;
  117. }
  118. if (isEmpty()) return;
  119. try {
  120. CommentedConfigurationNode root = loader.load();
  121. if (!root.isNull()) {
  122. apply(root);
  123. }
  124. } catch (ConfigurateException e) {
  125. logger.error("Failed to load config from file", e);
  126. }
  127. save();
  128. }
  129. /**
  130. * Saves the config.
  131. */
  132. public final void save() {
  133. if (resolver != null) {
  134. throw new IllegalStateException("Cannot save config before it was loaded");
  135. }
  136. if (isEmpty()) return;
  137. CommentedConfigurationNode root = loader.createNode();
  138. fetch(root);
  139. try {
  140. loader.save(root);
  141. } catch (ConfigurateException e) {
  142. logger.error("Failed to save config to file", e);
  143. }
  144. }
  145. }