summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--TODO.md4
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/Emc.java252
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java5
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyRegistry.java3
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java9
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java5
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/BufUtils.java20
-rw-r--r--src/main/java/lv/enes/mc/eris_alchemy/utils/PlayerUtils.java22
9 files changed, 209 insertions, 118 deletions
diff --git a/README.md b/README.md
deleted file mode 100644
index 34c9b35..0000000
--- a/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
1# Eris Alchemy
2
3## TODO
4
5- custom model for guide book
6
7When upgrading minecraft `grep` for `UPGRADE`, update content and bracketed version. \ No newline at end of file
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..97ca272
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,4 @@
1# TODO #
2
3- custom model for guide book
4- proper EmcLoader with separate prepare and apply stages \ No newline at end of file
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/Emc.java b/src/main/java/lv/enes/mc/eris_alchemy/Emc.java
index fdc7c0a..c12b143 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/Emc.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/Emc.java
@@ -1,11 +1,18 @@
1package lv.enes.mc.eris_alchemy; 1package lv.enes.mc.eris_alchemy;
2 2
3import jakarta.annotation.Nonnull;
4import jakarta.annotation.Nullable; 3import jakarta.annotation.Nullable;
4import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry.NetworkingConstants;
5import lv.enes.mc.eris_alchemy.utils.BufUtils;
5import lv.enes.mc.eris_alchemy.utils.ItemUtils; 6import lv.enes.mc.eris_alchemy.utils.ItemUtils;
7import lv.enes.mc.eris_alchemy.utils.PlayerUtils;
8import net.minecraft.client.Minecraft;
6import net.minecraft.core.registries.BuiltInRegistries; 9import net.minecraft.core.registries.BuiltInRegistries;
7import net.minecraft.core.registries.Registries; 10import net.minecraft.core.registries.Registries;
11import net.minecraft.network.FriendlyByteBuf;
8import net.minecraft.resources.ResourceLocation; 12import net.minecraft.resources.ResourceLocation;
13import net.minecraft.server.MinecraftServer;
14import net.minecraft.server.level.ServerLevel;
15import net.minecraft.server.level.ServerPlayer;
9import net.minecraft.tags.TagKey; 16import net.minecraft.tags.TagKey;
10import net.minecraft.world.item.BlockItem; 17import net.minecraft.world.item.BlockItem;
11import net.minecraft.world.item.Item; 18import net.minecraft.world.item.Item;
@@ -13,86 +20,37 @@ import net.minecraft.world.item.ItemStack;
13import net.minecraft.world.item.crafting.Ingredient; 20import net.minecraft.world.item.crafting.Ingredient;
14import net.minecraft.world.level.Level; 21import net.minecraft.world.level.Level;
15import net.minecraft.world.level.block.Block; 22import net.minecraft.world.level.block.Block;
23import org.quiltmc.loader.api.minecraft.ClientOnly;
24import org.quiltmc.qsl.networking.api.PacketByteBufs;
25import org.quiltmc.qsl.networking.api.ServerPlayNetworking;
26import org.quiltmc.qsl.networking.api.client.ClientPlayNetworking;
16 27
17import java.text.DecimalFormat; 28import java.text.DecimalFormat;
18import java.util.*; 29import java.util.*;
19import java.util.stream.Stream; 30import java.util.stream.Stream;
20 31
21public class Emc { 32public final class Emc {
33 private Emc() {}
34
22 private static final Map<ResourceLocation, OptionalDouble> ITEM_VALUES = new HashMap<>(); 35 private static final Map<ResourceLocation, OptionalDouble> ITEM_VALUES = new HashMap<>();
23 private static final Map<TagKey<Item>, OptionalDouble> ITEM_TAG_VALUES = new HashMap<>(); 36 private static final Map<TagKey<Item>, OptionalDouble> ITEM_TAG_VALUES = new HashMap<>();
24 private static final Map<TagKey<Block>, OptionalDouble> BLOCK_TAG_VALUES = new HashMap<>(); 37 private static final Map<TagKey<Block>, OptionalDouble> BLOCK_TAG_VALUES = new HashMap<>();
25 private static final List<SimplifiedRecipe> FAKE_RECIPES = new ArrayList<>(); 38 private static final List<SimplifiedRecipe> FAKE_RECIPES = new ArrayList<>();
26 39
27 private static final Map<Level, Emc> instances = Collections.synchronizedMap(new WeakHashMap<>()); 40 private static final Map<ResourceLocation, OptionalDouble> VALUES = Collections.synchronizedMap(new HashMap<>());
28 41
29 private static final DecimalFormat formatter = new DecimalFormat("0"); 42 private static final DecimalFormat FORMATTER = new DecimalFormat("0");
30 static { 43 static {
31 formatter.setMaximumFractionDigits(1); 44 FORMATTER.setMaximumFractionDigits(1);
32 } 45 }
33 46
34 public static Emc getInstance(@Nonnull Level world) { 47 private static ServerLevel overworld = null;
35 if (instances.containsKey(world)) {
36 return instances.get(world);
37 }
38
39 var instance = new Emc(world);
40 instances.put(world, instance);
41 return instance;
42 }
43 48
44 public static String formatEmc(double value) { 49 public static String formatEmc(double value) {
45 return formatter.format(value); 50 return FORMATTER.format(value);
46 } 51 }
47 52
48 public static void reloadData( 53 public static OptionalDouble get(ItemStack stack) {
49 Map<ResourceLocation, OptionalDouble> itemValues,
50 Map<ResourceLocation, OptionalDouble> itemTagValues,
51 Map<ResourceLocation, OptionalDouble> blockTagValues,
52 List<SimplifiedRecipe> fakeRecipes
53 ) {
54 ITEM_VALUES.clear();
55 ITEM_VALUES.putAll(itemValues);
56
57 ITEM_TAG_VALUES.clear();
58 itemTagValues.forEach((id, value) -> ITEM_TAG_VALUES.put(TagKey.create(Registries.ITEM, id), value));
59
60 BLOCK_TAG_VALUES.clear();
61 blockTagValues.forEach((id, value) -> BLOCK_TAG_VALUES.put(TagKey.create(Registries.BLOCK, id), value));
62
63 FAKE_RECIPES.clear();
64 FAKE_RECIPES.addAll(fakeRecipes);
65
66 instances.clear();
67 }
68
69 private final Map<ResourceLocation, OptionalDouble> data;
70
71 private Emc(@Nonnull Level world) {
72 data = Collections.synchronizedMap(new HashMap<>(ITEM_VALUES));
73 ITEM_TAG_VALUES.forEach(
74 (tag, emcValue) -> BuiltInRegistries.ITEM
75 .getTagOrEmpty(tag)
76 .forEach(holder -> data.putIfAbsent(ItemUtils.getId(holder), emcValue))
77 );
78 BLOCK_TAG_VALUES.forEach(
79 (tag, emcValue) -> BuiltInRegistries.BLOCK
80 .getTagOrEmpty(tag)
81 .forEach(holder -> data.putIfAbsent(ItemUtils.getId(holder), emcValue))
82 );
83
84 ErisAlchemy.LOGGER.info("Calculating EMC values...");
85 var recipes = getRecipes(world);
86 var configured = new HashSet<>(data.keySet());
87 BuiltInRegistries.ITEM.keySet().forEach(item -> {
88 configEmc(recipes, configured, item);
89 if (!data.containsKey(item)) {
90 ErisAlchemy.LOGGER.warn("No EMC value for '{}' known", item);
91 }
92 });
93 }
94
95 public OptionalDouble get(ItemStack stack) {
96 if (stack.isEmpty()) { 54 if (stack.isEmpty()) {
97 return OptionalDouble.empty(); 55 return OptionalDouble.empty();
98 } 56 }
@@ -118,51 +76,66 @@ public class Emc {
118 .findFirst(); 76 .findFirst();
119 } 77 }
120 78
121 public OptionalDouble get(ResourceLocation itemId) { 79 public static OptionalDouble get(ResourceLocation itemId) {
122 return data.getOrDefault(itemId, OptionalDouble.empty()); 80 return VALUES.getOrDefault(itemId, OptionalDouble.empty());
123 } 81 }
124 82
125 private List<SimplifiedRecipe> getRecipes(@Nullable Level world) { 83 @ClientOnly
126 Stream<SimplifiedRecipe> recipes = FAKE_RECIPES.stream(); 84 public static void initClient(Minecraft ignoredClient) {
85 ClientPlayNetworking.registerGlobalReceiver(
86 NetworkingConstants.UPDATE_EMCS,
87 (client1, handler, buf, responseSender) -> {
88 var map = buf.readMap(FriendlyByteBuf::readResourceLocation, BufUtils::readOptionalDouble);
89 VALUES.clear();
90 VALUES.putAll(map);
91 }
92 );
93 }
127 94
128 if (world != null) { 95 public static void initServer(MinecraftServer server) {
129 recipes = Stream.concat( 96 overworld = server.overworld();
130 recipes, 97 reinit();
131 world.getRecipeManager() 98 warnOfMissingValues();
132 .getRecipes() 99 }
133 .stream()
134 .map(recipe -> new SimplifiedRecipe(recipe, world.registryAccess()))
135 );
136 }
137 100
138 return recipes.toList(); 101 public static void reloadData(
102 Map<ResourceLocation, OptionalDouble> itemValues,
103 Map<ResourceLocation, OptionalDouble> itemTagValues,
104 Map<ResourceLocation, OptionalDouble> blockTagValues,
105 List<SimplifiedRecipe> fakeRecipes
106 ) {
107 ITEM_VALUES.clear();
108 ITEM_VALUES.putAll(itemValues);
109
110 ITEM_TAG_VALUES.clear();
111 itemTagValues.forEach((id, value) -> ITEM_TAG_VALUES.put(TagKey.create(Registries.ITEM, id), value));
112
113 BLOCK_TAG_VALUES.clear();
114 blockTagValues.forEach((id, value) -> BLOCK_TAG_VALUES.put(TagKey.create(Registries.BLOCK, id), value));
115
116 FAKE_RECIPES.clear();
117 FAKE_RECIPES.addAll(fakeRecipes);
118
119 reinit();
120 warnOfMissingValues();
139 } 121 }
140 122
141 private OptionalDouble configEmc( 123 private static OptionalDouble calculateEmcForIngredient(
142 List<SimplifiedRecipe> recipes, 124 List<SimplifiedRecipe> recipes,
143 Set<ResourceLocation> configured, 125 Set<ResourceLocation> configured,
144 ResourceLocation itemId 126 Ingredient ingredient
145 ) { 127 ) {
146 var res = get(itemId); 128 return Arrays.stream(ingredient.getItems())
147 if (res.isPresent() || configured.contains(itemId)) { 129 .map(stack -> configEmc(recipes, configured, ItemUtils.getId(stack.getItem())).stream()
148 return res; 130 .map(x -> x * stack.getCount())
149 } 131 .findFirst())
150 132 .filter(OptionalDouble::isPresent)
151 configured.add(itemId); 133 .mapToDouble(OptionalDouble::getAsDouble)
152 var item = BuiltInRegistries.ITEM.get(itemId); 134 .filter(x -> x > 0)
153 res = recipes.stream()
154 .filter(recipe -> recipe.output().is(item))
155 .map(recipe -> calculateEmcForRecipe(recipes, configured, recipe))
156 .flatMapToDouble(OptionalDouble::stream)
157 .average(); 135 .average();
158 res.ifPresentOrElse(
159 emc -> data.put(itemId, OptionalDouble.of(emc)),
160 () -> configured.remove(itemId)
161 );
162 return res;
163 } 136 }
164 137
165 private OptionalDouble calculateEmcForRecipe( 138 private static OptionalDouble calculateEmcForRecipe(
166 List<SimplifiedRecipe> recipes, 139 List<SimplifiedRecipe> recipes,
167 Set<ResourceLocation> configured, 140 Set<ResourceLocation> configured,
168 SimplifiedRecipe recipe 141 SimplifiedRecipe recipe
@@ -197,18 +170,87 @@ public class Emc {
197 } 170 }
198 } 171 }
199 172
200 private OptionalDouble calculateEmcForIngredient( 173 private static OptionalDouble configEmc(
201 List<SimplifiedRecipe> recipes, 174 List<SimplifiedRecipe> recipes,
202 Set<ResourceLocation> configured, 175 Set<ResourceLocation> configured,
203 Ingredient ingredient 176 ResourceLocation itemId
204 ) { 177 ) {
205 return Arrays.stream(ingredient.getItems()) 178 var res = get(itemId);
206 .map(stack -> configEmc(recipes, configured, ItemUtils.getId(stack.getItem())).stream() 179 if (res.isPresent() || configured.contains(itemId)) {
207 .map(x -> x * stack.getCount()) 180 return res;
208 .findFirst()) 181 }
209 .filter(OptionalDouble::isPresent) 182
210 .mapToDouble(OptionalDouble::getAsDouble) 183 configured.add(itemId);
211 .filter(x -> x > 0) 184 var item = BuiltInRegistries.ITEM.get(itemId);
185 res = recipes.stream()
186 .filter(recipe -> recipe.output().is(item))
187 .map(recipe -> calculateEmcForRecipe(recipes, configured, recipe))
188 .flatMapToDouble(OptionalDouble::stream)
212 .average(); 189 .average();
190 res.ifPresentOrElse(
191 emc -> VALUES.put(itemId, OptionalDouble.of(emc)),
192 () -> configured.remove(itemId)
193 );
194 return res;
195 }
196
197 private static List<SimplifiedRecipe> getRecipes(@Nullable Level world) {
198 Stream<SimplifiedRecipe> recipes = FAKE_RECIPES.stream();
199
200 if (world != null) {
201 recipes = Stream.concat(
202 recipes,
203 world.getRecipeManager()
204 .getRecipes()
205 .stream()
206 .map(recipe -> new SimplifiedRecipe(recipe, world.registryAccess()))
207 );
208 }
209
210 return recipes.toList();
211 }
212
213 private static void reinit() {
214 VALUES.clear();
215 VALUES.putAll(ITEM_VALUES);
216 ITEM_TAG_VALUES.forEach(
217 (tag, emcValue) -> BuiltInRegistries.ITEM
218 .getTagOrEmpty(tag)
219 .forEach(holder -> VALUES.putIfAbsent(ItemUtils.getId(holder), emcValue))
220 );
221 BLOCK_TAG_VALUES.forEach(
222 (tag, emcValue) -> BuiltInRegistries.BLOCK
223 .getTagOrEmpty(tag)
224 .forEach(holder -> VALUES.putIfAbsent(ItemUtils.getId(holder), emcValue))
225 );
226
227 ErisAlchemy.LOGGER.info("Calculating EMC values from recipes...");
228 var recipes = getRecipes(overworld);
229 var configured = new HashSet<>(VALUES.keySet());
230 BuiltInRegistries.ITEM.keySet().forEach(item -> configEmc(recipes, configured, item));
231
232 sync();
233 }
234
235 private static void sync() {
236 syncTo(PlayerUtils.all());
237 }
238
239 private static void syncTo(Collection<ServerPlayer> player) {
240 var buf = PacketByteBufs.create();
241 buf.writeMap(VALUES, FriendlyByteBuf::writeResourceLocation, BufUtils::writeOptionalDouble);
242 ServerPlayNetworking.send(player, NetworkingConstants.UPDATE_EMCS, buf);
243 }
244
245 private static void warnOfMissingValues() {
246 if (overworld == null) {
247 return;
248 }
249
250 BuiltInRegistries.ITEM
251 .keySet()
252 .stream()
253 .filter(item -> !VALUES.containsKey(item))
254 .forEach(item -> ErisAlchemy.LOGGER.warn("No EMC value for '{}' known", item));
213 } 255 }
214} 256}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
index bb84e18..1d363c2 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemy.java
@@ -2,6 +2,7 @@ package lv.enes.mc.eris_alchemy;
2 2
3import com.google.gson.Gson; 3import com.google.gson.Gson;
4import com.google.gson.GsonBuilder; 4import com.google.gson.GsonBuilder;
5import lv.enes.mc.eris_alchemy.utils.PlayerUtils;
5import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup; 6import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
6import net.minecraft.core.Registry; 7import net.minecraft.core.Registry;
7import net.minecraft.core.registries.BuiltInRegistries; 8import net.minecraft.core.registries.BuiltInRegistries;
@@ -12,6 +13,7 @@ import net.minecraft.world.item.CreativeModeTab;
12import net.minecraft.world.item.ItemStack; 13import net.minecraft.world.item.ItemStack;
13import org.quiltmc.loader.api.ModContainer; 14import org.quiltmc.loader.api.ModContainer;
14import org.quiltmc.qsl.base.api.entrypoint.ModInitializer; 15import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
16import org.quiltmc.qsl.lifecycle.api.event.ServerLifecycleEvents;
15import org.quiltmc.qsl.resource.loader.api.ResourceLoader; 17import org.quiltmc.qsl.resource.loader.api.ResourceLoader;
16import org.slf4j.Logger; 18import org.slf4j.Logger;
17import org.slf4j.LoggerFactory; 19import org.slf4j.LoggerFactory;
@@ -42,6 +44,9 @@ public class ErisAlchemy implements ModInitializer {
42 44
43 ResourceLoader.get(PackType.SERVER_DATA).registerReloader(EmcLoader.INSTANCE); 45 ResourceLoader.get(PackType.SERVER_DATA).registerReloader(EmcLoader.INSTANCE);
44 46
47 ServerLifecycleEvents.READY.register(Emc::initServer);
48 PlayerUtils.init();
49
45 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP); 50 Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(ID, "item_group"), ITEM_GROUP);
46 51
47 ErisAlchemyRegistry.BlockEntities.consume( 52 ErisAlchemyRegistry.BlockEntities.consume(
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyRegistry.java b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyRegistry.java
index 893e60d..e0f6e31 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyRegistry.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/ErisAlchemyRegistry.java
@@ -179,6 +179,9 @@ public final class ErisAlchemyRegistry {
179 public static final class NetworkingConstants { 179 public static final class NetworkingConstants {
180 private NetworkingConstants() {} 180 private NetworkingConstants() {}
181 181
182 public static final ResourceLocation UPDATE_EMCS
183 = new ResourceLocation(ErisAlchemy.ID, "update_emcs");
184
182 public static final ResourceLocation UPDATE_SYNCED_VALUE 185 public static final ResourceLocation UPDATE_SYNCED_VALUE
183 = new ResourceLocation(ErisAlchemy.ID, "update_synced_value"); 186 = new ResourceLocation(ErisAlchemy.ID, "update_synced_value");
184 } 187 }
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
index a264722..432ba6f 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/EnergyCondenserEntity.java
@@ -81,8 +81,8 @@ public class EnergyCondenserEntity extends ChestLikeEntity implements ExtendedSc
81 @Override 81 @Override
82 public void tick(Level world, BlockPos pos, BlockState state) { 82 public void tick(Level world, BlockPos pos, BlockState state) {
83 super.tick(world, pos, state); 83 super.tick(world, pos, state);
84 Emc.getInstance(world).get(items.get(0)).ifPresent(cost -> { 84 Emc.get(items.get(0)).ifPresent(cost -> {
85 tryConsumeEmc(world, cost); 85 tryConsumeEmc(cost);
86 tryCloneTemplate(cost); 86 tryCloneTemplate(cost);
87 }); 87 });
88 88
@@ -123,17 +123,16 @@ public class EnergyCondenserEntity extends ChestLikeEntity implements ExtendedSc
123 ); 123 );
124 } 124 }
125 125
126 private void tryConsumeEmc(Level world, double cost) { 126 private void tryConsumeEmc(double cost) {
127 if (cost <= getStoredEmc()) { 127 if (cost <= getStoredEmc()) {
128 return; 128 return;
129 } 129 }
130 130
131 var emc = Emc.getInstance(world);
132 var template = items.get(0); 131 var template = items.get(0);
133 var sacrifice = items.stream() 132 var sacrifice = items.stream()
134 .skip(1) // skip the template 133 .skip(1) // skip the template
135 .filter(stack -> !ItemStack.isSameItemSameTags(template, stack)) 134 .filter(stack -> !ItemStack.isSameItemSameTags(template, stack))
136 .flatMap(stack -> emc.get(stack) 135 .flatMap(stack -> Emc.get(stack)
137 .stream() 136 .stream()
138 .mapToObj(emcValue -> new StackEmcPair(stack, emcValue))) 137 .mapToObj(emcValue -> new StackEmcPair(stack, emcValue)))
139 .findFirst(); 138 .findFirst();
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
index f4de045..3e73c9e 100644
--- a/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
+++ b/src/main/java/lv/enes/mc/eris_alchemy/client/ErisAlchemyClient.java
@@ -7,6 +7,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
7import net.minecraft.network.chat.Component; 7import net.minecraft.network.chat.Component;
8import org.quiltmc.loader.api.ModContainer; 8import org.quiltmc.loader.api.ModContainer;
9import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer; 9import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer;
10import org.quiltmc.qsl.lifecycle.api.client.event.ClientLifecycleEvents;
10import org.quiltmc.qsl.tooltip.api.client.ItemTooltipCallback; 11import org.quiltmc.qsl.tooltip.api.client.ItemTooltipCallback;
11 12
12@SuppressWarnings("unused") 13@SuppressWarnings("unused")
@@ -17,12 +18,14 @@ public class ErisAlchemyClient implements ClientModInitializer {
17 ErisAlchemyClientRegistry.ItemRenderers.consume(BuiltinItemRendererRegistry.INSTANCE::register); 18 ErisAlchemyClientRegistry.ItemRenderers.consume(BuiltinItemRendererRegistry.INSTANCE::register);
18 ErisAlchemyClientRegistry.MenuScreens.consume(MenuScreens::register); 19 ErisAlchemyClientRegistry.MenuScreens.consume(MenuScreens::register);
19 20
21 ClientLifecycleEvents.READY.register(Emc::initClient);
22
20 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> { 23 ItemTooltipCallback.EVENT.register((stack, player, context, tooltip) -> {
21 if (player == null) { 24 if (player == null) {
22 return; 25 return;
23 } 26 }
24 27
25 var emc = Emc.getInstance(player.level()).get(stack); 28 var emc = Emc.get(stack);
26 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(Emc.formatEmc(value))))); 29 emc.ifPresent(value -> tooltip.add(Component.literal("EMC %s".formatted(Emc.formatEmc(value)))));
27 }); 30 });
28 } 31 }
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/BufUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/BufUtils.java
new file mode 100644
index 0000000..9d8fe82
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/BufUtils.java
@@ -0,0 +1,20 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import io.netty.buffer.ByteBuf;
4import net.minecraft.network.FriendlyByteBuf;
5
6import java.util.OptionalDouble;
7
8public final class BufUtils {
9 private BufUtils() {}
10
11 public static OptionalDouble readOptionalDouble(FriendlyByteBuf buf) {
12 return buf.readOptional(ByteBuf::readDouble).stream().mapToDouble(x -> x).findFirst();
13 }
14
15 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
16 public static void writeOptionalDouble(FriendlyByteBuf buf, OptionalDouble value) {
17 var convert = value.stream().boxed().findFirst();
18 buf.writeOptional(convert, ByteBuf::writeDoubleLE);
19 }
20}
diff --git a/src/main/java/lv/enes/mc/eris_alchemy/utils/PlayerUtils.java b/src/main/java/lv/enes/mc/eris_alchemy/utils/PlayerUtils.java
new file mode 100644
index 0000000..6320d6f
--- /dev/null
+++ b/src/main/java/lv/enes/mc/eris_alchemy/utils/PlayerUtils.java
@@ -0,0 +1,22 @@
1package lv.enes.mc.eris_alchemy.utils;
2
3import net.minecraft.server.level.ServerPlayer;
4import org.quiltmc.qsl.networking.api.ServerPlayConnectionEvents;
5
6import java.util.HashSet;
7import java.util.Set;
8
9public final class PlayerUtils {
10 private PlayerUtils() {}
11
12 private static final Set<ServerPlayer> ALL_PLAYERS = new HashSet<>();
13
14 public static Set<ServerPlayer> all() {
15 return ALL_PLAYERS;
16 }
17
18 public static void init() {
19 ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> ALL_PLAYERS.add(handler.getPlayer()));
20 ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> ALL_PLAYERS.remove(handler.getPlayer()));
21 }
22}