ClothConfigInitializer.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. package me.shedaniel.clothconfig2;
  2. import com.google.common.collect.ImmutableList;
  3. import me.shedaniel.clothconfig2.api.*;
  4. import me.shedaniel.clothconfig2.gui.entries.DoubleListEntry;
  5. import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry;
  6. import me.shedaniel.clothconfig2.gui.entries.LongSliderEntry;
  7. import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
  8. import me.shedaniel.clothconfig2.impl.EasingMethod;
  9. import me.shedaniel.clothconfig2.impl.EasingMethod.EasingMethodImpl;
  10. import me.shedaniel.clothconfig2.impl.EasingMethods;
  11. import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
  12. import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
  13. import net.fabricmc.api.ClientModInitializer;
  14. import net.fabricmc.api.EnvType;
  15. import net.fabricmc.api.Environment;
  16. import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl;
  17. import net.fabricmc.loader.api.FabricLoader;
  18. import net.minecraft.client.MinecraftClient;
  19. import net.minecraft.client.gui.Element;
  20. import net.minecraft.client.gui.widget.AbstractButtonWidget;
  21. import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
  22. import net.minecraft.client.util.InputUtil;
  23. import net.minecraft.client.util.Window;
  24. import net.minecraft.client.util.math.MatrixStack;
  25. import net.minecraft.item.Item;
  26. import net.minecraft.item.Items;
  27. import net.minecraft.text.LiteralText;
  28. import net.minecraft.text.TranslatableText;
  29. import net.minecraft.util.Identifier;
  30. import net.minecraft.util.registry.Registry;
  31. import org.apache.logging.log4j.LogManager;
  32. import org.apache.logging.log4j.Logger;
  33. import org.jetbrains.annotations.ApiStatus;
  34. import java.io.File;
  35. import java.io.FileInputStream;
  36. import java.io.FileWriter;
  37. import java.lang.reflect.Method;
  38. import java.nio.file.Files;
  39. import java.util.*;
  40. import java.util.stream.Collectors;
  41. @Environment(EnvType.CLIENT)
  42. public class ClothConfigInitializer implements ClientModInitializer {
  43. public static final Logger LOGGER = LogManager.getFormatterLogger("ClothConfig");
  44. private static EasingMethod easingMethod = EasingMethodImpl.LINEAR;
  45. private static long scrollDuration = 600;
  46. private static double scrollStep = 19;
  47. private static double bounceBackMultiplier = .24;
  48. @Deprecated
  49. @ApiStatus.ScheduledForRemoval
  50. public static double handleScrollingPosition(double[] target, double scroll, double maxScroll, float delta, double start, double duration) {
  51. return ScrollingContainer.handleScrollingPosition(target, scroll, maxScroll, delta, start, duration);
  52. }
  53. @Deprecated
  54. @ApiStatus.ScheduledForRemoval
  55. public static double expoEase(double start, double end, double amount) {
  56. return ScrollingContainer.ease(start, end, amount, getEasingMethod());
  57. }
  58. @Deprecated
  59. @ApiStatus.ScheduledForRemoval
  60. public static double clamp(double v, double maxScroll) {
  61. return ScrollingContainer.clampExtension(v, maxScroll);
  62. }
  63. @Deprecated
  64. @ApiStatus.ScheduledForRemoval
  65. public static double clamp(double v, double maxScroll, double clampExtension) {
  66. return ScrollingContainer.clampExtension(v, -clampExtension, maxScroll + clampExtension);
  67. }
  68. public static EasingMethod getEasingMethod() {
  69. return easingMethod;
  70. }
  71. public static long getScrollDuration() {
  72. return scrollDuration;
  73. }
  74. public static double getScrollStep() {
  75. return scrollStep;
  76. }
  77. public static double getBounceBackMultiplier() {
  78. return bounceBackMultiplier;
  79. }
  80. private static void loadConfig() {
  81. File file = new File(FabricLoader.getInstance().getConfigDirectory(), "cloth-config2/config.properties");
  82. try {
  83. file.getParentFile().mkdirs();
  84. easingMethod = EasingMethodImpl.LINEAR;
  85. scrollDuration = 600;
  86. scrollStep = 19;
  87. bounceBackMultiplier = .24;
  88. if (!file.exists()) {
  89. saveConfig();
  90. }
  91. Properties properties = new Properties();
  92. properties.load(new FileInputStream(file));
  93. String easing = properties.getProperty("easingMethod1", "LINEAR");
  94. for (EasingMethod value : EasingMethods.getMethods()) {
  95. if (value.toString().equalsIgnoreCase(easing)) {
  96. easingMethod = value;
  97. break;
  98. }
  99. }
  100. scrollDuration = Long.parseLong(properties.getProperty("scrollDuration1", "600"));
  101. scrollStep = Double.parseDouble(properties.getProperty("scrollStep1", "19"));
  102. bounceBackMultiplier = Double.parseDouble(properties.getProperty("bounceBackMultiplier2", "0.24"));
  103. } catch (Exception e) {
  104. e.printStackTrace();
  105. easingMethod = EasingMethodImpl.LINEAR;
  106. scrollDuration = 600;
  107. scrollStep = 19;
  108. bounceBackMultiplier = .24;
  109. try {
  110. Files.deleteIfExists(file.toPath());
  111. } catch (Exception ignored) {
  112. }
  113. }
  114. saveConfig();
  115. }
  116. private static void saveConfig() {
  117. File file = new File(FabricLoader.getInstance().getConfigDirectory(), "cloth-config2/config.properties");
  118. try {
  119. FileWriter writer = new FileWriter(file, false);
  120. Properties properties = new Properties();
  121. properties.setProperty("easingMethod1", easingMethod.toString());
  122. properties.setProperty("scrollDuration1", scrollDuration + "");
  123. properties.setProperty("scrollStep1", scrollStep + "");
  124. properties.setProperty("bounceBackMultiplier2", bounceBackMultiplier + "");
  125. properties.store(writer, null);
  126. writer.close();
  127. } catch (Exception e) {
  128. e.printStackTrace();
  129. easingMethod = EasingMethodImpl.LINEAR;
  130. scrollDuration = 600;
  131. scrollStep = 19;
  132. bounceBackMultiplier = .24;
  133. }
  134. }
  135. @Override
  136. public void onInitializeClient() {
  137. loadConfig();
  138. if (FabricLoader.getInstance().isModLoaded("modmenu")) {
  139. try {
  140. Class<?> clazz = Class.forName("io.github.prospector.modmenu.api.ModMenuApi");
  141. Method method = clazz.getMethod("addConfigOverride", String.class, Runnable.class);
  142. method.invoke(null, "cloth-config2", (Runnable) () -> {
  143. try {
  144. MinecraftClient.getInstance().openScreen(getConfigBuilderWithDemo().build());
  145. } catch (Throwable throwable) {
  146. throwable.printStackTrace();
  147. }
  148. });
  149. } catch (Exception e) {
  150. ClothConfigInitializer.LOGGER.error("[ClothConfig] Failed to add test config override for ModMenu!", e);
  151. }
  152. }
  153. if (FabricLoader.getInstance().isDevelopmentEnvironment()) {
  154. try {
  155. KeyBindingRegistryImpl.INSTANCE.addCategory("Cloth Test Keybinds");
  156. FakeModifierKeyCodeAdder.INSTANCE.registerModifierKeyCode("Cloth Test Keybinds", "Keybind 1",
  157. ModifierKeyCode::unknown, ModifierKeyCode::unknown, System.out::println);
  158. } catch (Throwable throwable) {
  159. throwable.printStackTrace();
  160. }
  161. }
  162. }
  163. @SuppressWarnings("deprecation")
  164. public static ConfigBuilder getConfigBuilder() {
  165. ConfigBuilder builder = ConfigBuilder.create().setParentScreen(MinecraftClient.getInstance().currentScreen).setTitle(new TranslatableText("title.cloth-config.config"));
  166. builder.setDefaultBackgroundTexture(new Identifier("minecraft:textures/block/oak_planks.png"));
  167. ConfigCategory scrolling = builder.getOrCreateCategory(new TranslatableText("category.cloth-config.scrolling"));
  168. ConfigEntryBuilder entryBuilder = ConfigEntryBuilder.create();
  169. DropdownBoxEntry<EasingMethod> easingMethodEntry = entryBuilder.startDropdownMenu(new LiteralText("Easing Method"), DropdownMenuBuilder.TopCellElementBuilder.of(easingMethod, str -> {
  170. for (EasingMethod m : EasingMethods.getMethods())
  171. if (m.toString().equals(str))
  172. return m;
  173. return null;
  174. })).setDefaultValue(EasingMethodImpl.LINEAR).setSaveConsumer(o -> easingMethod = o).setSelections(EasingMethods.getMethods()).build();
  175. LongSliderEntry scrollDurationEntry = entryBuilder.startLongSlider(new TranslatableText("option.cloth-config.scrollDuration"), scrollDuration, 0, 5000).setTextGetter(integer -> new LiteralText(integer <= 0 ? "Value: Disabled" : (integer > 1500 ? String.format("Value: %.1fs", integer / 1000f) : "Value: " + integer + "ms"))).setDefaultValue(600).setSaveConsumer(i -> scrollDuration = i).build();
  176. DoubleListEntry scrollStepEntry = entryBuilder.startDoubleField(new TranslatableText("option.cloth-config.scrollStep"), scrollStep).setDefaultValue(19).setSaveConsumer(i -> scrollStep = i).build();
  177. LongSliderEntry bounceMultiplierEntry = entryBuilder.startLongSlider(new TranslatableText("option.cloth-config.bounceBackMultiplier"), (long) (bounceBackMultiplier * 1000), -10, 750).setTextGetter(integer -> new LiteralText(integer < 0 ? "Value: Disabled" : String.format("Value: %s", integer / 1000d))).setDefaultValue(240).setSaveConsumer(i -> bounceBackMultiplier = i / 1000d).build();
  178. scrolling.addEntry(new TooltipListEntry<Object>(new TranslatableText("option.cloth-config.setDefaultSmoothScroll"), null) {
  179. final int width = 220;
  180. private final AbstractButtonWidget buttonWidget = new AbstractPressableButtonWidget(0, 0, 0, 20, getFieldName()) {
  181. @Override
  182. public void onPress() {
  183. easingMethodEntry.getSelectionElement().getTopRenderer().setValue(EasingMethodImpl.LINEAR);
  184. scrollDurationEntry.setValue(600);
  185. scrollStepEntry.setValue("19.0");
  186. bounceMultiplierEntry.setValue(240);
  187. getScreen().setEdited(true, isRequiresRestart());
  188. }
  189. };
  190. private final List<AbstractButtonWidget> children = ImmutableList.of(buttonWidget);
  191. @Override
  192. public Object getValue() {
  193. return null;
  194. }
  195. @Override
  196. public Optional<Object> getDefaultValue() {
  197. return Optional.empty();
  198. }
  199. @Override
  200. public void save() {
  201. }
  202. @Override
  203. public List<? extends Element> children() {
  204. return children;
  205. }
  206. @Override
  207. public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
  208. super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
  209. Window window = MinecraftClient.getInstance().getWindow();
  210. this.buttonWidget.active = this.isEditable();
  211. this.buttonWidget.y = y;
  212. this.buttonWidget.x = x + entryWidth / 2 - width / 2;
  213. this.buttonWidget.setWidth(width);
  214. this.buttonWidget.render(matrices, mouseX, mouseY, delta);
  215. }
  216. });
  217. scrolling.addEntry(new TooltipListEntry<Object>(new TranslatableText("option.cloth-config.disableSmoothScroll"), null) {
  218. final int width = 220;
  219. private final AbstractButtonWidget buttonWidget = new AbstractPressableButtonWidget(0, 0, 0, 20, getFieldName()) {
  220. @Override
  221. public void onPress() {
  222. easingMethodEntry.getSelectionElement().getTopRenderer().setValue(EasingMethodImpl.NONE);
  223. scrollDurationEntry.setValue(0);
  224. scrollStepEntry.setValue("16.0");
  225. bounceMultiplierEntry.setValue(-10);
  226. getScreen().setEdited(true, isRequiresRestart());
  227. }
  228. };
  229. private final List<AbstractButtonWidget> children = ImmutableList.of(buttonWidget);
  230. @Override
  231. public Object getValue() {
  232. return null;
  233. }
  234. @Override
  235. public Optional<Object> getDefaultValue() {
  236. return Optional.empty();
  237. }
  238. @Override
  239. public void save() {
  240. }
  241. @Override
  242. public List<? extends Element> children() {
  243. return children;
  244. }
  245. @Override
  246. public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
  247. super.render(matrices, index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
  248. Window window = MinecraftClient.getInstance().getWindow();
  249. this.buttonWidget.active = this.isEditable();
  250. this.buttonWidget.y = y;
  251. this.buttonWidget.x = x + entryWidth / 2 - width / 2;
  252. this.buttonWidget.setWidth(width);
  253. this.buttonWidget.render(matrices, mouseX, mouseY, delta);
  254. }
  255. });
  256. scrolling.addEntry(easingMethodEntry);
  257. scrolling.addEntry(scrollDurationEntry);
  258. scrolling.addEntry(scrollStepEntry);
  259. scrolling.addEntry(bounceMultiplierEntry);
  260. builder.setSavingRunnable(ClothConfigInitializer::saveConfig);
  261. builder.transparentBackground();
  262. return builder;
  263. }
  264. public static ConfigBuilder getConfigBuilderWithDemo() {
  265. ConfigBuilder builder = getConfigBuilder();
  266. ConfigEntryBuilder entryBuilder = builder.entryBuilder();
  267. ConfigCategory testing = builder.getOrCreateCategory(new TranslatableText("category.cloth-config.testing"));
  268. // testing.addEntry(entryBuilder.startDropdownMenu("lol apple", DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  269. testing.addEntry(entryBuilder.startKeyCodeField(new LiteralText("Cool Key"), InputUtil.UNKNOWN_KEYCODE).setDefaultValue(InputUtil.UNKNOWN_KEYCODE).build());
  270. testing.addEntry(entryBuilder.startModifierKeyCodeField(new LiteralText("Cool Modifier Key"), ModifierKeyCode.of(InputUtil.Type.KEYSYM.createFromCode(79), Modifier.of(false, true, false))).setDefaultValue(ModifierKeyCode.of(InputUtil.Type.KEYSYM.createFromCode(79), Modifier.of(false, true, false))).build());
  271. testing.addEntry(entryBuilder.startDoubleList(new LiteralText("A list of Doubles"), Arrays.asList(1d, 2d, 3d)).setDefaultValue(Arrays.asList(1d, 2d, 3d)).build());
  272. testing.addEntry(entryBuilder.startLongList(new LiteralText("A list of Longs"), Arrays.asList(1L, 2L, 3L)).setDefaultValue(Arrays.asList(1L, 2L, 3L)).build());
  273. testing.addEntry(entryBuilder.startStrList(new LiteralText("A list of Strings"), Arrays.asList("abc", "xyz")).setDefaultValue(Arrays.asList("abc", "xyz")).build());
  274. SubCategoryBuilder colors = entryBuilder.startSubCategory(new LiteralText("Colors")).setExpanded(true);
  275. colors.add(entryBuilder.startColorField(new LiteralText("A color field"), 0x00ffff).setDefaultValue(0x00ffff).build());
  276. colors.add(entryBuilder.startColorField(new LiteralText("An alpha color field"), 0xff00ffff).setDefaultValue(0xff00ffff).setAlphaMode(true).build());
  277. colors.add(entryBuilder.startDropdownMenu(new LiteralText("lol apple"), DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  278. colors.add(entryBuilder.startDropdownMenu(new LiteralText("lol apple"), DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  279. colors.add(entryBuilder.startDropdownMenu(new LiteralText("lol apple"), DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  280. colors.add(entryBuilder.startDropdownMenu(new LiteralText("lol apple"), DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  281. colors.add(entryBuilder.startDropdownMenu(new LiteralText("lol apple"), DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toCollection(LinkedHashSet::new))).setSaveConsumer(item -> System.out.println("save this " + item)).build());
  282. testing.addEntry(colors.build());
  283. return builder;
  284. }
  285. public static class Precision {
  286. public static final float FLOAT_EPSILON = 1e-3f;
  287. public static final double DOUBLE_EPSILON = 1e-7;
  288. public static boolean almostEquals(float value1, float value2, float acceptableDifference) {
  289. return Math.abs(value1 - value2) <= acceptableDifference;
  290. }
  291. public static boolean almostEquals(double value1, double value2, double acceptableDifference) {
  292. return Math.abs(value1 - value2) <= acceptableDifference;
  293. }
  294. }
  295. }