aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/anthonyhilyard/iceberg/mixin/ConfigMenusForgeConfigScreenMixin.java
blob: 42c388df6539539f2dbcedc55df33afd649f870e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package com.anthonyhilyard.iceberg.mixin;

import java.lang.reflect.Constructor;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import com.anthonyhilyard.iceberg.Loader;
import com.anthonyhilyard.iceberg.util.ConfigMenusForgeHelper;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import fuzs.configmenusforge.client.gui.data.IEntryData;
import fuzs.configmenusforge.client.gui.screens.ConfigScreen;
import fuzs.configmenusforge.client.util.ServerConfigUploader;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.config.ModConfig;


@Mixin(ConfigScreen.class)
public abstract class ConfigMenusForgeConfigScreenMixin extends Screen
{
	protected ConfigMenusForgeConfigScreenMixin(Component p_96550_) { super(p_96550_); }
	
	@Unique
	private UnmodifiableConfig mainConfig = null;

	@Inject(method = "create", at = @At("HEAD"), remap = false, cancellable = true)
	private static void create(Screen lastScreen, Component title, ResourceLocation background, ModConfig config, Map<Object, IEntryData> valueToData, CallbackInfoReturnable<ConfigScreen> info)
	{
		try
		{
			Constructor<?> mainConstructor = Class.forName("fuzs.configmenusforge.client.gui.screens.ConfigScreen$Main").getDeclaredConstructor(Screen.class, Component.class, ResourceLocation.class, UnmodifiableConfig.class, Map.class, Runnable.class);
			mainConstructor.setAccessible(true);
			info.setReturnValue((ConfigScreen)mainConstructor.newInstance(lastScreen, title, background, ConfigMenusForgeHelper.getValues(config.getSpec()), valueToData, (Runnable)(() -> ServerConfigUploader.saveAndUpload(config))));
			info.cancel();
			return;
		}
		catch (Exception e)
		{
			Loader.LOGGER.warn(ExceptionUtils.getStackTrace(e.getCause()));
		}
	}

