Skip to content

Commit e793ee1

Browse files
committed
[registries] add LegacyStringIds utilities
for converting between legacy String IDs and modern namespaced IDs
1 parent c0818a2 commit e793ee1

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package net.ornithemc.osl.registries.api.registry;
2+
3+
import net.ornithemc.osl.core.api.util.NamespacedIdentifier;
4+
import net.ornithemc.osl.core.api.util.NamespacedIdentifiers;
5+
import net.ornithemc.osl.core.impl.util.Util;
6+
7+
/**
8+
* Utilities for converting legacy {@linkplain String} IDs to proper
9+
* {@linkplain NamespacedIdentifier namespaced IDs} for use in registries.
10+
* <p>
11+
* Legacy IDs were not namespaced and used PascalCase rather than snake_case.
12+
* Many of these IDs are very old and some use outdated names or conventions.
13+
* For example:
14+
* <li>{@code LavaSlime} is the legacy ID for {@code minecraft:magma_cube} (the
15+
* name changed entirely)</li>
16+
* <li>{@code MinecartChest} and {@code MinecartTNT} are the legacy IDs for
17+
* {@code minecraft:chest_minecart} and {@code minecraft:tnt_minecart} (the word
18+
* order changed)</li>
19+
* <p>
20+
* The various Minecraft systems switched over to namespaced identifiers in
21+
* different updates, and in the process the IDs were often tweaked or changed
22+
* to better fit new conventions. For this reason, OSL uses hard-coded
23+
* conversion tables for known Vanilla legacy IDs and their respective new
24+
* namespaced IDs.
25+
* <p>
26+
* Where content from mods is concerned however, that is not a feasible
27+
* approach. With that in mind, this class provides utility methods for
28+
* <i>general</i> conversion between legacy IDs and namespaced IDs. An attempt
29+
* was made to match the different conventions, but to keep the complexity down,
30+
* no attempt is made to change things like word order. See
31+
* {@link #fromIdentifier(String, String)} and {@link #toIdentifier(String)} for
32+
* implementation details.
33+
*/
34+
public final class LegacyStringIds {
35+
36+
/**
37+
* Converts the given {@linkplain NamespacedIdentifier namespaced ID} to a
38+
* legacy format {@linkplain String} ID. See
39+
* {@link #fromIdentifier(String, String)} for implementation details.
40+
*
41+
* @param identifier the namespaced ID to convert.
42+
* @return the legacy ID representation of the namespaced ID.
43+
*
44+
* @see #fromIdentifier(String, String)
45+
*/
46+
public static String fromIdentifier(NamespacedIdentifier identifier) {
47+
return fromIdentifier(identifier.namespace(), identifier.identifier());
48+
}
49+
50+
/**
51+
* Converts the given {@linkplain NamespacedIdentifier namespaced ID} to a
52+
* legacy format {@linkplain String} ID. Legacy IDs are not namespaced and use
53+
* PascalCase rather than snake_case.
54+
* <p>
55+
* Namespaced IDs are converted to the format
56+
* {@code <namespace>.<IdentifierInPascalCase>}, though for Minecraft IDs the
57+
* namespace is dropped and the result looks like
58+
* {@code <IdentifierInPascalCase>}.
59+
* <p>
60+
* The conversion to PascalCase works as follows:
61+
* <li>All {@code _} characters are dropped.</li>
62+
* <li>The first character of the string, and any character superceding a
63+
* {@code _} character is converted to upper case using
64+
* {@linkplain Character#toUpperCase(char)}.</li>
65+
* <p>
66+
* See below for some example conversions.
67+
* <li>{@code minecraft:tnt_minecart} -> {@code TntMinecart}</li>
68+
* <li>{@code example:chocolate_chip_cookie} ->
69+
* {@code example.ChocolateChipCookie}</li>
70+
*
71+
* @param namespace the namespace of the namespaced ID to convert.
72+
* @param identifier the identifier of the namespaced ID to convert.
73+
* @return the legacy ID representation of the namespaced ID.
74+
*/
75+
public static String fromIdentifier(String namespace, String identifier) {
76+
String id = Util.snakeCaseToPascalCase(identifier);
77+
78+
if (!namespace.equals(NamespacedIdentifiers.MINECRAFT_NAMESPACE)) {
79+
id = namespace + "." + id;
80+
}
81+
82+
return id;
83+
}
84+
85+
/**
86+
* Converts the given legacy format {@linkplain String} ID to a proper
87+
* {@linkplain NamespacedIdentifier namespaced ID}. Legacy IDs are not
88+
* namespaced and use PascalCase rather than snake_case.
89+
* <p>
90+
* Legacy IDs are converted to the format
91+
* {@code <namespace>:<id_in_snake_case>}. The namespace is parsed from the
92+
* legacy ID based on the presence of a {@code .} character. If that character
93+
* is not present in the legacy ID, the {@code minecraft} namespace is used
94+
* instead.
95+
* <p>
96+
* The conversion to snake_case works as follows:
97+
* <li>All characters that match {@linkplain Character#isUpperCase(char)} are
98+
* converted to lower case using {@linkplain Character#toLowerCase(char)}.</li>
99+
* <li>A {@code _} character is inserted before every upper case character that
100+
* is not the first character of the string <b>IF</b> the preceding character is
101+
* not upper case.</li>
102+
* <p>
103+
* See below for some example conversions.
104+
* <li>{@code MinecartTNT} -> {@code minecraft:minecart_tnt}</li>
105+
* <li>{@code example.ChocolateChipCookie} ->
106+
* {@code example:chocolate_chip_cookie}</li>
107+
*
108+
* @param id the legacy ID to convert.
109+
* @return the namespaced ID representation of the legacy ID.
110+
*/
111+
public static NamespacedIdentifier toIdentifier(String id) {
112+
String namespace = NamespacedIdentifiers.MINECRAFT_NAMESPACE;
113+
String identifier = id;
114+
115+
int i = id.indexOf('.');
116+
117+
if (i > 0) {
118+
namespace = id.substring(0, i);
119+
identifier = id.substring(i + 1);
120+
}
121+
122+
identifier = Util.pascalCaseToSnakeCase(identifier);
123+
124+
return NamespacedIdentifiers.from(namespace, identifier);
125+
}
126+
}

0 commit comments

Comments
 (0)