diff --git a/src/main/java/dev/latvian/mods/kubejs/bindings/HolderSetWrapper.java b/src/main/java/dev/latvian/mods/kubejs/bindings/HolderSetWrapper.java new file mode 100644 index 000000000..f1daffa95 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/bindings/HolderSetWrapper.java @@ -0,0 +1,67 @@ +package dev.latvian.mods.kubejs.bindings; + +import com.google.common.collect.Iterators; +import dev.latvian.mods.kubejs.util.UtilsJS; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public record HolderSetWrapper(Registry registry, HolderSet holders) implements Iterable { + + public int size() { + return holders.size(); + } + + public boolean isEmpty() { + return holders.size() == 0; + } + + public boolean contains(ResourceLocation id) { + return registry.getHolder(id).filter(holders::contains).isPresent(); + } + + public boolean containsValue(T value) { + return holders.contains(registry.wrapAsHolder(value)); + } + + public List getValues() { + return holders.stream().map(Holder::value).toList(); + } + + public Set getKeys() { + return holders.stream().map(holder -> { + var key = holder.getKey(); + if (key == null) { + return null; + } + + return key.location(); + }).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + @Nullable + public T getRandom() { + return getRandom(UtilsJS.RANDOM); + } + + @Nullable + public T getRandom(RandomSource random) { + return holders.getRandomElement(random).map(Holder::value).orElse(null); + } + + @NotNull + @Override + public Iterator iterator() { + return Iterators.transform(holders.iterator(), Holder::value); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/bindings/RegistryWrapper.java b/src/main/java/dev/latvian/mods/kubejs/bindings/RegistryWrapper.java index 4ef15db9d..2acf7f049 100644 --- a/src/main/java/dev/latvian/mods/kubejs/bindings/RegistryWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/bindings/RegistryWrapper.java @@ -1,16 +1,22 @@ package dev.latvian.mods.kubejs.bindings; +import dev.latvian.mods.kubejs.holder.HolderWrapper; import dev.latvian.mods.kubejs.util.RegistryAccessContainer; +import dev.latvian.mods.kubejs.util.UtilsJS; import dev.latvian.mods.rhino.Context; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -27,6 +33,10 @@ public boolean contains(ResourceLocation id) { return registry.containsKey(id); } + public boolean containsValue(T value) { + return registry.containsValue(value); + } + public Set> getEntrySet() { return registry.entrySet().stream().map(e -> Map.entry(e.getKey().location(), e.getValue())).collect(Collectors.toSet()); } @@ -35,6 +45,11 @@ public Map getValueMap() { return registry.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().location(), Map.Entry::getValue)); } + public HolderSetWrapper getValues(Object filter) { + var holderSet = HolderWrapper.wrapSimpleSet(registry, filter); + return new HolderSetWrapper<>(registry, Objects.requireNonNullElseGet(holderSet, HolderSet::empty)); + } + public List getValues() { return registry.stream().collect(Collectors.toList()); } @@ -43,6 +58,16 @@ public Set getKeys() { return registry.keySet(); } + @Nullable + public T getRandom() { + return getRandom(UtilsJS.RANDOM); + } + + @Nullable + public T getRandom(RandomSource random) { + return registry.getRandom(random).map(Holder::value).orElse(null); + } + @Nullable public ResourceLocation getId(T value) { return registry.getKey(value); diff --git a/src/main/java/dev/latvian/mods/kubejs/bindings/UtilsWrapper.java b/src/main/java/dev/latvian/mods/kubejs/bindings/UtilsWrapper.java index df89b395b..d5c0b24ac 100644 --- a/src/main/java/dev/latvian/mods/kubejs/bindings/UtilsWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/bindings/UtilsWrapper.java @@ -12,6 +12,7 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.stats.Stat; import net.minecraft.stats.Stats; +import net.minecraft.util.RandomSource; import net.minecraft.world.item.CreativeModeTab; import org.jetbrains.annotations.Nullable; @@ -28,13 +29,13 @@ @Info("A collection of utilities") public interface UtilsWrapper { @Info("Get a Random, for generating random numbers. Note this will always return the same Random instance") - static Random getRandom() { + static RandomSource getRandom() { return UtilsJS.RANDOM; } @Info("Get a new random with the specified seed") - static Random newRandom(long seed) { - return new Random(seed); + static RandomSource newRandom(long seed) { + return RandomSource.create(seed); } @Info("Get an immutable empty list") diff --git a/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java b/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java index 98ee48645..94b56ea94 100644 --- a/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/holder/HolderWrapper.java @@ -8,9 +8,10 @@ import dev.latvian.mods.rhino.type.TypeInfo; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; -import net.minecraft.resources.ResourceKey; +import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -59,6 +60,22 @@ static HolderSet wrapSet(KubeJSContext cx, Object from, TypeInfo param) { var registry = cx.lookupRegistry(param, from); + var simpleHolders = wrapSimpleSet(registry, from); + if (simpleHolders != null) { + return simpleHolders; + } + + if (from instanceof Iterable) { + var holder = (List) cx.jsToJava(from, TypeInfo.RAW_LIST.withParams(HOLDER.withParams(param))); + return HolderSet.direct(holder); + } else { + var holder = wrap(cx, from, param); + return HolderSet.direct(holder); + } + } + + @Nullable + static HolderSet wrapSimpleSet(Registry registry, Object from) { var regex = RegExpKJS.wrap(from); if (regex != null) { @@ -73,17 +90,11 @@ static HolderSet wrapSet(KubeJSContext cx, Object from, TypeInfo param) { } else if (s.charAt(0) == '@') { return new NamespaceHolderSet<>(registry.asLookup(), s.substring(1)); } else if (s.charAt(0) == '#') { - var tagKey = TagKey.create((ResourceKey) registry.key(), ResourceLocation.parse(s.substring(1))); + var tagKey = TagKey.create(registry.key(), ResourceLocation.parse(s.substring(1))); return registry.getOrCreateTag(tagKey); } } - if (from instanceof Iterable) { - var holder = (List) cx.jsToJava(from, TypeInfo.RAW_LIST.withParams(HOLDER.withParams(param))); - return HolderSet.direct(holder); - } else { - var holder = wrap(cx, from, param); - return HolderSet.direct(holder); - } + return null; } } diff --git a/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java b/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java index 06d801d30..c1558c57b 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java @@ -24,6 +24,7 @@ import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; import net.minecraft.world.item.CreativeModeTab; import org.jetbrains.annotations.Nullable; @@ -48,7 +49,7 @@ import java.util.regex.Pattern; public class UtilsJS { - public static final Random RANDOM = new Random(); + public static final RandomSource RANDOM = RandomSource.create(); public static final ResourceLocation AIR_LOCATION = ResourceLocation.parse("minecraft:air"); public static final Pattern SNAKE_CASE_SPLIT = Pattern.compile("[:_/]"); public static final Set ALWAYS_LOWER_CASE = new HashSet<>(Arrays.asList("a", "an", "the", "of", "on", "in", "and", "or", "but", "for"));