	@Redirect(method = "<init>(Lnet/minecraft/client/gui/screens/Screen;Lnet/minecraft/network/chat/Component;Lnet/minecraft/resources/ResourceLocation;Lcom/electronwill/nightconfig/core/UnmodifiableConfig;Ljava/util/Map;[I)V",
			  at = @At(value = "INVOKE", target = "Ljava/util/Collection;stream()Ljava/util/stream/Stream;", ordinal = 0, remap = false), remap = false)
	Stream<Object> filteredEntries(Collection<Object> values)
	{
		return values.stream().map(value -> {
			if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue && configValue.get() instanceof UnmodifiableConfig config)
			{
				return config;
			}
			else
			{
				return value;
			}
		});
	}

	/// TODO: Add extended support for mutable subconfigs by adding an "Add new key" button and ability to delete keys.

	// @Shadow(remap = false)
	// @Final
	// @Mutable
	// private List<IEntryData> searchEntries;

	// @Shadow(remap = false)
	// @Final
	// @Mutable
	// private List<IEntryData> screenEntries;

	// @Shadow(remap = false)
	// @Final
	// @Mutable
	// Map<Object, IEntryData> valueToData;

	// @Shadow(remap = false)
	// EditBox searchTextField;

	// @Shadow(remap = false)
	// @Final
	// ResourceLocation background;
	
	// @Shadow(remap = false)
	// List<ConfigScreen.Entry> getConfigListEntries(List<IEntryData> entries, final String searchHighlight) { return null; }
	
	// @Inject(method = "getConfigListEntries(Ljava/lang/String;)Ljava/util/List;", at = @At("HEAD"), remap = false, cancellable = true)
	// private void getConfigListEntries(String query, CallbackInfoReturnable<List<ConfigScreen.Entry>> info)
	// {
	// 	query = query.toLowerCase(Locale.ROOT).trim();
	// 	if (query.isEmpty())
	// 	{
	// 		List<ConfigScreen.Entry> entries = Lists.newArrayList(getConfigListEntries(screenEntries, query));

	// 		// Add an "add new key" button if this is a dynamic subconfig.  We can't be sure that's what this is,
	// 		// since we don't have access to the spec here, so we're going to have to make an assumption...
	// 		try
	// 		{
	// 			if (mainConfig != null && mainConfig.getClass().isAssignableFrom(Class.forName("com.electronwill.nightconfig.core.SimpleCommentedConfig")))
	// 			{
	// 				Class<?> categoryEntryClass = Class.forName("fuzs.configmenusforge.client.gui.screens.ConfigScreen$CategoryEntry");

	// 				Constructor<?> categoryEntryConstructor = categoryEntryClass.getDeclaredConstructor(ConfigScreen.class, CategoryEntryData.class, String.class);
	// 				categoryEntryConstructor.setAccessible(true);
	// 				ConfigScreen.Entry addNewKeyEntry = (ConfigScreen.Entry) categoryEntryConstructor.newInstance(this, new CategoryEntryData(null, null, null) {
	// 					// TODO: Make translatable
	// 					private static Component title = new TextComponent("Add new key");
	// 					@Override
	// 					public String getPath() { return null; }
	// 					@Override
	// 					public String getComment() { return null; }
	// 					@Override
	// 					public Component getTitle() { return title; }
	// 					@Override
	// 					public boolean mayResetValue() { return false; }
	// 					@Override
	// 					public boolean mayDiscardChanges() { return false; }
	// 					@Override
	// 					public void resetCurrentValue() { }
	// 					@Override
	// 					public void discardCurrentValue() { }
	// 					@Override
	// 					public void saveConfigValue() { }
	// 					@Override
	// 					public boolean category() { return false; }
	// 				}, null);

	// 				Field buttonField = categoryEntryClass.getDeclaredField("button");
	// 				UnsafeHacks.setField(buttonField, addNewKeyEntry, new Button(10, 5, 260, 20, new TextComponent("Add new key"), button -> {
	// 					searchTextField.setValue("");
	// 					searchTextField.setFocus(false);
	// 					Screen editScreen = new EditStringScreen((ConfigScreen)(Object)this, title, background, "", x -> true, currentValue -> {
	// 						((Config)mainConfig).set(currentValue, "");
	// 						// Update screen and search entries lists.
	// 						List<IEntryData> newEntries = Lists.newArrayList();
	// 						ValueSpec newValueSpec = IcebergConfigSpec.createValueSpec(null, null, false, Object.class, () -> null, v -> v != null);
	// 						final EntryData.ConfigEntryData<?> data = new DynamicConfigEntryData<>(List.of(currentValue), "", newValueSpec, mainConfig);
	// 						valueToData = Maps.newLinkedHashMap(valueToData);
	// 						valueToData.put(currentValue, data);
	// 						gatherEntries(mainConfig, newEntries, valueToData);
	// 						searchEntries = newEntries;
	// 						screenEntries = mainConfig.valueMap().values().stream().map(valueToData::get).toList();
	// 						((ConfigScreen)(Object)this).updateList(false);
	// 					});
	// 					final Minecraft minecraft = Minecraft.getInstance();
	// 					minecraft.setScreen(editScreen);
	// 				}));
					
	// 				entries.add(addNewKeyEntry);
	// 			}
	// 		}
	// 		catch (Exception e)
	// 		{
	// 			Loader.LOGGER.info(ExceptionUtils.getStackTrace(e));
	// 		}
			
	// 		info.setReturnValue(entries);
	// 	}
	// 	else
	// 	{
	// 		info.setReturnValue(getConfigListEntries(searchEntries, query));
	// 	}
		
	// 	info.cancel();
	// }

	@Inject(method = "gatherEntriesRecursive(Lcom/electronwill/nightconfig/core/UnmodifiableConfig;Ljava/util/Map;)Ljava/util/List;",
			at = @At("HEAD"), remap = false, cancellable = true)
	private void gatherEntriesRecursiveSubconfigSupport(UnmodifiableConfig mainConfig, Map<Object, IEntryData> allEntries, CallbackInfoReturnable<List<IEntryData>> info)
	{
		// Store this config for later.
		this.mainConfig = mainConfig;

		List<IEntryData> entries = Lists.newArrayList();
		gatherEntries(mainConfig, entries, allEntries);
		info.setReturnValue(ImmutableList.copyOf(entries));
		info.cancel();
	}

	@Unique
	private static void gatherEntries(UnmodifiableConfig mainConfig, List<IEntryData> entries, Map<Object, IEntryData> entryMap)
	{
		for (Object value : mainConfig.valueMap().values())
		{
			if (entryMap.get(value) != null)
			{
				entries.add(entryMap.get(value));
			}
			if (value instanceof UnmodifiableConfig config)
			{
				gatherEntries(config, entries, entryMap);
			}
			else if (value instanceof ForgeConfigSpec.ConfigValue<?> configValue && configValue.get() instanceof UnmodifiableConfig config)
			{
				if (entryMap.get(config) != null)
				{
					entries.add(entryMap.get(config));
				}
				gatherEntries(config, entries, entryMap);
			}
		}
	}
}