Skip to content

Commit a84fa8a

Browse files
committed
Merge 1.18 into 1.19.2
2 parents 40be7c9 + 6a7d62b commit a84fa8a

File tree

6 files changed

+86
-133
lines changed

6 files changed

+86
-133
lines changed

common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ private ModernFixEarlyConfig(File file) {
158158

159159
this.scanForAndBuildMixinOptions();
160160
mixinOptions.addAll(DEFAULT_SETTING_OVERRIDES.keySet());
161+
if(!isFabric) {
162+
mixinOptions.add("mixin.bugfix.fix_config_crashes");
163+
}
161164
for(String optionName : mixinOptions) {
162165
boolean defaultEnabled = DEFAULT_SETTING_OVERRIDES.getOrDefault(optionName, true);
163166
this.options.putIfAbsent(optionName, new Option(optionName, defaultEnabled, false));
Lines changed: 22 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,46 @@
11
package org.embeddedt.modernfix.util;
22

3+
import com.google.common.base.Function;
34
import com.google.common.collect.Interner;
45
import com.google.common.collect.Interners;
5-
import it.unimi.dsi.fastutil.objects.*;
6-
import org.jetbrains.annotations.NotNull;
7-
import org.jetbrains.annotations.Nullable;
6+
import com.google.common.collect.Maps;
87

9-
import java.util.*;
10-
import java.util.function.Function;
8+
import java.util.HashMap;
9+
import java.util.Map;
1110

1211
/**
13-
* Replacement backing map for CompoundTags. Uses an array map for tags with 4 or less entries,
14-
* and a hash map for larger tags.
12+
* Replacement backing map for CompoundTags that interns keys.
1513
*/
16-
public class CanonizingStringMap<T> implements Map<String, T> {
17-
private Object2ObjectMap<String, T> backingMap;
18-
19-
private static final int GROWTH_THRESHOLD = 4;
14+
public class CanonizingStringMap<T> extends HashMap<String, T> {
2015
private static final Interner<String> KEY_INTERNER = Interners.newStrongInterner();
2116

22-
public CanonizingStringMap() {
23-
this(new Object2ObjectArrayMap<>());
24-
}
25-
26-
protected CanonizingStringMap(Object2ObjectMap<String, T> newMap) {
27-
this.backingMap = newMap;
28-
}
29-
30-
@Override
31-
public int size() {
32-
return backingMap.size();
33-
}
34-
35-
@Override
36-
public boolean isEmpty() {
37-
return backingMap.isEmpty();
38-
}
39-
40-
@Override
41-
public boolean containsKey(Object o) {
42-
return backingMap.containsKey(o);
43-
}
44-
45-
@Override
46-
public boolean containsValue(Object o) {
47-
return backingMap.containsValue(o);
48-
}
49-
50-
@Override
51-
public T get(Object o) {
52-
return backingMap.get(o);
17+
private static String intern(String key) {
18+
return key != null ? KEY_INTERNER.intern(key) : null;
5319
}
5420

55-
@Nullable
56-
@Override
57-
public T put(String s, T t) {
58-
if(backingMap.size() >= GROWTH_THRESHOLD && !(backingMap instanceof Object2ObjectOpenHashMap) && !backingMap.containsKey(s)) {
59-
// map will grow to GROWTH_THRESHOLD + 1 entries, change to hashmap
60-
backingMap = new Object2ObjectOpenHashMap<>(backingMap);
61-
}
62-
s = KEY_INTERNER.intern(s);
63-
return backingMap.put(s, t);
64-
}
65-
66-
@Override
67-
public T remove(Object o) {
68-
T value = backingMap.remove(o);
69-
// need to shrink to be consistent with new maps
70-
if(backingMap.size() <= GROWTH_THRESHOLD && backingMap instanceof Object2ObjectOpenHashMap) {
71-
backingMap = new Object2ObjectArrayMap<>(backingMap);
72-
}
73-
return value;
74-
}
75-
76-
@Override
77-
public void putAll(@NotNull Map<? extends String, ? extends T> map) {
78-
if(map.size() == 0)
79-
return;
80-
// grow early if we know there are enough non-overlapping keys
81-
if((map.size() - backingMap.size()) > GROWTH_THRESHOLD && !(backingMap instanceof Object2ObjectOpenHashMap)) {
82-
backingMap = new Object2ObjectOpenHashMap<>(backingMap);
83-
}
84-
map.forEach((String key, T val) -> {
85-
key = KEY_INTERNER.intern(key);
86-
backingMap.put(key, val);
87-
});
88-
// if it's still an array, and now too big, grow it
89-
if(backingMap.size() > GROWTH_THRESHOLD && !(backingMap instanceof Object2ObjectOpenHashMap)) {
90-
backingMap = new Object2ObjectOpenHashMap<>(backingMap);
91-
}
92-
}
93-
94-
@Override
95-
public void clear() {
96-
if(!(this.backingMap instanceof Object2ObjectArrayMap))
97-
this.backingMap = new Object2ObjectArrayMap<>();
98-
else
99-
this.backingMap.clear();
100-
}
101-
102-
@NotNull
103-
@Override
104-
public Set<String> keySet() {
105-
// has to be modifiable because mods (cough, Tinkers) use it to clear the tag
106-
return this.backingMap.keySet();
107-
}
108-
109-
@NotNull
110-
@Override
111-
public Collection<T> values() {
112-
return Collections.unmodifiableCollection(this.backingMap.values());
21+
public CanonizingStringMap() {
22+
super();
11323
}
11424

115-
@NotNull
11625
@Override
117-
public Set<Entry<String, T>> entrySet() {
118-
return Collections.unmodifiableSet(this.backingMap.entrySet());
26+
public T put(String key, T value) {
27+
return super.put(intern(key), value);
11928
}
12029

12130
@Override
122-
public boolean equals(Object o) {
123-
if (this == o) return true;
124-
if (o == null || getClass() != o.getClass()) return false;
125-
CanonizingStringMap<?> that = (CanonizingStringMap<?>)o;
126-
if(that.backingMap.size() != backingMap.size())
127-
return false;
128-
return backingMap.object2ObjectEntrySet().containsAll(that.backingMap.object2ObjectEntrySet());
31+
public void putAll(Map<? extends String, ? extends T> m) {
32+
HashMap<String, T> tmp = new HashMap<>();
33+
m.forEach((k, v) -> tmp.put(intern(k), v));
34+
super.putAll(tmp);
12935
}
13036

131-
/**
132-
* We deliberately use a hashcode that will be consistent regardless of underlying map type.
133-
*/
134-
@Override
135-
public int hashCode() {
136-
final ObjectIterator<Object2ObjectMap.Entry<String, T>> i = Object2ObjectMaps.fastIterator(backingMap);
137-
int h = 0, n = backingMap.size();
138-
while (n-- != 0)
139-
h += i.next().hashCode();
140-
return h;
37+
private void putAllWithoutInterning(Map<? extends String, ? extends T> m) {
38+
super.putAll(m);
14139
}
14240

143-
public static <T> CanonizingStringMap<T> deepCopy(CanonizingStringMap<T> inputMap, Function<T, T> deepCopier) {
144-
Objects.requireNonNull(deepCopier);
145-
Object2ObjectMap<String, T> copiedBackingMap;
146-
int size = inputMap.backingMap.size();
147-
if(size > GROWTH_THRESHOLD) {
148-
copiedBackingMap = new Object2ObjectOpenHashMap<>(size);
149-
} else
150-
copiedBackingMap = new Object2ObjectArrayMap<>(size);
151-
inputMap.backingMap.object2ObjectEntrySet().forEach(entry -> {
152-
if(entry.getKey() != null && entry.getValue() != null)
153-
copiedBackingMap.put(entry.getKey(), deepCopier.apply(entry.getValue()));
154-
});
155-
return new CanonizingStringMap<>(copiedBackingMap);
41+
public static <T> CanonizingStringMap<T> deepCopy(CanonizingStringMap<T> incomingMap, Function<T, T> deepCopier) {
42+
CanonizingStringMap<T> newMap = new CanonizingStringMap<>();
43+
newMap.putAllWithoutInterning(Maps.transformValues(incomingMap, deepCopier));
44+
return newMap;
15645
}
15746
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.embeddedt.modernfix.forge.config;
2+
3+
import net.minecraftforge.fml.ModContainer;
4+
import net.minecraftforge.fml.ModList;
5+
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
6+
import net.minecraftforge.fml.config.ModConfig;
7+
import org.embeddedt.modernfix.ModernFix;
8+
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
9+
10+
import java.util.Optional;
11+
import java.util.function.Consumer;
12+
13+
public class ConfigFixer {
14+
/**
15+
* To prevent mods from crashing if their ModConfigEvent is invoked by Night Config's watch thread and Forge
16+
* at the same time, wrap their config handler so that it only executes the event in serial for that mod.
17+
*
18+
* Should have no noticeable performance impact as config handlers are virtually instant.
19+
*/
20+
public static void replaceConfigHandlers() {
21+
if(!ModernFixMixinPlugin.instance.isOptionEnabled("bugfix.fix_config_crashes.ConfigFixerMixin"))
22+
return;
23+
ModList.get().forEachModContainer((id, container) -> {
24+
try {
25+
Optional<Consumer<ModConfig.ModConfigEvent>> configOpt = ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, container, "configHandler");
26+
if(configOpt.isPresent()) {
27+
ObfuscationReflectionHelper.setPrivateValue(ModContainer.class, container, Optional.of(new LockingConfigHandler(id, configOpt.get())), "configHandler");
28+
}
29+
} catch(RuntimeException e) {
30+
ModernFix.LOGGER.error("Error replacing config handler", e);
31+
}
32+
});
33+
}
34+
35+
private static class LockingConfigHandler implements Consumer<ModConfig.ModConfigEvent> {
36+
private final Consumer<ModConfig.ModConfigEvent> actualHandler;
37+
private final String modId;
38+
39+
LockingConfigHandler(String id, Consumer<ModConfig.ModConfigEvent> actualHandler) {
40+
this.modId = id;
41+
this.actualHandler = actualHandler;
42+
}
43+
44+
@Override
45+
public void accept(ModConfig.ModConfigEvent modConfigEvent) {
46+
synchronized (this) {
47+
this.actualHandler.accept(modConfigEvent);
48+
}
49+
}
50+
51+
@Override
52+
public String toString() {
53+
return "LockingConfigHandler{id=" + modId + "}";
54+
}
55+
}
56+
}

forge/src/main/java/org/embeddedt/modernfix/forge/init/ModernFixForge.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.embeddedt.modernfix.forge.classloading.ModFileScanDataDeduplicator;
2727
import org.embeddedt.modernfix.forge.ModernFixConfig;
2828
import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler;
29+
import org.embeddedt.modernfix.forge.config.ConfigFixer;
2930
import org.embeddedt.modernfix.forge.packet.PacketHandler;
3031
import org.embeddedt.modernfix.forge.registry.ObjectHolderClearer;
3132

@@ -46,6 +47,7 @@ public ModernFixForge() {
4647
PacketHandler.register();
4748
ModFileScanDataDeduplicator.deduplicate();
4849
ClassLoadHack.loadModClasses();
50+
ConfigFixer.replaceConfigHandlers();
4951
}
5052

5153
@SubscribeEvent

scripts/autorelease.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ do_release() {
2727
echo "we think the current tag is $(git describe --tags --abbrev=0)"
2828
echo "the current commit head is $(git rev-parse HEAD)"
2929
read -p "new tag name: " tag_name
30+
git tag -a $tag_name -m "$tag_name"
31+
git push --tags
3032
gh release create $tag_name --target $1 --title "$tag_name" --notes ""
3133
}
3234

scripts/propagate.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ for version in "${all_versions[@]}"; do
4747
read -rs -n1
4848
fi
4949
if (git add . && git commit -m "Merge $our_version into $version" &>/dev/null); then
50+
echo
5051
git push -u origin propagations/$version:$version &>/dev/null
5152
else
5253
echo -e "\b\b\b\bnothing to merge"

0 commit comments

Comments
 (0)