|
36 | 36 | import com.mojang.brigadier.arguments.ArgumentType; |
37 | 37 | import io.leangen.geantyref.TypeToken; |
38 | 38 | import java.lang.reflect.Constructor; |
| 39 | +import java.lang.reflect.Field; |
39 | 40 | import java.lang.reflect.Method; |
| 41 | +import java.util.Arrays; |
40 | 42 | import java.util.List; |
| 43 | +import java.util.Objects; |
41 | 44 | import java.util.Queue; |
42 | 45 | import java.util.function.BiFunction; |
43 | 46 | import java.util.function.Predicate; |
@@ -141,18 +144,62 @@ private Builder(final @NonNull String name) { |
141 | 144 | public static final class Parser<C> implements ArgumentParser<C, BlockPredicate> { |
142 | 145 |
|
143 | 146 | private static final Class<?> TAG_CONTAINER_CLASS; |
| 147 | + private static final @Nullable Field REGISTRY_REGISTRY; |
| 148 | + private static final @Nullable Method REGISTRY_GET; |
| 149 | + private static final @Nullable Object BLOCK_REGISTRY_RESOURCE_LOCATION; |
144 | 150 |
|
145 | 151 | static { |
| 152 | + Class<?> tagContainerClass; |
146 | 153 | if (CraftBukkitReflection.MAJOR_REVISION > 12 && CraftBukkitReflection.MAJOR_REVISION < 16) { |
147 | | - TAG_CONTAINER_CLASS = CraftBukkitReflection.needNMSClass("TagRegistry"); |
| 154 | + tagContainerClass = CraftBukkitReflection.needNMSClass("TagRegistry"); |
| 155 | + REGISTRY_REGISTRY = null; |
| 156 | + REGISTRY_GET = null; |
| 157 | + BLOCK_REGISTRY_RESOURCE_LOCATION = null; |
148 | 158 | } else { |
149 | | - TAG_CONTAINER_CLASS = CraftBukkitReflection.firstNonNullOrThrow( |
150 | | - () -> "Couldn't find TagContainer class", |
| 159 | + tagContainerClass = CraftBukkitReflection.firstNonNullOrNull( |
151 | 160 | CraftBukkitReflection.findNMSClass("ITagRegistry"), |
152 | 161 | CraftBukkitReflection.findMCClass("tags.ITagRegistry"), |
153 | 162 | CraftBukkitReflection.findMCClass("tags.TagContainer") |
154 | 163 | ); |
| 164 | + if (tagContainerClass == null) { |
| 165 | + tagContainerClass = CraftBukkitReflection.firstNonNullOrThrow( |
| 166 | + () -> "Registry", |
| 167 | + CraftBukkitReflection.findMCClass("core.IRegistry"), |
| 168 | + CraftBukkitReflection.findMCClass("core.Registry") |
| 169 | + ); |
| 170 | + final Class<?> tagContainerClassFinal = tagContainerClass; |
| 171 | + REGISTRY_REGISTRY = Arrays.stream(tagContainerClass.getDeclaredFields()) |
| 172 | + .filter(it -> it.getType().equals(tagContainerClassFinal)) |
| 173 | + .findFirst() |
| 174 | + .orElseThrow(() -> new IllegalStateException("Could not find Registry Registry field")); |
| 175 | + REGISTRY_REGISTRY.setAccessible(true); |
| 176 | + final Class<?> resourceLocationClass = CraftBukkitReflection.firstNonNullOrThrow( |
| 177 | + () -> "ResourceLocation class", |
| 178 | + CraftBukkitReflection.findMCClass("resources.ResourceLocation"), |
| 179 | + CraftBukkitReflection.findMCClass("resources.MinecraftKey") |
| 180 | + ); |
| 181 | + REGISTRY_GET = Arrays.stream(tagContainerClass.getDeclaredMethods()) |
| 182 | + .filter(it -> it.getParameterCount() == 1 |
| 183 | + && it.getParameterTypes()[0].equals(resourceLocationClass) |
| 184 | + && it.getReturnType().equals(Object.class)) |
| 185 | + .findFirst() |
| 186 | + .orElseThrow(() -> new IllegalStateException("Could not find Registry#get(ResourceLocation)")); |
| 187 | + final Constructor<?> resourceLocationCtr = CraftBukkitReflection.needConstructor( |
| 188 | + resourceLocationClass, |
| 189 | + String.class |
| 190 | + ); |
| 191 | + try { |
| 192 | + BLOCK_REGISTRY_RESOURCE_LOCATION = resourceLocationCtr.newInstance("block"); |
| 193 | + } catch (final ReflectiveOperationException e) { |
| 194 | + throw new RuntimeException(e); |
| 195 | + } |
| 196 | + } else { |
| 197 | + REGISTRY_REGISTRY = null; |
| 198 | + REGISTRY_GET = null; |
| 199 | + BLOCK_REGISTRY_RESOURCE_LOCATION = null; |
| 200 | + } |
155 | 201 | } |
| 202 | + TAG_CONTAINER_CLASS = tagContainerClass; |
156 | 203 | } |
157 | 204 |
|
158 | 205 | private static final Class<?> CRAFT_WORLD_CLASS = CraftBukkitReflection.needOBCClass("CraftWorld"); |
@@ -206,8 +253,7 @@ public static final class Parser<C> implements ArgumentParser<C, BlockPredicate> |
206 | 253 | .filter(it -> it.getReturnType().equals(MINECRAFT_SERVER_CLASS) && it.getParameterCount() == 0) |
207 | 254 | .findFirst() |
208 | 255 | .orElseThrow(() -> new IllegalStateException("Could not find CommandSourceStack#getServer.")); |
209 | | - private static final Method GET_TAG_REGISTRY_METHOD = CraftBukkitReflection.firstNonNullOrThrow( |
210 | | - () -> "getTags method on MinecraftServer", |
| 256 | + private static final @Nullable Method GET_TAG_REGISTRY_METHOD = CraftBukkitReflection.firstNonNullOrNull( |
211 | 257 | CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTagRegistry"), |
212 | 258 | CraftBukkitReflection.findMethod(MINECRAFT_SERVER_CLASS, "getTags"), |
213 | 259 | CraftBukkitReflection.streamMethods(MINECRAFT_SERVER_CLASS) |
@@ -239,7 +285,15 @@ private ArgumentParser<C, BlockPredicate> createParser() throws ReflectiveOperat |
239 | 285 | final Object commandSourceStack = ctx.get(WrappedBrigadierParser.COMMAND_CONTEXT_BRIGADIER_NATIVE_SENDER); |
240 | 286 | try { |
241 | 287 | final Object server = GET_SERVER_METHOD.invoke(commandSourceStack); |
242 | | - final Object tagRegistry = GET_TAG_REGISTRY_METHOD.invoke(server); |
| 288 | + final Object tagRegistry; |
| 289 | + if (GET_TAG_REGISTRY_METHOD != null) { |
| 290 | + tagRegistry = GET_TAG_REGISTRY_METHOD.invoke(server); |
| 291 | + } else { |
| 292 | + Objects.requireNonNull(REGISTRY_GET, "REGISTRY_GET"); |
| 293 | + Objects.requireNonNull(REGISTRY_REGISTRY, "REGISTRY_REGISTRY"); |
| 294 | + final Object registryRegistry = REGISTRY_REGISTRY.get(null); |
| 295 | + tagRegistry = REGISTRY_GET.invoke(registryRegistry, BLOCK_REGISTRY_RESOURCE_LOCATION); |
| 296 | + } |
243 | 297 | final Predicate<Object> predicate = (Predicate<Object>) CREATE_PREDICATE_METHOD.invoke(result, tagRegistry); |
244 | 298 | return ArgumentParseResult.success(new BlockPredicateImpl(predicate)); |
245 | 299 | } catch (final ReflectiveOperationException ex) { |
|
0 commit comments