Skip to content

Commit fb5aeb5

Browse files
authored
2.3.0 (#159)
1 parent 15edc70 commit fb5aeb5

14 files changed

Lines changed: 444 additions & 105 deletions

File tree

common/src/main/java/software/bluelib/BlueLibConstants.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
import software.bluelib.platform.IPlatformHelper;
2121
import software.bluelib.platform.IRegistryHelper;
2222

23-
public class BlueLibConstants {
24-
25-
private BlueLibConstants() {}
23+
public class BlueLibConstants implements BuildDetails {
2624

2725
public static void init() {}
2826

@@ -33,6 +31,11 @@ public static <T> T load(@NotNull Class<T> pClazz) {
3331
.orElseThrow(() -> new NullPointerException("Failed to load service for " + pClazz.getName()));
3432
}
3533

34+
@NotNull
35+
public static <T> ServiceLoader<T> loadAll(@NotNull Class<T> pClazz) {
36+
return ServiceLoader.load(pClazz);
37+
}
38+
3639
@NotNull
3740
public static final Logger LOGGER = Logger.getLogger(BlueLibConstants.MOD_NAME);
3841

@@ -45,9 +48,27 @@ public static <T> T load(@NotNull Class<T> pClazz) {
4548
@NotNull
4649
public static final String MOD_NAME = "BlueLib";
4750

51+
@NotNull
52+
public static final String VERSION = "2.3.0";
53+
4854
@Nullable
4955
public static MinecraftServer server;
5056

57+
@Override
58+
public @NotNull String getModId() {
59+
return MOD_ID;
60+
}
61+
62+
@Override
63+
public @NotNull String getVersion() {
64+
return VERSION;
65+
}
66+
67+
@Override
68+
public boolean displayWarning() {
69+
return false;
70+
}
71+
5172
public static class BlueLoader {
5273

5374
@NotNull
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (C) 2024 BlueLib Contributors
3+
*
4+
* This Source Code Form is subject to the terms of the MIT License.
5+
* If a copy of the MIT License was not distributed with this file,
6+
* You can obtain one at https://opensource.org/licenses/MIT.
7+
*/
8+
package software.bluelib;
9+
10+
import org.jetbrains.annotations.NotNull;
11+
12+
public interface BuildDetails {
13+
14+
@NotNull
15+
String getModId();
16+
17+
@NotNull
18+
String getVersion();
19+
20+
boolean displayWarning();
21+
}

common/src/main/java/software/bluelib/api/entity/variant/IVariantEntity.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ public interface IVariantEntity<T extends Entity> {
3030
@NotNull
3131
T getEntity();
3232

33-
@Nullable
34-
default String getRandomVariant(@NotNull List<String> pVariantNamesList, @Nullable String pDefaultVariant) {
33+
@NotNull
34+
default String getRandomVariant(@NotNull List<String> pVariantNamesList, @NotNull String pDefaultVariant) {
3535
if (pVariantNamesList.isEmpty()) {
3636
BaseLogger.log(true, BaseLogLevel.INFO, BlueTranslation.log("variant.list.empty", pDefaultVariant));
3737
return pDefaultVariant;

common/src/main/java/software/bluelib/api/net/NetworkRegistry.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,18 @@ public static void sendPacketToPlayers(@NotNull Iterable<ServerPlayer> pPlayers,
5050
private static final List<PacketProvider.C2SPacketProvider> c2sProviders = new ArrayList<>();
5151
private static final List<PacketProvider.S2CPacketProvider> s2cProviders = new ArrayList<>();
5252

53-
public static List<PacketRegisterInfo<?>> s2cPayloads = generateS2CPacketInfoList();
54-
public static List<PacketRegisterInfo<?>> c2sPayloads = generateC2SPacketInfoList();
53+
private static List<PacketRegisterInfo<?>> c2sPayloads = null;
54+
private static List<PacketRegisterInfo<?>> s2cPayloads = null;
55+
56+
public static List<PacketRegisterInfo<?>> getC2SPayloads() {
57+
if (c2sPayloads == null) c2sPayloads = generateC2SPacketInfoList();
58+
return c2sPayloads;
59+
}
60+
61+
public static List<PacketRegisterInfo<?>> getS2CPayloads() {
62+
if (s2cPayloads == null) s2cPayloads = generateS2CPacketInfoList();
63+
return s2cPayloads;
64+
}
5565

5666
@NotNull
5767
private static List<PacketRegisterInfo<?>> generateS2CPacketInfoList() {
@@ -73,11 +83,11 @@ private static List<PacketRegisterInfo<?>> generateC2SPacketInfoList() {
7383

7484
public static void registerC2SPacketProvider(@NotNull PacketProvider.C2SPacketProvider pProvider) {
7585
c2sProviders.add(pProvider);
76-
c2sPayloads = generateC2SPacketInfoList();
86+
c2sPayloads = null;
7787
}
7888

7989
public static void registerS2CPacketProvider(@NotNull PacketProvider.S2CPacketProvider pProvider) {
8090
s2cProviders.add(pProvider);
81-
s2cPayloads = generateS2CPacketInfoList();
91+
s2cPayloads = null;
8292
}
8393
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright (C) 2024 BlueLib Contributors
3+
*
4+
* This Source Code Form is subject to the terms of the MIT License.
5+
* If a copy of the MIT License was not distributed with this file,
6+
* You can obtain one at https://opensource.org/licenses/MIT.
7+
*/
8+
package software.bluelib.api.random;
9+
10+
import java.util.*;
11+
import org.jetbrains.annotations.ApiStatus;
12+
import org.jetbrains.annotations.NotNull;
13+
14+
/**
15+
* <b>WARNING:</b> <i>Still a massive Work in Progress.</i> <br>
16+
* A generic randomizer with a "hard pity" system layered on top of the standard pity randomization.
17+
* <p>
18+
* This class extends {@link PityRandom}, retaining all standard pity random behavior:
19+
* <ul>
20+
* <li>Each call to {@link #nextValue()} uses the pity system to weight less-picked values higher.</li>
21+
* <li>The hard pity threshold guarantees that after a specified number of attempts, the least-picked value will be selected.</li>
22+
* <li>The pity system may select the least-picked value <b>before</b> the hard pity threshold is reached.</li>
23+
* <li>When the hard pity is triggered, or (optionally) when the least-picked value is selected by the pity system, all selection counts can be reset (configurable).</li>
24+
* </ul>
25+
* <p>
26+
* <b>Supported types:</b>
27+
* <ul>
28+
* <li>Any type (T) provided as a collection of values</li>
29+
* <li>Convenience factory methods are available for common types such as Integer, Boolean, Float, and Double</li>
30+
* </ul>
31+
* <p>
32+
* <b>How it works:</b>
33+
* <ul>
34+
* <li>Each call to {@link #nextValue()} increments an attempt counter.</li>
35+
* <li>If the number of attempts reaches the hard pity threshold, the least-picked value is forcibly selected, and all selection counts are reset.</li>
36+
* <li>If the least-picked value is selected by the pity system before the threshold, selection counts may also be reset (if configured).</li>
37+
* <li>After a hard pity trigger or reset, the attempt counter is reset.</li>
38+
* </ul>
39+
* <p>
40+
* <b>Use cases:</b>
41+
* <ul>
42+
* <li>Ensures fairness by guaranteeing a rare outcome after repeated failures, while still allowing for early success via the pity system.</li>
43+
* <li>Useful for systems like loot boxes or gacha, where both randomness and guaranteed outcomes are desired.</li>
44+
* </ul>
45+
* <p>
46+
* <b>Parameters:</b>
47+
* <ul>
48+
* <li><code>hardPity</code>: The number of attempts after which the hard pity is triggered.</li>
49+
* <li><code>resetOnAnyPity</code> (if implemented): Whether to reset selection counts when the least-picked value is selected by the pity system before the hard pity threshold.</li>
50+
* </ul>
51+
*/
52+
@SuppressWarnings("unused")
53+
@ApiStatus.Experimental
54+
public class HardPityRandom<T> extends PityRandom<T> {
55+
56+
@NotNull
57+
private final Integer hardPity;
58+
@NotNull
59+
private Integer attempts = 0;
60+
61+
public HardPityRandom(@NotNull Collection<T> pValues, @NotNull Integer pHardPity) {
62+
super(pValues);
63+
this.hardPity = pHardPity;
64+
}
65+
66+
@NotNull
67+
public static HardPityRandom<Double> ofRange(@NotNull Double pMin, @NotNull Double pMax, @NotNull Double pStep) {
68+
return ofRange(pMin, pMax, pStep, pMax.intValue());
69+
}
70+
71+
@NotNull
72+
public static HardPityRandom<Double> ofRange(@NotNull Double pMax, @NotNull Double pStep, @NotNull Integer pHardPity) {
73+
return ofRange(0.0, pMax, pStep, pHardPity);
74+
}
75+
76+
@NotNull
77+
public static HardPityRandom<Double> ofRange(@NotNull Double pMax, @NotNull Double pStep) {
78+
return ofRange(0.0, pMax, pStep, pMax.intValue());
79+
}
80+
81+
@NotNull
82+
public static HardPityRandom<Double> ofRange(@NotNull Double pMin, @NotNull Double pMax, @NotNull Double pStep, @NotNull Integer pHardPity) {
83+
return new HardPityRandom<>(buildRange(pMin, pMax, pStep), pHardPity);
84+
}
85+
86+
@NotNull
87+
private static List<Double> buildRange(@NotNull Double pStart, @NotNull Double pEnd, @NotNull Double pStep) {
88+
List<Double> range = new ArrayList<>();
89+
for (double d = pStart; d <= pEnd + 1e-9; d += pStep) {
90+
range.add(Math.round(d * 1_000_000.0) / 1_000_000.0);
91+
}
92+
return range;
93+
}
94+
95+
@Override
96+
public @NotNull T nextValue() {
97+
attempts++;
98+
99+
if (hardPity > 0 && attempts >= hardPity) {
100+
attempts = 0;
101+
102+
T leastPicked = selectionCounts.entrySet().stream()
103+
.min(Comparator.comparingInt(Map.Entry::getValue))
104+
.map(Map.Entry::getKey)
105+
.orElse(values.getFirst());
106+
107+
selectionCounts.put(leastPicked, selectionCounts.get(leastPicked) + 1);
108+
resetCounts();
109+
return leastPicked;
110+
}
111+
112+
T value = super.nextValue();
113+
114+
int minCount = selectionCounts.values().stream().min(Integer::compareTo).orElse(0);
115+
116+
if (selectionCounts.get(value) == minCount + 1) {
117+
long stillMin = selectionCounts.values().stream().filter(c -> c == minCount).count();
118+
if (stillMin == 0) {
119+
resetCounts();
120+
attempts = 0;
121+
}
122+
}
123+
124+
return value;
125+
}
126+
}

0 commit comments

Comments
 (0)