mirror of
https://github.com/architectury/architectury-api.git
synced 2026-03-28 03:56:59 -05:00
[ci skip] Port to NeoForge 24w14a
Signed-off-by: shedaniel <daniel@shedaniel.me>
This commit is contained in:
@@ -32,6 +32,14 @@ subprojects {
|
||||
|
||||
repositories {
|
||||
maven { url "https://maven.neoforged.net/releases/" }
|
||||
if (rootProject.neoforge_pr != "") {
|
||||
maven {
|
||||
url "https://prmaven.neoforged.net/NeoForge/pr$rootProject.neoforge_pr"
|
||||
content {
|
||||
includeModule("net.neoforged", "neoforge")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ public interface LootEvent {
|
||||
*
|
||||
* <h2>Example: adding diamonds as a drop for dirt</h2>
|
||||
* <pre>{@code
|
||||
* LootEvent.MODIFY_LOOT_TABLE.register((lootTables, id, context, builtin) -> {
|
||||
* LootEvent.MODIFY_LOOT_TABLE.register((key, context, builtin) -> {
|
||||
* // Check that the loot table is dirt and built-in
|
||||
* if (builtin && Blocks.DIRT.getLootTable().equals(id)) {
|
||||
* if (builtin && Blocks.DIRT.getLootTable().equals(key)) {
|
||||
* // Create a loot pool with a single item entry of Items.DIAMOND
|
||||
* LootPool.Builder pool = LootPool.lootPool().add(LootItem.lootTableItem(Items.DIAMOND));
|
||||
* context.addPool(pool);
|
||||
@@ -58,7 +58,7 @@ public interface LootEvent {
|
||||
*
|
||||
* @see ModifyLootTable#modifyLootTable(ResourceKey, LootTableModificationContext, boolean)
|
||||
*/
|
||||
// Event<ModifyLootTable> MODIFY_LOOT_TABLE = EventFactory.createLoop();
|
||||
Event<ModifyLootTable> MODIFY_LOOT_TABLE = EventFactory.createLoop();
|
||||
|
||||
@FunctionalInterface
|
||||
interface ModifyLootTable {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package dev.architectury.fluid;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.mojang.serialization.Codec;
|
||||
import dev.architectury.hooks.fluid.FluidStackHooks;
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
@@ -35,7 +34,8 @@ import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -66,100 +66,6 @@ public final class FluidStack implements DataComponentHolder {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataComponentMap getComponents() {
|
||||
return new DataComponentMap() {
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T get(DataComponentType<? extends T> type) {
|
||||
return getPatch().get(type).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<DataComponentType<?>> keySet() {
|
||||
return new AbstractSet<>() {
|
||||
@Override
|
||||
public Iterator<DataComponentType<?>> iterator() {
|
||||
return Iterators.transform(getPatch().entrySet().iterator(), Map.Entry::getKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return getPatch().entrySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (!(o instanceof DataComponentType<?> type)) return false;
|
||||
return getPatch().get(type).isPresent();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public <T> T set(DataComponentType<? super T> dataComponentType, @Nullable T object) {
|
||||
T previous = (T) get(dataComponentType);
|
||||
DataComponentPatch.Builder builder = DataComponentPatch.builder();
|
||||
for (TypedDataComponent<?> component : getComponents()) {
|
||||
if (component.type() != dataComponentType) {
|
||||
builder.set(component);
|
||||
}
|
||||
}
|
||||
if (object != null) {
|
||||
builder.set(dataComponentType, object);
|
||||
}
|
||||
setPatch(builder.build());
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T, U> T update(DataComponentType<T> dataComponentType, T object, U object2, BiFunction<T, U, T> biFunction) {
|
||||
return this.set(dataComponentType, biFunction.apply(this.getOrDefault(dataComponentType, object), object2));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T update(DataComponentType<T> dataComponentType, T object, UnaryOperator<T> unaryOperator) {
|
||||
return this.set(dataComponentType, unaryOperator.apply(this.getOrDefault(dataComponentType, object)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T remove(DataComponentType<? extends T> dataComponentType) {
|
||||
return this.set(dataComponentType, null);
|
||||
}
|
||||
|
||||
public void applyComponents(DataComponentPatch dataComponentPatch) {
|
||||
DataComponentPatch.Builder builder = DataComponentPatch.builder();
|
||||
for (TypedDataComponent<?> component : getComponents()) {
|
||||
builder.set(component);
|
||||
}
|
||||
for (Map.Entry<DataComponentType<?>, Optional<?>> entry : dataComponentPatch.entrySet()) {
|
||||
if (entry.getValue().isPresent()) {
|
||||
//noinspection rawtypes
|
||||
builder.set((DataComponentType) entry.getKey(), entry.getValue().get());
|
||||
} else {
|
||||
builder.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
setPatch(builder.build());
|
||||
}
|
||||
|
||||
public void applyComponents(DataComponentMap dataComponentMap) {
|
||||
DataComponentPatch.Builder builder = DataComponentPatch.builder();
|
||||
for (TypedDataComponent<?> component : getComponents()) {
|
||||
builder.set(component);
|
||||
}
|
||||
for (TypedDataComponent<?> entry : dataComponentMap) {
|
||||
if (entry.value() != null) {
|
||||
//noinspection rawtypes
|
||||
builder.set((DataComponentType) entry.type(), entry.value());
|
||||
} else {
|
||||
builder.remove(entry.type());
|
||||
}
|
||||
}
|
||||
setPatch(builder.build());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public interface FluidStackAdapter<T> {
|
||||
T create(Supplier<Fluid> fluid, long amount, @Nullable DataComponentPatch patch);
|
||||
@@ -174,7 +80,19 @@ public final class FluidStack implements DataComponentHolder {
|
||||
|
||||
DataComponentPatch getPatch(T value);
|
||||
|
||||
void setPatch(T value, DataComponentPatch patch);
|
||||
PatchedDataComponentMap getComponents(T value);
|
||||
|
||||
void applyComponents(T value, DataComponentPatch patch);
|
||||
|
||||
void applyComponents(T value, DataComponentMap patch);
|
||||
|
||||
@Nullable <D> D set(T value, DataComponentType<? super D> type, @Nullable D component);
|
||||
|
||||
@Nullable <D> D remove(T value, DataComponentType<? extends D> type);
|
||||
|
||||
@Nullable <D> D update(T value, DataComponentType<D> type, D component, UnaryOperator<D> updater);
|
||||
|
||||
@Nullable <D, U> D update(T value, DataComponentType<D> type, D component, U updateContext, BiFunction<D, U, D> updater);
|
||||
|
||||
T copy(T value);
|
||||
|
||||
@@ -260,8 +178,37 @@ public final class FluidStack implements DataComponentHolder {
|
||||
return ADAPTER.getPatch(value);
|
||||
}
|
||||
|
||||
public void setPatch(DataComponentPatch patch) {
|
||||
ADAPTER.setPatch(value, patch);
|
||||
@Override
|
||||
public PatchedDataComponentMap getComponents() {
|
||||
return ADAPTER.getComponents(value);
|
||||
}
|
||||
|
||||
public void applyComponents(DataComponentPatch patch) {
|
||||
ADAPTER.applyComponents(value, patch);
|
||||
}
|
||||
|
||||
public void applyComponents(DataComponentMap patch) {
|
||||
ADAPTER.applyComponents(value, patch);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T set(DataComponentType<? super T> type, @Nullable T component) {
|
||||
return ADAPTER.set(value, type, component);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T remove(DataComponentType<? extends T> type) {
|
||||
return ADAPTER.remove(value, type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T update(DataComponentType<T> type, T component, UnaryOperator<T> updater) {
|
||||
return ADAPTER.update(value, type, component, updater);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T, U> T update(DataComponentType<T> type, T component, U updateContext, BiFunction<T, U, T> updater) {
|
||||
return ADAPTER.update(value, type, component, updateContext, updater);
|
||||
}
|
||||
|
||||
public Component getName() {
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.impl;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.transformers.PacketSink;
|
||||
import dev.architectury.networking.transformers.PacketTransformer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class NetworkAggregator {
|
||||
public static final Supplier<Adaptor> ADAPTOR = Suppliers.memoize(() -> {
|
||||
try {
|
||||
Method adaptor = NetworkManager.class.getDeclaredMethod("getAdaptor");
|
||||
adaptor.setAccessible(true);
|
||||
return (Adaptor) adaptor.invoke(null);
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
});
|
||||
public static final Map<ResourceLocation, CustomPacketPayload.Type<BufCustomPacketPayload>> C2S_TYPE = new HashMap<>();
|
||||
public static final Map<ResourceLocation, CustomPacketPayload.Type<BufCustomPacketPayload>> S2C_TYPE = new HashMap<>();
|
||||
public static final Map<ResourceLocation, NetworkManager.NetworkReceiver<?>> C2S_RECEIVER = new HashMap<>();
|
||||
public static final Map<ResourceLocation, NetworkManager.NetworkReceiver<?>> S2C_RECEIVER = new HashMap<>();
|
||||
public static final Map<ResourceLocation, StreamCodec<ByteBuf, ?>> C2S_CODECS = new HashMap<>();
|
||||
public static final Map<ResourceLocation, StreamCodec<ByteBuf, ?>> S2C_CODECS = new HashMap<>();
|
||||
public static final Map<ResourceLocation, PacketTransformer> C2S_TRANSFORMERS = new HashMap<>();
|
||||
public static final Map<ResourceLocation, PacketTransformer> S2C_TRANSFORMERS = new HashMap<>();
|
||||
|
||||
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkManager.NetworkReceiver<RegistryFriendlyByteBuf> receiver) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = new CustomPacketPayload.Type<>(id);
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
C2S_TYPE.put(id, type);
|
||||
registerC2SReceiver(type, BufCustomPacketPayload.streamCodec(type), packetTransformers, (value, context) -> {
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(value.payload()), context.registryAccess());
|
||||
receiver.receive(buf, context);
|
||||
buf.release();
|
||||
});
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
S2C_TYPE.put(id, type);
|
||||
registerS2CReceiver(type, BufCustomPacketPayload.streamCodec(type), packetTransformers, (value, context) -> {
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(value.payload()), context.registryAccess());
|
||||
receiver.receive(buf, context);
|
||||
buf.release();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void registerReceiver(NetworkManager.Side side, CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers, NetworkManager.NetworkReceiver<T> receiver) {
|
||||
Objects.requireNonNull(type, "Cannot register receiver with a null type!");
|
||||
packetTransformers = Objects.requireNonNullElse(packetTransformers, List.of());
|
||||
Objects.requireNonNull(receiver, "Cannot register a null receiver!");
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
registerC2SReceiver(type, codec, packetTransformers, receiver);
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
registerS2CReceiver(type, codec, packetTransformers, receiver);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends CustomPacketPayload> void registerC2SReceiver(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers, NetworkManager.NetworkReceiver<T> receiver) {
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
C2S_RECEIVER.put(type.id(), receiver);
|
||||
C2S_CODECS.put(type.id(), (StreamCodec<ByteBuf, ?>) codec);
|
||||
C2S_TRANSFORMERS.put(type.id(), transformer);
|
||||
ADAPTOR.get().registerC2S((CustomPacketPayload.Type<BufCustomPacketPayload>) type, BufCustomPacketPayload.streamCodec((CustomPacketPayload.Type<BufCustomPacketPayload>) type), (payload, context) -> {
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(payload.payload()), context.registryAccess());
|
||||
transformer.inbound(NetworkManager.Side.C2S, type.id(), buf, context, (side, id1, buf1) -> {
|
||||
NetworkManager.NetworkReceiver<T> networkReceiver = (NetworkManager.NetworkReceiver<T>) (side == NetworkManager.Side.C2S ? C2S_RECEIVER.get(id1) : S2C_RECEIVER.get(id1));
|
||||
if (networkReceiver == null) {
|
||||
throw new IllegalArgumentException("Network Receiver not found! " + id1);
|
||||
}
|
||||
T actualPayload = codec.decode(buf1);
|
||||
networkReceiver.receive(actualPayload, context);
|
||||
});
|
||||
buf.release();
|
||||
});
|
||||
}
|
||||
|
||||
private static <T extends CustomPacketPayload> void registerS2CReceiver(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers, NetworkManager.NetworkReceiver<T> receiver) {
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
S2C_RECEIVER.put(type.id(), receiver);
|
||||
S2C_CODECS.put(type.id(), (StreamCodec<ByteBuf, ?>) codec);
|
||||
S2C_TRANSFORMERS.put(type.id(), transformer);
|
||||
ADAPTOR.get().registerS2C((CustomPacketPayload.Type<BufCustomPacketPayload>) type, BufCustomPacketPayload.streamCodec((CustomPacketPayload.Type<BufCustomPacketPayload>) type), (payload, context) -> {
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(payload.payload()), context.registryAccess());
|
||||
transformer.inbound(NetworkManager.Side.S2C, type.id(), buf, context, (side, id1, buf1) -> {
|
||||
NetworkManager.NetworkReceiver<T> networkReceiver = (NetworkManager.NetworkReceiver<T>) (side == NetworkManager.Side.C2S ? C2S_RECEIVER.get(id1) : S2C_RECEIVER.get(id1));
|
||||
if (networkReceiver == null) {
|
||||
throw new IllegalArgumentException("Network Receiver not found! " + id1);
|
||||
}
|
||||
T actualPayload = codec.decode(buf1);
|
||||
networkReceiver.receive(actualPayload, context);
|
||||
});
|
||||
buf.release();
|
||||
});
|
||||
}
|
||||
|
||||
public static void collectPackets(PacketSink sink, NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
collectPackets(sink, side, new BufCustomPacketPayload(C2S_TYPE.get(id), ByteBufUtil.getBytes(buf)), buf.registryAccess());
|
||||
} else {
|
||||
collectPackets(sink, side, new BufCustomPacketPayload(S2C_TYPE.get(id), ByteBufUtil.getBytes(buf)), buf.registryAccess());
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void collectPackets(PacketSink sink, NetworkManager.Side side, T payload, RegistryAccess access) {
|
||||
CustomPacketPayload.Type<T> type = (CustomPacketPayload.Type<T>) payload.type();
|
||||
PacketTransformer transformer = side == NetworkManager.Side.C2S ? C2S_TRANSFORMERS.get(type.id()) : S2C_TRANSFORMERS.get(type.id());
|
||||
StreamCodec<ByteBuf, T> codec = (StreamCodec<ByteBuf, T>) (side == NetworkManager.Side.C2S ? C2S_CODECS.get(type.id()) : S2C_CODECS.get(type.id()));
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), access);
|
||||
codec.encode(buf, payload);
|
||||
|
||||
if (transformer != null) {
|
||||
transformer.outbound(side, type.id(), buf, (side1, id1, buf1) -> {
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type1 = C2S_TYPE.getOrDefault(id1, (CustomPacketPayload.Type<BufCustomPacketPayload>) type);
|
||||
sink.accept(toPacket(side1, new BufCustomPacketPayload(type1, ByteBufUtil.getBytes(buf1))));
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type1 = S2C_TYPE.getOrDefault(id1, (CustomPacketPayload.Type<BufCustomPacketPayload>) type);
|
||||
sink.accept(toPacket(side1, new BufCustomPacketPayload(type1, ByteBufUtil.getBytes(buf1))));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sink.accept(toPacket(side, new BufCustomPacketPayload((CustomPacketPayload.Type<BufCustomPacketPayload>) type, ByteBufUtil.getBytes(buf))));
|
||||
}
|
||||
buf.release();
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> Packet<?> toPacket(NetworkManager.Side side, T payload) {
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
return ADAPTOR.get().toC2SPacket(payload);
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
return ADAPTOR.get().toS2CPacket(payload);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid side: " + side);
|
||||
}
|
||||
|
||||
public static void registerS2CType(ResourceLocation id, List<PacketTransformer> packetTransformers) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = new CustomPacketPayload.Type<>(id);
|
||||
S2C_TYPE.put(id, type);
|
||||
registerS2CType(type, BufCustomPacketPayload.streamCodec(type), packetTransformers);
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void registerS2CType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers) {
|
||||
Objects.requireNonNull(type, "Cannot register a null type!");
|
||||
packetTransformers = Objects.requireNonNullElse(packetTransformers, List.of());
|
||||
S2C_CODECS.put(type.id(), (StreamCodec<ByteBuf, ?>) codec);
|
||||
S2C_TRANSFORMERS.put(type.id(), PacketTransformer.concat(packetTransformers));
|
||||
ADAPTOR.get().registerS2CType((CustomPacketPayload.Type<BufCustomPacketPayload>) type, BufCustomPacketPayload.streamCodec((CustomPacketPayload.Type<BufCustomPacketPayload>) type));
|
||||
}
|
||||
|
||||
public interface Adaptor {
|
||||
<T extends CustomPacketPayload> void registerC2S(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkManager.NetworkReceiver<T> receiver);
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
<T extends CustomPacketPayload> void registerS2C(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkManager.NetworkReceiver<T> receiver);
|
||||
|
||||
<T extends CustomPacketPayload> Packet<?> toC2SPacket(T payload);
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
<T extends CustomPacketPayload> Packet<?> toS2CPacket(T payload);
|
||||
|
||||
<T extends CustomPacketPayload> void registerS2CType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec);
|
||||
}
|
||||
|
||||
public record BufCustomPacketPayload(Type<BufCustomPacketPayload> _type,
|
||||
byte[] payload) implements CustomPacketPayload {
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return this._type();
|
||||
}
|
||||
|
||||
public static StreamCodec<ByteBuf, BufCustomPacketPayload> streamCodec(Type<BufCustomPacketPayload> type) {
|
||||
return ByteBufCodecs.BYTE_ARRAY.map(bytes -> new BufCustomPacketPayload(type, bytes), BufCustomPacketPayload::payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,16 @@ import io.netty.buffer.Unpooled;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
@@ -60,7 +64,7 @@ public final class NetworkChannel {
|
||||
var s = UUID.nameUUIDFromBytes(type.getName().getBytes(StandardCharsets.UTF_8)).toString().replace("-", "");
|
||||
var info = new MessageInfo<T>(new ResourceLocation(id + "/" + s), encoder, decoder, messageConsumer);
|
||||
encoders.put(type, info);
|
||||
NetworkManager.NetworkReceiver receiver = (buf, context) -> {
|
||||
NetworkManager.NetworkReceiver<RegistryFriendlyByteBuf> receiver = (buf, context) -> {
|
||||
info.messageConsumer.accept(info.decoder.apply(buf), () -> context);
|
||||
};
|
||||
NetworkManager.registerReceiver(NetworkManager.c2s(), info.packetId, receiver);
|
||||
@@ -78,19 +82,21 @@ public final class NetworkChannel {
|
||||
return h;
|
||||
}
|
||||
|
||||
public <T> Packet<?> toPacket(NetworkManager.Side side, T message) {
|
||||
public <T> Packet<?> toPacket(NetworkManager.Side side, T message, RegistryAccess access) {
|
||||
var messageInfo = (MessageInfo<T>) Objects.requireNonNull(encoders.get(message.getClass()), "Unknown message type! " + message);
|
||||
var buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
var buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), access);
|
||||
messageInfo.encoder.accept(message, buf);
|
||||
return NetworkManager.toPacket(side, messageInfo.packetId, buf);
|
||||
}
|
||||
|
||||
public <T> void sendToPlayer(ServerPlayer player, T message) {
|
||||
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(toPacket(NetworkManager.s2c(), message));
|
||||
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(toPacket(NetworkManager.s2c(), message, player.registryAccess()));
|
||||
}
|
||||
|
||||
public <T> void sendToPlayers(Iterable<ServerPlayer> players, T message) {
|
||||
var packet = toPacket(NetworkManager.s2c(), message);
|
||||
Iterator<ServerPlayer> iterator = players.iterator();
|
||||
if (!iterator.hasNext()) return;
|
||||
var packet = toPacket(NetworkManager.s2c(), message, iterator.next().registryAccess());
|
||||
for (var player : players) {
|
||||
Objects.requireNonNull(player, "Unable to send packet to a 'null' player!").connection.send(packet);
|
||||
}
|
||||
@@ -98,8 +104,9 @@ public final class NetworkChannel {
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public <T> void sendToServer(T message) {
|
||||
if (Minecraft.getInstance().getConnection() != null) {
|
||||
Minecraft.getInstance().getConnection().send(toPacket(NetworkManager.c2s(), message));
|
||||
ClientPacketListener connection = Minecraft.getInstance().getConnection();
|
||||
if (connection != null) {
|
||||
connection.send(toPacket(NetworkManager.c2s(), message, connection.registryAccess()));
|
||||
} else {
|
||||
throw new IllegalStateException("Unable to send packet to the server while not in game!");
|
||||
}
|
||||
|
||||
@@ -19,16 +19,22 @@
|
||||
|
||||
package dev.architectury.networking;
|
||||
|
||||
import dev.architectury.impl.NetworkAggregator;
|
||||
import dev.architectury.injectables.annotations.ExpectPlatform;
|
||||
import dev.architectury.networking.transformers.PacketCollector;
|
||||
import dev.architectury.networking.transformers.PacketSink;
|
||||
import dev.architectury.networking.transformers.PacketTransformer;
|
||||
import dev.architectury.networking.transformers.SinglePacketCollector;
|
||||
import dev.architectury.utils.Env;
|
||||
import dev.architectury.utils.GameInstance;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -37,53 +43,112 @@ import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public final class NetworkManager {
|
||||
public static void registerReceiver(Side side, ResourceLocation id, NetworkReceiver receiver) {
|
||||
/**
|
||||
* For S2C types, {@link #registerReceiver} should be called on the client side,
|
||||
* while {@link #registerS2CPayloadType} should be called on the server side.
|
||||
*/
|
||||
public static void registerS2CPayloadType(ResourceLocation id) {
|
||||
NetworkAggregator.registerS2CType(id, List.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* For S2C types, {@link #registerReceiver} should be called on the client side,
|
||||
* while {@link #registerS2CPayloadType} should be called on the server side.
|
||||
*/
|
||||
public static <T extends CustomPacketPayload> void registerS2CPayloadType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec) {
|
||||
NetworkAggregator.registerS2CType(type, codec, List.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* For S2C types, {@link #registerReceiver} should be called on the client side,
|
||||
* while {@link #registerS2CPayloadType} should be called on the server side.
|
||||
*/
|
||||
public static void registerS2CPayloadType(ResourceLocation id, List<PacketTransformer> packetTransformers) {
|
||||
NetworkAggregator.registerS2CType(id, packetTransformers);
|
||||
}
|
||||
|
||||
/**
|
||||
* For S2C types, {@link #registerReceiver} should be called on the client side,
|
||||
* while {@link #registerS2CPayloadType} should be called on the server side.
|
||||
*/
|
||||
public static <T extends CustomPacketPayload> void registerS2CPayloadType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers) {
|
||||
NetworkAggregator.registerS2CType(type, codec, packetTransformers);
|
||||
}
|
||||
|
||||
public static void registerReceiver(Side side, ResourceLocation id, NetworkReceiver<RegistryFriendlyByteBuf> receiver) {
|
||||
registerReceiver(side, id, Collections.emptyList(), receiver);
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
@ApiStatus.Experimental
|
||||
public static void registerReceiver(Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
throw new AssertionError();
|
||||
public static void registerReceiver(Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver<RegistryFriendlyByteBuf> receiver) {
|
||||
NetworkAggregator.registerReceiver(side, id, packetTransformers, receiver);
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void registerReceiver(Side side, CustomPacketPayload.Type<T> id, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkReceiver<T> receiver) {
|
||||
registerReceiver(side, id, codec, Collections.emptyList(), receiver);
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static <T extends CustomPacketPayload> void registerReceiver(Side side, CustomPacketPayload.Type<T> id, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, List<PacketTransformer> packetTransformers, NetworkReceiver<T> receiver) {
|
||||
NetworkAggregator.registerReceiver(side, id, codec, packetTransformers, receiver);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static Packet<?> toPacket(Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
public static Packet<?> toPacket(Side side, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
SinglePacketCollector sink = new SinglePacketCollector(null);
|
||||
collectPackets(sink, side, id, buf);
|
||||
return sink.getPacket();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static List<Packet<?>> toPackets(Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
public static List<Packet<?>> toPackets(Side side, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
PacketCollector sink = new PacketCollector(null);
|
||||
collectPackets(sink, side, id, buf);
|
||||
return sink.collect();
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
public static void collectPackets(PacketSink sink, Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
throw new AssertionError();
|
||||
public static void collectPackets(PacketSink sink, Side side, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
NetworkAggregator.collectPackets(sink, side, id, buf);
|
||||
}
|
||||
|
||||
public static void sendToPlayer(ServerPlayer player, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
public static <T extends CustomPacketPayload> void collectPackets(PacketSink sink, Side side, T payload, RegistryAccess access) {
|
||||
NetworkAggregator.collectPackets(sink, side, payload, access);
|
||||
}
|
||||
|
||||
public static void sendToPlayer(ServerPlayer player, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
collectPackets(PacketSink.ofPlayer(player), serverToClient(), id, buf);
|
||||
}
|
||||
|
||||
public static void sendToPlayers(Iterable<ServerPlayer> players, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
public static void sendToPlayers(Iterable<ServerPlayer> players, ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
collectPackets(PacketSink.ofPlayers(players), serverToClient(), id, buf);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static void sendToServer(ResourceLocation id, FriendlyByteBuf buf) {
|
||||
public static void sendToServer(ResourceLocation id, RegistryFriendlyByteBuf buf) {
|
||||
collectPackets(PacketSink.client(), clientToServer(), id, buf);
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void sendToPlayer(ServerPlayer player, T payload) {
|
||||
collectPackets(PacketSink.ofPlayer(player), serverToClient(), payload, player.registryAccess());
|
||||
}
|
||||
|
||||
public static <T extends CustomPacketPayload> void sendToPlayers(Iterable<ServerPlayer> players, T payload) {
|
||||
Iterator<ServerPlayer> iterator = players.iterator();
|
||||
if (!iterator.hasNext()) return;
|
||||
collectPackets(PacketSink.ofPlayers(players), serverToClient(), payload, iterator.next().registryAccess());
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static <T extends CustomPacketPayload> void sendToServer(T payload) {
|
||||
ClientPacketListener connection = GameInstance.getClient().getConnection();
|
||||
if (connection == null) return;
|
||||
collectPackets(PacketSink.client(), clientToServer(), payload, connection.registryAccess());
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@ExpectPlatform
|
||||
public static boolean canServerReceive(ResourceLocation id) {
|
||||
@@ -112,9 +177,14 @@ public final class NetworkManager {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@ExpectPlatform
|
||||
private static NetworkAggregator.Adaptor getAdaptor() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface NetworkReceiver {
|
||||
void receive(FriendlyByteBuf buf, PacketContext context);
|
||||
public interface NetworkReceiver<T> {
|
||||
void receive(T value, PacketContext context);
|
||||
}
|
||||
|
||||
public interface PacketContext {
|
||||
@@ -124,6 +194,8 @@ public final class NetworkManager {
|
||||
|
||||
Env getEnvironment();
|
||||
|
||||
RegistryAccess registryAccess();
|
||||
|
||||
default EnvType getEnv() {
|
||||
return getEnvironment().toPlatform();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -41,7 +42,7 @@ public class SpawnEntityPacket {
|
||||
if (entity.level().isClientSide()) {
|
||||
throw new IllegalStateException("SpawnPacketUtil.create called on the logical client!");
|
||||
}
|
||||
var buffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
var buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), entity.registryAccess());
|
||||
buffer.writeVarInt(BuiltInRegistries.ENTITY_TYPE.getId(entity.getType()));
|
||||
buffer.writeUUID(entity.getUUID());
|
||||
buffer.writeVarInt(entity.getId());
|
||||
@@ -62,6 +63,10 @@ public class SpawnEntityPacket {
|
||||
return (Packet<ClientGamePacketListener>) NetworkManager.toPacket(NetworkManager.s2c(), PACKET_ID, buffer);
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
NetworkManager.registerS2CPayloadType(PACKET_ID);
|
||||
}
|
||||
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static class Client {
|
||||
|
||||
@@ -33,7 +33,7 @@ public abstract class BaseC2SMessage extends Message {
|
||||
@Environment(EnvType.CLIENT)
|
||||
public final void sendToServer() {
|
||||
if (Minecraft.getInstance().getConnection() != null) {
|
||||
Minecraft.getInstance().getConnection().send(toPacket());
|
||||
Minecraft.getInstance().getConnection().send(toPacket(Minecraft.getInstance().level.registryAccess()));
|
||||
} else {
|
||||
throw new IllegalStateException("Unable to send packet to the server while not in game!");
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public abstract class BaseS2CMessage extends Message {
|
||||
* @param player the player
|
||||
*/
|
||||
public final void sendTo(ServerPlayer player) {
|
||||
sendTo(player, toPacket());
|
||||
sendTo(player, toPacket(player.registryAccess()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,8 @@ public abstract class BaseS2CMessage extends Message {
|
||||
* @param players the players
|
||||
*/
|
||||
public final void sendTo(Iterable<ServerPlayer> players) {
|
||||
Packet<?> packet = toPacket();
|
||||
if (!players.iterator().hasNext()) return;
|
||||
Packet<?> packet = toPacket(players.iterator().next().registryAccess());
|
||||
|
||||
for (ServerPlayer player : players) {
|
||||
sendTo(player, packet);
|
||||
@@ -84,7 +85,7 @@ public abstract class BaseS2CMessage extends Message {
|
||||
* @param chunk the listened chunk
|
||||
*/
|
||||
public final void sendToChunkListeners(LevelChunk chunk) {
|
||||
Packet<?> packet = toPacket();
|
||||
Packet<?> packet = toPacket(chunk.getLevel().registryAccess());
|
||||
((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(chunk.getPos(), false).forEach(e -> sendTo(e, packet));
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,8 @@ package dev.architectury.networking.simple;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
/**
|
||||
@@ -48,7 +49,7 @@ public abstract class Message {
|
||||
*
|
||||
* @param buf the byte buffer
|
||||
*/
|
||||
public abstract void write(FriendlyByteBuf buf);
|
||||
public abstract void write(RegistryFriendlyByteBuf buf);
|
||||
|
||||
/**
|
||||
* Handles this message when it is received.
|
||||
@@ -62,8 +63,8 @@ public abstract class Message {
|
||||
*
|
||||
* @return the converted {@link Packet}
|
||||
*/
|
||||
public final Packet<?> toPacket() {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
public final Packet<?> toPacket(RegistryAccess access) {
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), access);
|
||||
write(buf);
|
||||
return NetworkManager.toPacket(getType().getSide(), getType().getId(), buf);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
package dev.architectury.networking.simple;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
|
||||
/**
|
||||
* Decodes a {@link Message} from a {@link FriendlyByteBuf}.
|
||||
* Decodes a {@link Message} from a {@link RegistryFriendlyByteBuf}.
|
||||
*
|
||||
* @param <T> the message type handled by this decoder
|
||||
* @author LatvianModder
|
||||
@@ -36,17 +36,17 @@ public interface MessageDecoder<T extends Message> {
|
||||
* @param buf the byte buffer
|
||||
* @return the decoded instance
|
||||
*/
|
||||
T decode(FriendlyByteBuf buf);
|
||||
T decode(RegistryFriendlyByteBuf buf);
|
||||
|
||||
/**
|
||||
* Creates a network receiver from this decoder.
|
||||
*
|
||||
* <p>The returned receiver will first {@linkplain #decode(FriendlyByteBuf) decode a message}
|
||||
* <p>The returned receiver will first {@linkplain #decode(RegistryFriendlyByteBuf) decode a message}
|
||||
* and then call {@link Message#handle(NetworkManager.PacketContext)} on the decoded message.
|
||||
*
|
||||
* @return the created receiver
|
||||
*/
|
||||
default NetworkManager.NetworkReceiver createReceiver() {
|
||||
default NetworkManager.NetworkReceiver<RegistryFriendlyByteBuf> createReceiver() {
|
||||
return (buf, context) -> {
|
||||
Message packet = decode(buf);
|
||||
context.queue(() -> packet.handle(context));
|
||||
|
||||
@@ -23,6 +23,7 @@ import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.transformers.PacketTransformer;
|
||||
import dev.architectury.platform.Platform;
|
||||
import dev.architectury.utils.Env;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@@ -77,7 +78,7 @@ public class SimpleNetworkManager {
|
||||
MessageType messageType = new MessageType(this, new ResourceLocation(namespace, id), NetworkManager.s2c());
|
||||
|
||||
if (Platform.getEnvironment() == Env.CLIENT) {
|
||||
NetworkManager.NetworkReceiver receiver = decoder.createReceiver();
|
||||
NetworkManager.NetworkReceiver<RegistryFriendlyByteBuf> receiver = decoder.createReceiver();
|
||||
NetworkManager.registerReceiver(NetworkManager.s2c(), messageType.getId(), transformers, receiver);
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ public class SimpleNetworkManager {
|
||||
@ApiStatus.Experimental
|
||||
public MessageType registerC2S(String id, MessageDecoder<BaseC2SMessage> decoder, List<PacketTransformer> transformers) {
|
||||
MessageType messageType = new MessageType(this, new ResourceLocation(namespace, id), NetworkManager.c2s());
|
||||
NetworkManager.NetworkReceiver receiver = decoder.createReceiver();
|
||||
NetworkManager.NetworkReceiver<RegistryFriendlyByteBuf> receiver = decoder.createReceiver();
|
||||
NetworkManager.registerReceiver(NetworkManager.c2s(), messageType.getId(), transformers, receiver);
|
||||
return messageType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
package dev.architectury.networking.simple;
|
||||
@@ -20,7 +20,7 @@
|
||||
package dev.architectury.networking.transformers;
|
||||
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -31,24 +31,24 @@ import java.util.List;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public interface PacketTransformer {
|
||||
void inbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink);
|
||||
void inbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink);
|
||||
|
||||
void outbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, TransformationSink sink);
|
||||
void outbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, TransformationSink sink);
|
||||
|
||||
@FunctionalInterface
|
||||
interface TransformationSink {
|
||||
void accept(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf);
|
||||
void accept(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf);
|
||||
}
|
||||
|
||||
static PacketTransformer none() {
|
||||
return new PacketTransformer() {
|
||||
@Override
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
sink.accept(side, id, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, TransformationSink sink) {
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, TransformationSink sink) {
|
||||
sink.accept(side, id, buf);
|
||||
}
|
||||
};
|
||||
@@ -62,16 +62,16 @@ public interface PacketTransformer {
|
||||
}
|
||||
return new PacketTransformer() {
|
||||
@Override
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
traverse(side, id, buf, context, sink, true, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, TransformationSink sink) {
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, TransformationSink sink) {
|
||||
traverse(side, id, buf, null, sink, false, 0);
|
||||
}
|
||||
|
||||
private void traverse(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, @Nullable NetworkManager.PacketContext context, TransformationSink outerSink, boolean inbound, int index) {
|
||||
private void traverse(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, @Nullable NetworkManager.PacketContext context, TransformationSink outerSink, boolean inbound, int index) {
|
||||
if (transformers instanceof List) {
|
||||
if (((List<? extends PacketTransformer>) transformers).size() > index) {
|
||||
PacketTransformer transformer = ((List<? extends PacketTransformer>) transformers).get(index);
|
||||
|
||||
@@ -28,7 +28,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -81,7 +81,7 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
private static class PartData {
|
||||
private final ResourceLocation id;
|
||||
private final int partsExpected;
|
||||
private final List<FriendlyByteBuf> parts;
|
||||
private final List<RegistryFriendlyByteBuf> parts;
|
||||
|
||||
public PartData(ResourceLocation id, int partsExpected) {
|
||||
this.id = id;
|
||||
@@ -109,7 +109,7 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
public void inbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, NetworkManager.PacketContext context, TransformationSink sink) {
|
||||
PartKey key = side == NetworkManager.Side.S2C ? new PartKey(side, null) : new PartKey(side, context.getPlayer().getUUID());
|
||||
PartData data;
|
||||
switch (buf.readByte()) {
|
||||
@@ -128,7 +128,7 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
} else if (!data.id.equals(id)) {
|
||||
LOGGER.warn("Received invalid PART packet for SplitPacketTransformer with packet id " + id + " for side " + side + ", id in cache is " + data.id);
|
||||
buf.release();
|
||||
for (FriendlyByteBuf part : data.parts) {
|
||||
for (RegistryFriendlyByteBuf part : data.parts) {
|
||||
if (part != buf) {
|
||||
part.release();
|
||||
}
|
||||
@@ -146,7 +146,7 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
} else if (!data.id.equals(id)) {
|
||||
LOGGER.warn("Received invalid END packet for SplitPacketTransformer with packet id " + id + " for side " + side + ", id in cache is " + data.id);
|
||||
buf.release();
|
||||
for (FriendlyByteBuf part : data.parts) {
|
||||
for (RegistryFriendlyByteBuf part : data.parts) {
|
||||
if (part != buf) {
|
||||
part.release();
|
||||
}
|
||||
@@ -158,13 +158,13 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
}
|
||||
if (data.parts.size() != data.partsExpected) {
|
||||
LOGGER.warn("Received invalid END packet for SplitPacketTransformer with packet id " + id + " for side " + side + " with size " + data.parts + ", parts expected is " + data.partsExpected);
|
||||
for (FriendlyByteBuf part : data.parts) {
|
||||
for (RegistryFriendlyByteBuf part : data.parts) {
|
||||
if (part != buf) {
|
||||
part.release();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FriendlyByteBuf byteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(data.parts.toArray(new ByteBuf[0])));
|
||||
RegistryFriendlyByteBuf byteBuf = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(data.parts.toArray(new ByteBuf[0])), buf.registryAccess());
|
||||
sink.accept(side, data.id, byteBuf);
|
||||
byteBuf.release();
|
||||
}
|
||||
@@ -179,18 +179,18 @@ public class SplitPacketTransformer implements PacketTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf, TransformationSink sink) {
|
||||
public void outbound(NetworkManager.Side side, ResourceLocation id, RegistryFriendlyByteBuf buf, TransformationSink sink) {
|
||||
int maxSize = (side == NetworkManager.Side.C2S ? 32767 : 1048576) - 1 - 20 - id.toString().getBytes(StandardCharsets.UTF_8).length;
|
||||
if (buf.readableBytes() <= maxSize) {
|
||||
ByteBuf stateBuf = Unpooled.buffer(1);
|
||||
stateBuf.writeByte(ONLY);
|
||||
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.wrappedBuffer(stateBuf, buf));
|
||||
RegistryFriendlyByteBuf packetBuffer = new RegistryFriendlyByteBuf(Unpooled.wrappedBuffer(stateBuf, buf), buf.registryAccess());
|
||||
sink.accept(side, id, packetBuffer);
|
||||
} else {
|
||||
int partSize = maxSize - 4;
|
||||
int parts = (int) Math.ceil(buf.readableBytes() / (float) partSize);
|
||||
for (int i = 0; i < parts; i++) {
|
||||
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
RegistryFriendlyByteBuf packetBuffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), buf.registryAccess());
|
||||
if (i == 0) {
|
||||
packetBuffer.writeByte(START);
|
||||
packetBuffer.writeInt(parts);
|
||||
|
||||
@@ -38,7 +38,7 @@ import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||
import net.fabricmc.fabric.api.event.player.UseItemCallback;
|
||||
// import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.loot.v2.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageDecoratorEvent;
|
||||
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class EventHandlerImpl {
|
||||
AttackBlockCallback.EVENT.register((player, world, hand, pos, face) -> InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(player, hand, pos, face).asMinecraft());
|
||||
AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> PlayerEvent.ATTACK_ENTITY.invoker().attack(player, world, entity, hand, hitResult).asMinecraft());
|
||||
|
||||
// LootTableEvents.MODIFY.register((key, tableBuilder, source) -> LootEvent.MODIFY_LOOT_TABLE.invoker().modifyLootTable(lootManager, id, new LootTableModificationContextImpl(tableBuilder), source.isBuiltin()));
|
||||
LootTableEvents.MODIFY.register((key, tableBuilder, source) -> LootEvent.MODIFY_LOOT_TABLE.invoker().modifyLootTable(key, new LootTableModificationContextImpl(tableBuilder), source.isBuiltin()));
|
||||
|
||||
ServerMessageDecoratorEvent.EVENT.register(ServerMessageDecoratorEvent.CONTENT_PHASE, (player, component) -> {
|
||||
ChatEvent.ChatComponent chatComponent = new ChatComponentImpl(component);
|
||||
|
||||
@@ -25,24 +25,28 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dev.architectury.fluid.FluidStack;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.component.PatchedDataComponentMap;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public enum FluidStackImpl implements FluidStack.FluidStackAdapter<FluidStackImpl.Pair> {
|
||||
INSTANCE;
|
||||
|
||||
@@ -60,13 +64,30 @@ public enum FluidStackImpl implements FluidStack.FluidStackAdapter<FluidStackImp
|
||||
}
|
||||
|
||||
public static class Pair {
|
||||
public FluidVariant variant;
|
||||
public Fluid fluid;
|
||||
public PatchedDataComponentMap components;
|
||||
public long amount;
|
||||
|
||||
public Pair(FluidVariant variant, long amount) {
|
||||
this.variant = variant;
|
||||
public Pair(Fluid fluid, @Nullable DataComponentPatch patch, long amount) {
|
||||
this(fluid,
|
||||
patch == null ? new PatchedDataComponentMap(DataComponentMap.EMPTY)
|
||||
: PatchedDataComponentMap.fromPatch(DataComponentMap.EMPTY, patch),
|
||||
amount);
|
||||
}
|
||||
|
||||
public Pair(Fluid fluid, PatchedDataComponentMap components, long amount) {
|
||||
this.fluid = fluid;
|
||||
this.components = components;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public FluidVariant toVariant() {
|
||||
return FluidVariant.of(fluid, getPatch());
|
||||
}
|
||||
|
||||
public DataComponentPatch getPatch() {
|
||||
return amount <= 0L || this.fluid == Fluids.EMPTY ? components.asPatch() : DataComponentPatch.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,17 +96,17 @@ public enum FluidStackImpl implements FluidStack.FluidStackAdapter<FluidStackImp
|
||||
if (fluidType instanceof FlowingFluid flowingFluid) {
|
||||
fluidType = flowingFluid.getSource();
|
||||
}
|
||||
return new Pair(FluidVariant.of(fluidType, patch == null ? DataComponentPatch.EMPTY : patch), amount);
|
||||
return new Pair(fluidType, patch, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Fluid> getRawFluidSupplier(FluidStackImpl.Pair object) {
|
||||
return () -> object.variant.getFluid();
|
||||
return () -> object.fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getFluid(FluidStackImpl.Pair object) {
|
||||
return object.variant.getFluid();
|
||||
return object.fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,28 +120,60 @@ public enum FluidStackImpl implements FluidStack.FluidStackAdapter<FluidStackImp
|
||||
}
|
||||
|
||||
public DataComponentPatch getPatch(FluidStackImpl.Pair value) {
|
||||
return value.variant.getComponents();
|
||||
return value.getPatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPatch(FluidStackImpl.Pair value, DataComponentPatch patch) {
|
||||
value.variant = FluidVariant.of(value.variant.getFluid(), patch);
|
||||
public PatchedDataComponentMap getComponents(Pair value) {
|
||||
return value.components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyComponents(Pair value, DataComponentPatch patch) {
|
||||
value.components.applyPatch(patch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyComponents(Pair value, DataComponentMap patch) {
|
||||
value.components.setAll(patch);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D set(Pair value, DataComponentType<? super D> type, @Nullable D component) {
|
||||
return value.components.set(type, component);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D remove(Pair value, DataComponentType<? extends D> type) {
|
||||
return value.components.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D update(Pair value, DataComponentType<D> type, D component, UnaryOperator<D> updater) {
|
||||
return value.components.set(type, updater.apply(getComponents(value).getOrDefault(type, component)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D, U> D update(Pair value, DataComponentType<D> type, D component, U updateContext, BiFunction<D, U, D> updater) {
|
||||
return value.components.set(type, updater.apply(getComponents(value).getOrDefault(type, component), updateContext));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStackImpl.Pair copy(FluidStackImpl.Pair value) {
|
||||
return new Pair(value.variant, value.amount);
|
||||
return new Pair(value.fluid, value.components.copy(), value.amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(FluidStackImpl.Pair value) {
|
||||
var pair = (Pair) value;
|
||||
var code = 1;
|
||||
code = 31 * code + pair.variant.hashCode();
|
||||
code = 31 * code + pair.fluid.hashCode();
|
||||
code = 31 * code + Long.hashCode(pair.amount);
|
||||
var patch = pair.variant.getComponents();
|
||||
if (patch != null)
|
||||
code = 31 * code + patch.hashCode();
|
||||
code = 31 * code + pair.components.hashCode();
|
||||
return code;
|
||||
}
|
||||
|
||||
@@ -133,7 +186,7 @@ public enum FluidStackImpl implements FluidStack.FluidStackAdapter<FluidStackImp
|
||||
? DataResult.success(value)
|
||||
: DataResult.error(() -> "Value must be non-negative: " + value);
|
||||
}).fieldOf("amount").forGetter(FluidStack::getAmount),
|
||||
DataComponentPatch.CODEC.fieldOf("components").forGetter(FluidStack::getPatch)
|
||||
DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter(FluidStack::getPatch)
|
||||
).apply(instance, FluidStack::create));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import dev.architectury.fluid.fabric.FluidStackImpl;
|
||||
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
|
||||
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public final class FluidStackHooksFabric {
|
||||
private FluidStackHooksFabric() {
|
||||
}
|
||||
@@ -34,10 +33,10 @@ public final class FluidStackHooksFabric {
|
||||
}
|
||||
|
||||
public static FluidStack fromFabric(FluidVariant variant, long amount) {
|
||||
return FluidStackImpl.fromValue.apply(new FluidStackImpl.Pair(variant, amount));
|
||||
return FluidStackImpl.fromValue.apply(new FluidStackImpl.Pair(variant.getFluid(), variant.getComponents(), amount));
|
||||
}
|
||||
|
||||
public static FluidVariant toFabric(FluidStack stack) {
|
||||
return ((FluidStackImpl.Pair) FluidStackImpl.toValue.apply(stack)).variant;
|
||||
return ((FluidStackImpl.Pair) FluidStackImpl.toValue.apply(stack)).toVariant();
|
||||
}
|
||||
}
|
||||
@@ -20,20 +20,19 @@
|
||||
package dev.architectury.networking.fabric;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.architectury.impl.NetworkAggregator;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.NetworkManager.NetworkReceiver;
|
||||
import dev.architectury.networking.SpawnEntityPacket;
|
||||
import dev.architectury.networking.transformers.PacketSink;
|
||||
import dev.architectury.networking.transformers.PacketTransformer;
|
||||
import dev.architectury.utils.Env;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
@@ -44,79 +43,47 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class NetworkManagerImpl {
|
||||
private static final Map<ResourceLocation, CustomPacketPayload.Type<BufCustomPacketPayload>> C2S_TYPE = new HashMap<>();
|
||||
private static final Map<ResourceLocation, CustomPacketPayload.Type<BufCustomPacketPayload>> S2C_TYPE = new HashMap<>();
|
||||
private static final Map<ResourceLocation, NetworkReceiver> C2S_RECEIVER = new HashMap<>();
|
||||
private static final Map<ResourceLocation, NetworkReceiver> S2C_RECEIVER = new HashMap<>();
|
||||
private static final Map<ResourceLocation, PacketTransformer> C2S_TRANSFORMERS = new HashMap<>();
|
||||
private static final Map<ResourceLocation, PacketTransformer> S2C_TRANSFORMERS = new HashMap<>();
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
Objects.requireNonNull(id, "Cannot register receiver with a null ID!");
|
||||
packetTransformers = Objects.requireNonNullElse(packetTransformers, List.of());
|
||||
Objects.requireNonNull(receiver, "Cannot register a null receiver!");
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
registerC2SReceiver(id, packetTransformers, receiver);
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
registerS2CReceiver(id, packetTransformers, receiver);
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerC2SReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
LOGGER.info("Registering C2S receiver with id {}", id);
|
||||
C2S_RECEIVER.put(id, receiver);
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = new CustomPacketPayload.Type<>(id);
|
||||
C2S_TYPE.put(id, type);
|
||||
PayloadTypeRegistry.playC2S().register(type, BufCustomPacketPayload.streamCodec(type));
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
ServerPlayNetworking.registerGlobalReceiver(type, (payload, fabricContext) -> {
|
||||
var context = context(fabricContext.player(), fabricContext.player().server, false);
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(payload.payload()));
|
||||
transformer.inbound(NetworkManager.Side.C2S, id, buf, context, (side, id1, buf1) -> {
|
||||
NetworkReceiver networkReceiver = side == NetworkManager.Side.C2S ? C2S_RECEIVER.get(id1) : S2C_RECEIVER.get(id1);
|
||||
if (networkReceiver == null) {
|
||||
throw new IllegalArgumentException("Network Receiver not found! " + id1);
|
||||
}
|
||||
networkReceiver.receive(buf1, context);
|
||||
});
|
||||
buf.release();
|
||||
});
|
||||
C2S_TRANSFORMERS.put(id, transformer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Convert2Lambda")
|
||||
@Environment(EnvType.CLIENT)
|
||||
private static void registerS2CReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
LOGGER.info("Registering S2C receiver with id {}", id);
|
||||
S2C_RECEIVER.put(id, receiver);
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = new CustomPacketPayload.Type<>(id);
|
||||
S2C_TYPE.put(id, type);
|
||||
PayloadTypeRegistry.playS2C().register(type, BufCustomPacketPayload.streamCodec(type));
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
ClientPlayNetworking.registerGlobalReceiver(type, new ClientPlayNetworking.PlayPayloadHandler<>() {
|
||||
public static NetworkAggregator.Adaptor getAdaptor() {
|
||||
return new NetworkAggregator.Adaptor() {
|
||||
@Override
|
||||
public void receive(BufCustomPacketPayload payload, ClientPlayNetworking.Context fabricContext) {
|
||||
var context = context(fabricContext.player(), fabricContext.client(), true);
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(payload.payload()));
|
||||
transformer.inbound(NetworkManager.Side.S2C, id, buf, context, (side, id1, buf1) -> {
|
||||
NetworkReceiver networkReceiver = side == NetworkManager.Side.C2S ? C2S_RECEIVER.get(id1) : S2C_RECEIVER.get(id1);
|
||||
if (networkReceiver == null) {
|
||||
throw new IllegalArgumentException("Network Receiver not found! " + id1);
|
||||
}
|
||||
networkReceiver.receive(buf1, context);
|
||||
public <T extends CustomPacketPayload> void registerC2S(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkReceiver<T> receiver) {
|
||||
LOGGER.info("Registering C2S receiver with id {}", type.id());
|
||||
PayloadTypeRegistry.playC2S().register(type, codec);
|
||||
ServerPlayNetworking.registerGlobalReceiver(type, (payload, fabricContext) -> {
|
||||
var context = context(fabricContext.player(), fabricContext.player().server, false);
|
||||
receiver.receive(payload, context);
|
||||
});
|
||||
buf.release();
|
||||
}
|
||||
});
|
||||
S2C_TRANSFORMERS.put(id, transformer);
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public <T extends CustomPacketPayload> void registerS2C(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkReceiver<T> receiver) {
|
||||
LOGGER.info("Registering S2C receiver with id {}", type.id());
|
||||
PayloadTypeRegistry.playS2C().register(type, codec);
|
||||
ClientPlayNetworking.registerGlobalReceiver(type, (payload, fabricContext) -> {
|
||||
var context = context(fabricContext.player(), fabricContext.client(), true);
|
||||
receiver.receive(payload, context);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> Packet<?> toC2SPacket(T payload) {
|
||||
return ClientPlayNetworking.createC2SPacket(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> Packet<?> toS2CPacket(T payload) {
|
||||
return ServerPlayNetworking.createS2CPacket(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> void registerS2CType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec) {
|
||||
PayloadTypeRegistry.playS2C().register(type, codec);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static NetworkManager.PacketContext context(Player player, BlockableEventLoop<?> taskQueue, boolean client) {
|
||||
@@ -135,30 +102,14 @@ public class NetworkManagerImpl {
|
||||
public Env getEnvironment() {
|
||||
return client ? Env.CLIENT : Env.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryAccess registryAccess() {
|
||||
return player.registryAccess();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void collectPackets(PacketSink sink, NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
PacketTransformer transformer = side == NetworkManager.Side.C2S ? C2S_TRANSFORMERS.get(id) : S2C_TRANSFORMERS.get(id);
|
||||
if (transformer != null) {
|
||||
transformer.outbound(side, id, buf, (side1, id1, buf1) -> {
|
||||
sink.accept(toPacket(side1, id1, buf1));
|
||||
});
|
||||
} else {
|
||||
sink.accept(toPacket(side, id, buf));
|
||||
}
|
||||
}
|
||||
|
||||
public static Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
return toC2SPacket(id, buf);
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
return toS2CPacket(id, buf);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid side: " + side);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public static boolean canServerReceive(ResourceLocation id) {
|
||||
return ClientPlayNetworking.canSend(id);
|
||||
@@ -171,21 +122,4 @@ public class NetworkManagerImpl {
|
||||
public static Packet<ClientGamePacketListener> createAddEntityPacket(Entity entity) {
|
||||
return SpawnEntityPacket.create(entity);
|
||||
}
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
private static Packet<?> toC2SPacket(ResourceLocation id, FriendlyByteBuf buf) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = C2S_TYPE.get(id);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown packet id: " + id);
|
||||
}
|
||||
return ClientPlayNetworking.createC2SPacket(new BufCustomPacketPayload(type, ByteBufUtil.getBytes(buf)));
|
||||
}
|
||||
|
||||
private static Packet<?> toS2CPacket(ResourceLocation id, FriendlyByteBuf buf) {
|
||||
CustomPacketPayload.Type<BufCustomPacketPayload> type = S2C_TYPE.get(id);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Unknown packet id: " + id);
|
||||
}
|
||||
return ServerPlayNetworking.createS2CPacket(new BufCustomPacketPayload(type, ByteBufUtil.getBytes(buf)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
org.gradle.jvmargs=-Xmx6G
|
||||
org.gradle.daemon=false
|
||||
|
||||
platforms=fabric
|
||||
platforms=fabric,neoforge
|
||||
|
||||
minecraft_version=24w14a
|
||||
supported_version=1.20.5 (24w14a)
|
||||
@@ -18,7 +18,10 @@ fabric_api_version=0.96.14+1.20.5
|
||||
mod_menu_version=9.0.0
|
||||
|
||||
forge_version=49.0.14
|
||||
neoforge_version=20.4.77-beta
|
||||
neoforge_version=20.5.0-alpha.24w14a.20240407.201521
|
||||
|
||||
# Set to empty if not snapshots
|
||||
neoforge_pr=787
|
||||
|
||||
curseforge_id=419699
|
||||
modrinth_id=lhGA9TYQ
|
||||
|
||||
@@ -11,38 +11,29 @@ architectury {
|
||||
platformSetupLoomIde()
|
||||
neoForge {
|
||||
platformPackage = "forge"
|
||||
remapForgeLike "net/minecraftforge/common/extensions/IForgeItem", "net/neoforged/neoforge/common/extensions/IItemExtension"
|
||||
remapForgeLike "net/minecraftforge/client/event/TextureStitchEvent\$Post", "net/neoforged/neoforge/client/event/TextureAtlasStitchedEvent"
|
||||
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid", "net/neoforged/neoforge/fluids/BaseFlowingFluid"
|
||||
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid\$Properties", "net/neoforged/neoforge/fluids/BaseFlowingFluid\$Properties"
|
||||
remapForgeLike "net/minecraftforge/common/ForgeHooks", "net/neoforged/neoforge/common/CommonHooks"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
forgeLike
|
||||
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
||||
compileClasspath.extendsFrom common, forgeLike
|
||||
runtimeClasspath.extendsFrom common, forgeLike
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentNeoForge.extendsFrom common
|
||||
developmentForgeLike.extendsFrom forgeLike
|
||||
}
|
||||
|
||||
dependencies {
|
||||
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
||||
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
forgeLike(project(path: ":forge", configuration: "namedElements")) { transitive false }
|
||||
shadowCommon(project(path: ":common", configuration: "transformProductionNeoForge")) { transitive false }
|
||||
shadowCommon(project(path: ":forge", configuration: "transformProductionNeoForge")) { transitive false }
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesMatching("META-INF/mods.toml") {
|
||||
filesMatching("META-INF/neoforge.mods.toml") {
|
||||
expand "version": project.version
|
||||
}
|
||||
inputs.property "META-INF/mods.toml", project.version
|
||||
inputs.property "META-INF/neoforge.mods.toml", project.version
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
@@ -113,7 +104,7 @@ publishing {
|
||||
}
|
||||
|
||||
repositories {
|
||||
if (System.getenv("MAVEN_PASS") != null) {
|
||||
if (System.getenv("MAVEN_PASS") != null && rootProject.neoforge_pr == "") {
|
||||
maven {
|
||||
url = "https://deploy.shedaniel.me/"
|
||||
credentials {
|
||||
@@ -126,6 +117,7 @@ publishing {
|
||||
}
|
||||
|
||||
unifiedPublishing {
|
||||
if (rootProject.neoforge_pr != "") return // Don't publish PRs
|
||||
project {
|
||||
displayName = "[NeoForge $rootProject.supported_version] v$project.version"
|
||||
releaseType = "$rootProject.artifact_type"
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.core.block.forge.imitator;
|
||||
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ArchitecturyLiquidBlock extends LiquidBlock {
|
||||
public ArchitecturyLiquidBlock(Supplier<? extends FlowingFluid> fluid, Properties properties) {
|
||||
super(fluid, properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.core.fluid.forge.imitator;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Suppliers;
|
||||
import dev.architectury.core.fluid.ArchitecturyFluidAttributes;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.neoforged.neoforge.fluids.BaseFlowingFluid;
|
||||
import net.neoforged.neoforge.fluids.FluidType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class ArchitecturyFlowingFluid extends BaseFlowingFluid {
|
||||
private static final Map<ArchitecturyFluidAttributes, FluidType> FLUID_TYPE_MAP = new IdentityHashMap<>();
|
||||
private final ArchitecturyFluidAttributes attributes;
|
||||
|
||||
ArchitecturyFlowingFluid(ArchitecturyFluidAttributes attributes) {
|
||||
super(toForgeProperties(attributes));
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
private static Properties toForgeProperties(ArchitecturyFluidAttributes attributes) {
|
||||
Properties forge = new Properties(Suppliers.memoize(() -> {
|
||||
return FLUID_TYPE_MAP.computeIfAbsent(attributes, attr -> {
|
||||
return new ArchitecturyFluidAttributesForge(FluidType.Properties.create(), attr.getSourceFluid(), attr);
|
||||
});
|
||||
}), attributes::getSourceFluid, attributes::getFlowingFluid);
|
||||
forge.slopeFindDistance(attributes.getSlopeFindDistance());
|
||||
forge.levelDecreasePerBlock(attributes.getDropOff());
|
||||
forge.bucket(() -> MoreObjects.firstNonNull(attributes.getBucketItem(), Items.AIR));
|
||||
forge.tickRate(attributes.getTickDelay());
|
||||
forge.explosionResistance(attributes.getExplosionResistance());
|
||||
forge.block(() -> MoreObjects.firstNonNull(attributes.getBlock(), (LiquidBlock) Blocks.WATER));
|
||||
return forge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getFlowing() {
|
||||
return attributes.getFlowingFluid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getSource() {
|
||||
return attributes.getSourceFluid();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canConvertToSource(Level level) {
|
||||
return attributes.canConvertToSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state) {
|
||||
// Same implementation as in WaterFluid.
|
||||
BlockEntity blockEntity = state.hasBlockEntity() ? level.getBlockEntity(pos) : null;
|
||||
Block.dropResources(state, level, pos, blockEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSlopeFindDistance(LevelReader level) {
|
||||
return attributes.getSlopeFindDistance(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDropOff(LevelReader level) {
|
||||
return attributes.getDropOff(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getBucket() {
|
||||
Item item = attributes.getBucketItem();
|
||||
return item == null ? Items.AIR : item;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canBeReplacedWith(FluidState state, BlockGetter level, BlockPos pos, Fluid fluid, Direction direction) {
|
||||
// Same implementation as in WaterFluid.
|
||||
return direction == Direction.DOWN && !this.isSame(fluid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
return attributes.getTickDelay(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getExplosionResistance() {
|
||||
return attributes.getExplosionResistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState createLegacyBlock(FluidState state) {
|
||||
LiquidBlock block = attributes.getBlock();
|
||||
if (block == null) return Blocks.AIR.defaultBlockState();
|
||||
return block.defaultBlockState().setValue(LiquidBlock.LEVEL, getLegacyLevel(state));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Optional<SoundEvent> getPickupSound() {
|
||||
return Optional.ofNullable(attributes.getFillSound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSame(Fluid fluid) {
|
||||
return fluid == getSource() || fluid == getFlowing();
|
||||
}
|
||||
|
||||
public static class Source extends ArchitecturyFlowingFluid {
|
||||
public Source(ArchitecturyFluidAttributes attributes) {
|
||||
super(attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Flowing extends ArchitecturyFlowingFluid {
|
||||
public Flowing(ArchitecturyFluidAttributes attributes) {
|
||||
super(attributes);
|
||||
this.registerDefaultState(this.getStateDefinition().any().setValue(LEVEL, 7));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createFluidStateDefinition(StateDefinition.Builder<Fluid, FluidState> builder) {
|
||||
super.createFluidStateDefinition(builder);
|
||||
builder.add(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount(FluidState state) {
|
||||
return state.getValue(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSource(FluidState state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.core.fluid.forge.imitator;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import dev.architectury.core.fluid.ArchitecturyFluidAttributes;
|
||||
import dev.architectury.hooks.fluid.forge.FluidStackHooksForge;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Rarity;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
|
||||
import net.neoforged.neoforge.common.SoundAction;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.FluidType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minecraft.sounds.SoundEvents.BUCKET_EMPTY;
|
||||
import static net.minecraft.sounds.SoundEvents.BUCKET_FILL;
|
||||
|
||||
class ArchitecturyFluidAttributesForge extends FluidType {
|
||||
private final ArchitecturyFluidAttributes attributes;
|
||||
private final String defaultTranslationKey;
|
||||
|
||||
public ArchitecturyFluidAttributesForge(Properties builder, Fluid fluid, ArchitecturyFluidAttributes attributes) {
|
||||
super(addArchIntoBuilder(builder, attributes));
|
||||
this.attributes = attributes;
|
||||
this.defaultTranslationKey = Util.makeDescriptionId("fluid", BuiltInRegistries.FLUID.getKey(fluid));
|
||||
}
|
||||
|
||||
private static Properties addArchIntoBuilder(Properties builder, ArchitecturyFluidAttributes attributes) {
|
||||
builder.lightLevel(attributes.getLuminosity())
|
||||
.density(attributes.getDensity())
|
||||
.temperature(attributes.getTemperature())
|
||||
.rarity(attributes.getRarity())
|
||||
.canConvertToSource(attributes.canConvertToSource())
|
||||
.viscosity(attributes.getViscosity());
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getBucket(FluidStack stack) {
|
||||
Item item = attributes.getBucketItem();
|
||||
return item == null ? super.getBucket(stack) : new ItemStack(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeClient(Consumer<IClientFluidTypeExtensions> consumer) {
|
||||
consumer.accept(new IClientFluidTypeExtensions() {
|
||||
@Override
|
||||
public int getTintColor() {
|
||||
return attributes.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getStillTexture() {
|
||||
return attributes.getSourceTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getFlowingTexture() {
|
||||
return attributes.getFlowingTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ResourceLocation getOverlayTexture() {
|
||||
return attributes.getOverlayTexture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getStillTexture(FluidState state, BlockAndTintGetter getter, BlockPos pos) {
|
||||
return attributes.getSourceTexture(state, getter, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getFlowingTexture(FluidState state, BlockAndTintGetter getter, BlockPos pos) {
|
||||
return attributes.getFlowingTexture(state, getter, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ResourceLocation getOverlayTexture(FluidState state, BlockAndTintGetter getter, BlockPos pos) {
|
||||
return attributes.getOverlayTexture(state, getter, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTintColor(FluidState state, BlockAndTintGetter getter, BlockPos pos) {
|
||||
return attributes.getColor(state, getter, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTintColor(FluidStack stack) {
|
||||
return attributes.getColor(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getStillTexture(FluidStack stack) {
|
||||
return attributes.getSourceTexture(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getFlowingTexture(FluidStack stack) {
|
||||
return attributes.getFlowingTexture(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ResourceLocation getOverlayTexture(FluidStack stack) {
|
||||
return attributes.getOverlayTexture(convertSafe(stack));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightLevel(FluidStack stack) {
|
||||
return attributes.getLuminosity(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightLevel(FluidState state, BlockAndTintGetter level, BlockPos pos) {
|
||||
return attributes.getLuminosity(convertSafe(state), level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDensity(FluidStack stack) {
|
||||
return attributes.getDensity(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDensity(FluidState state, BlockAndTintGetter level, BlockPos pos) {
|
||||
return attributes.getDensity(convertSafe(state), level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTemperature(FluidStack stack) {
|
||||
return attributes.getTemperature(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTemperature(FluidState state, BlockAndTintGetter level, BlockPos pos) {
|
||||
return attributes.getTemperature(convertSafe(state), level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViscosity(FluidStack stack) {
|
||||
return attributes.getViscosity(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViscosity(FluidState state, BlockAndTintGetter level, BlockPos pos) {
|
||||
return attributes.getViscosity(convertSafe(state), level, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rarity getRarity() {
|
||||
return attributes.getRarity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rarity getRarity(FluidStack stack) {
|
||||
return attributes.getRarity(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription() {
|
||||
return attributes.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription(FluidStack stack) {
|
||||
return attributes.getName(convertSafe(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptionId() {
|
||||
return MoreObjects.firstNonNull(attributes.getTranslationKey(), defaultTranslationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptionId(FluidStack stack) {
|
||||
return MoreObjects.firstNonNull(attributes.getTranslationKey(convertSafe(stack)), defaultTranslationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SoundEvent getSound(SoundAction action) {
|
||||
return getSound((FluidStack) null, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SoundEvent getSound(@Nullable FluidStack stack, SoundAction action) {
|
||||
var archStack = convertSafe(stack);
|
||||
if (BUCKET_FILL.equals(action)) {
|
||||
return attributes.getFillSound(archStack);
|
||||
} else if (BUCKET_EMPTY.equals(action)) {
|
||||
return attributes.getEmptySound(archStack);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SoundEvent getSound(@Nullable Player player, BlockGetter getter, BlockPos pos, SoundAction action) {
|
||||
if (getter instanceof BlockAndTintGetter level) {
|
||||
if (BUCKET_FILL.equals(action)) {
|
||||
return attributes.getFillSound(null, level, pos);
|
||||
} else if (BUCKET_EMPTY.equals(action)) {
|
||||
return attributes.getEmptySound(null, level, pos);
|
||||
}
|
||||
}
|
||||
return getSound((FluidStack) null, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConvertToSource(FluidStack stack) {
|
||||
return attributes.canConvertToSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConvertToSource(FluidState state, LevelReader reader, BlockPos pos) {
|
||||
return attributes.canConvertToSource();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public dev.architectury.fluid.FluidStack convertSafe(@Nullable FluidStack stack) {
|
||||
return stack == null ? null : FluidStackHooksForge.fromForge(stack);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public dev.architectury.fluid.FluidStack convertSafe(@Nullable FluidState state) {
|
||||
return state == null ? null : dev.architectury.fluid.FluidStack.create(state.getType(), dev.architectury.fluid.FluidStack.bucketAmount());
|
||||
}
|
||||
}
|
||||
@@ -17,47 +17,38 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.forgelike.forge;
|
||||
package dev.architectury.core.item.forge.imitator;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import dev.architectury.platform.hooks.forge.EventBusesHooksImpl;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.BucketItem;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
|
||||
import net.neoforged.neoforge.common.world.BiomeModifier;
|
||||
import net.neoforged.neoforge.fluids.capability.wrappers.FluidBucketWrapper;
|
||||
import net.neoforged.neoforge.registries.NeoForgeRegistries;
|
||||
import net.neoforged.neoforge.registries.RegisterEvent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ForgeLikeHooksImpl {
|
||||
private static final Logger LOGGER = LogManager.getLogger(ForgeLikeHooksImpl.class);
|
||||
public class ArchitecturyBucketItem extends BucketItem {
|
||||
private static final Logger LOGGER = LogManager.getLogger(ArchitecturyBucketItem.class);
|
||||
|
||||
public static void registerBiomeModifier(ResourceLocation id, Supplier<Codec<? extends BiomeModifier>> codecSupplier) {
|
||||
EventBusesHooksImpl.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterEvent>addListener(event -> {
|
||||
event.register(NeoForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> {
|
||||
registry.register(id, codecSupplier.get());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static void registerBucketItemCapability(Item item) {
|
||||
EventBusesHooksImpl.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
public ArchitecturyBucketItem(Supplier<? extends Fluid> fluid, Properties properties) {
|
||||
super(fluid, properties);
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterCapabilitiesEvent>addListener(event -> {
|
||||
if (BuiltInRegistries.ITEM.containsValue(item)) {
|
||||
event.registerItem(Capabilities.FluidHandler.ITEM, (stack, ctx) -> new FluidBucketWrapper(stack), item);
|
||||
if (BuiltInRegistries.ITEM.containsValue(this)) {
|
||||
event.registerItem(Capabilities.FluidHandler.ITEM, (stack, ctx) -> new FluidBucketWrapper(stack), this);
|
||||
} else {
|
||||
LOGGER.warn("Tried to register a bucket item capability for an item that is not registered: {}", item);
|
||||
LOGGER.warn("Tried to register a bucket item capability for an item that is not registered: {}", this);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public final Fluid getContainedFluid() {
|
||||
return getFluid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.core.item.forge.imitator;
|
||||
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.MobBucketItem;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ArchitecturyMobBucketItem extends MobBucketItem {
|
||||
public ArchitecturyMobBucketItem(Supplier<? extends EntityType<?>> entity, Supplier<? extends Fluid> fluid, Supplier<? extends SoundEvent> sound, Properties properties) {
|
||||
super(entity, fluid, sound, properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import dev.architectury.event.Event;
|
||||
import dev.architectury.event.EventActor;
|
||||
import dev.architectury.event.EventResult;
|
||||
import net.neoforged.bus.api.ICancellableEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class EventFactoryImpl {
|
||||
public static <T> Event<Consumer<T>> attachToForge(Event<Consumer<T>> event) {
|
||||
event.register(eventObj -> {
|
||||
if (!(eventObj instanceof net.neoforged.bus.api.Event)) {
|
||||
throw new ClassCastException(eventObj.getClass() + " is not an instance of forge Event!");
|
||||
}
|
||||
NeoForge.EVENT_BUS.post((net.neoforged.bus.api.Event) eventObj);
|
||||
});
|
||||
return event;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> Event<EventActor<T>> attachToForgeEventActor(Event<EventActor<T>> event) {
|
||||
event.register(eventObj -> {
|
||||
if (!(eventObj instanceof net.neoforged.bus.api.Event)) {
|
||||
throw new ClassCastException(eventObj.getClass() + " is not an instance of forge Event!");
|
||||
}
|
||||
if (!(eventObj instanceof ICancellableEvent)) {
|
||||
throw new ClassCastException(eventObj.getClass() + " is not cancellable Event!");
|
||||
}
|
||||
NeoForge.EVENT_BUS.post((net.neoforged.bus.api.Event) eventObj);
|
||||
return EventResult.pass();
|
||||
});
|
||||
return event;
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> Event<EventActor<T>> attachToForgeEventActorCancellable(Event<EventActor<T>> event) {
|
||||
event.register(eventObj -> {
|
||||
if (!(eventObj instanceof net.neoforged.bus.api.Event)) {
|
||||
throw new ClassCastException(eventObj.getClass() + " is not an instance of forge Event!");
|
||||
}
|
||||
if (!(eventObj instanceof ICancellableEvent)) {
|
||||
throw new ClassCastException(eventObj.getClass() + " is not cancellable Event!");
|
||||
}
|
||||
if (((ICancellableEvent) NeoForge.EVENT_BUS.post((net.neoforged.bus.api.Event) eventObj)).isCanceled()) {
|
||||
return EventResult.interrupt(false);
|
||||
}
|
||||
return EventResult.pass();
|
||||
});
|
||||
return event;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
|
||||
public class EventHandlerImpl {
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void registerClient() {
|
||||
NeoForge.EVENT_BUS.register(EventHandlerImplClient.class);
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(EventHandlerImplClient.ModBasedEventHandler.class);
|
||||
});
|
||||
}
|
||||
|
||||
public static void registerCommon() {
|
||||
NeoForge.EVENT_BUS.register(EventHandlerImplCommon.class);
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(EventHandlerImplCommon.ModBasedEventHandler.class);
|
||||
});
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.DEDICATED_SERVER)
|
||||
public static void registerServer() {
|
||||
// MinecraftForge.EVENT_BUS.register(EventHandlerImplServer.class);
|
||||
// EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
// bus.register(EventHandlerImplServer.ModBasedEventHandler.class);
|
||||
// });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import dev.architectury.event.CompoundEventResult;
|
||||
import dev.architectury.event.EventResult;
|
||||
import dev.architectury.event.events.client.ClientChatEvent;
|
||||
import dev.architectury.event.events.client.*;
|
||||
import dev.architectury.event.events.common.InteractionEvent;
|
||||
import dev.architectury.impl.ScreenAccessImpl;
|
||||
import dev.architectury.impl.TooltipEventColorContextImpl;
|
||||
import dev.architectury.impl.TooltipEventPositionContextImpl;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.neoforged.neoforge.client.event.*;
|
||||
import net.neoforged.neoforge.event.TickEvent;
|
||||
import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class EventHandlerImplClient {
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ItemTooltipEvent event) {
|
||||
ClientTooltipEvent.ITEM.invoker().append(event.getItemStack(), event.getToolTip(), event.getFlags());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(TickEvent.ClientTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.START)
|
||||
ClientTickEvent.CLIENT_PRE.invoker().tick(Minecraft.getInstance());
|
||||
else if (event.phase == TickEvent.Phase.END)
|
||||
ClientTickEvent.CLIENT_POST.invoker().tick(Minecraft.getInstance());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventRenderGameOverlayEvent(RenderGuiEvent.Post event) {
|
||||
ClientGuiEvent.RENDER_HUD.invoker().renderHud(event.getGuiGraphics(), event.getPartialTick());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ClientPlayerNetworkEvent.LoggingIn event) {
|
||||
ClientPlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(event.getPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ClientPlayerNetworkEvent.LoggingOut event) {
|
||||
ClientPlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(event.getPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ClientPlayerNetworkEvent.Clone event) {
|
||||
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(event.getOldPlayer(), event.getNewPlayer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInitScreenEvent(ScreenEvent.Init.Pre event) {
|
||||
if (ClientGuiEvent.INIT_PRE.invoker().init(event.getScreen(), new ScreenAccessImpl(event.getScreen())).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInitScreenEvent(ScreenEvent.Init.Post event) {
|
||||
ClientGuiEvent.INIT_POST.invoker().init(event.getScreen(), new ScreenAccessImpl(event.getScreen()));
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventRenderGameOverlayEvent(CustomizeGuiOverlayEvent.DebugText event) {
|
||||
if (Minecraft.getInstance().gui.getDebugOverlay().showDebugScreen()) {
|
||||
ClientGuiEvent.DEBUG_TEXT_LEFT.invoker().gatherText(event.getLeft());
|
||||
ClientGuiEvent.DEBUG_TEXT_RIGHT.invoker().gatherText(event.getRight());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(net.neoforged.neoforge.client.event.ClientChatEvent event) {
|
||||
EventResult process = ClientChatEvent.SEND.invoker().send(event.getMessage(), null);
|
||||
if (process.isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ClientChatReceivedEvent event) {
|
||||
CompoundEventResult<Component> process = ClientChatEvent.RECEIVED.invoker().process(event.getBoundChatType(), event.getMessage());
|
||||
if (process.isPresent()) {
|
||||
if (process.isFalse())
|
||||
event.setCanceled(true);
|
||||
else if (process.object() != null)
|
||||
event.setMessage(process.object());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventWorldEvent(LevelEvent.Load event) {
|
||||
if (event.getLevel().isClientSide()) {
|
||||
ClientLevel world = (ClientLevel) event.getLevel();
|
||||
ClientLifecycleEvent.CLIENT_LEVEL_LOAD.invoker().act(world);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ScreenEvent.Opening event) {
|
||||
CompoundEventResult<Screen> result = ClientGuiEvent.SET_SCREEN.invoker().modifyScreen(event.getScreen());
|
||||
if (result.isPresent()) {
|
||||
if (result.isFalse())
|
||||
event.setCanceled(true);
|
||||
else if (result.object() != null)
|
||||
event.setNewScreen(result.object());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventDrawScreenEvent(ScreenEvent.Render.Pre event) {
|
||||
if (ClientGuiEvent.RENDER_PRE.invoker().render(event.getScreen(), event.getGuiGraphics(), event.getMouseX(), event.getMouseY(), event.getPartialTick()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventDrawScreenEvent(ScreenEvent.Render.Post event) {
|
||||
ClientGuiEvent.RENDER_POST.invoker().render(event.getScreen(), event.getGuiGraphics(), event.getMouseX(), event.getMouseY(), event.getPartialTick());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventContainerScreenEvent(ContainerScreenEvent.Render.Background event) {
|
||||
ClientGuiEvent.RENDER_CONTAINER_BACKGROUND.invoker().render(event.getContainerScreen(), event.getGuiGraphics(), event.getMouseX(), event.getMouseY(), Minecraft.getInstance().getDeltaFrameTime());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventContainerScreenEvent(ContainerScreenEvent.Render.Foreground event) {
|
||||
ClientGuiEvent.RENDER_CONTAINER_FOREGROUND.invoker().render(event.getContainerScreen(), event.getGuiGraphics(), event.getMouseX(), event.getMouseY(), Minecraft.getInstance().getDeltaFrameTime());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.RightClickEmpty event) {
|
||||
InteractionEvent.CLIENT_RIGHT_CLICK_AIR.invoker().click(event.getEntity(), event.getHand());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.LeftClickEmpty event) {
|
||||
InteractionEvent.CLIENT_LEFT_CLICK_AIR.invoker().click(event.getEntity(), event.getHand());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(RecipesUpdatedEvent event) {
|
||||
ClientRecipeUpdateEvent.EVENT.invoker().update(event.getRecipeManager());
|
||||
}
|
||||
|
||||
private static final ThreadLocal<TooltipEventPositionContextImpl> tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new);
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventRenderTooltipEvent(RenderTooltipEvent.Pre event) {
|
||||
GuiGraphics graphics = event.getGraphics();
|
||||
ClientTooltipEvent.additionalContexts().setItem(event.getItemStack());
|
||||
|
||||
try {
|
||||
if (ClientTooltipEvent.RENDER_PRE.invoker().renderTooltip(graphics, event.getComponents(), event.getX(), event.getY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
TooltipEventPositionContextImpl positionContext = tooltipPositionContext.get();
|
||||
positionContext.reset(event.getX(), event.getY());
|
||||
ClientTooltipEvent.RENDER_MODIFY_POSITION.invoker().renderTooltip(graphics, positionContext);
|
||||
event.setX(positionContext.getTooltipX());
|
||||
event.setY(positionContext.getTooltipY());
|
||||
} finally {
|
||||
ClientTooltipEvent.additionalContexts().setItem(null);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventRenderTooltipEvent(RenderTooltipEvent.Color event) {
|
||||
GuiGraphics graphics = event.getGraphics();
|
||||
ClientTooltipEvent.additionalContexts().setItem(event.getItemStack());
|
||||
|
||||
try {
|
||||
TooltipEventColorContextImpl colorContext = TooltipEventColorContextImpl.CONTEXT.get();
|
||||
colorContext.reset();
|
||||
colorContext.setBackgroundColor(event.getBackgroundStart());
|
||||
colorContext.setOutlineGradientTopColor(event.getBorderStart());
|
||||
colorContext.setOutlineGradientBottomColor(event.getBorderEnd());
|
||||
ClientTooltipEvent.RENDER_MODIFY_COLOR.invoker().renderTooltip(graphics, event.getX(), event.getY(), colorContext);
|
||||
event.setBackground(colorContext.getBackgroundColor());
|
||||
event.setBorderEnd(colorContext.getOutlineGradientBottomColor());
|
||||
event.setBorderStart(colorContext.getOutlineGradientTopColor());
|
||||
} finally {
|
||||
ClientTooltipEvent.additionalContexts().setItem(null);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseScrollEvent(ScreenEvent.MouseScrolled.Pre event) {
|
||||
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getScrollDeltaX(), event.getScrollDeltaY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseScrollEvent(ScreenEvent.MouseScrolled.Post event) {
|
||||
ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getScrollDeltaX(), event.getScrollDeltaY());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseClickedEvent(ScreenEvent.MouseButtonPressed.Pre event) {
|
||||
if (ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getButton()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseClickedEvent(ScreenEvent.MouseButtonPressed.Post event) {
|
||||
ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getButton());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseDragEvent(ScreenEvent.MouseDragged.Pre event) {
|
||||
if (ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseDragEvent(ScreenEvent.MouseDragged.Post event) {
|
||||
ClientScreenInputEvent.MOUSE_DRAGGED_POST.invoker().mouseDragged(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseReleasedEvent(ScreenEvent.MouseButtonReleased.Pre event) {
|
||||
if (ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getButton()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventMouseReleasedEvent(ScreenEvent.MouseButtonReleased.Post event) {
|
||||
ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getButton());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardCharTypedEvent(ScreenEvent.CharacterTyped.Pre event) {
|
||||
if (ClientScreenInputEvent.CHAR_TYPED_PRE.invoker().charTyped(Minecraft.getInstance(), event.getScreen(), event.getCodePoint(), event.getModifiers()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardCharTypedEvent(ScreenEvent.CharacterTyped.Post event) {
|
||||
ClientScreenInputEvent.CHAR_TYPED_POST.invoker().charTyped(Minecraft.getInstance(), event.getScreen(), event.getCodePoint(), event.getModifiers());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardKeyPressedEvent(ScreenEvent.KeyPressed.Pre event) {
|
||||
if (ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(Minecraft.getInstance(), event.getScreen(), event.getKeyCode(), event.getScanCode(), event.getModifiers()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardKeyPressedEvent(ScreenEvent.KeyPressed.Post event) {
|
||||
ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(Minecraft.getInstance(), event.getScreen(), event.getKeyCode(), event.getScanCode(), event.getModifiers());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardKeyReleasedEvent(ScreenEvent.KeyReleased.Pre event) {
|
||||
if (ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(Minecraft.getInstance(), event.getScreen(), event.getKeyCode(), event.getScanCode(), event.getModifiers()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventKeyboardKeyReleasedEvent(ScreenEvent.KeyReleased.Post event) {
|
||||
ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(Minecraft.getInstance(), event.getScreen(), event.getKeyCode(), event.getScanCode(), event.getModifiers());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInputEvent(InputEvent.MouseScrollingEvent event) {
|
||||
if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDeltaX(), event.getScrollDeltaY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInputEvent(InputEvent.MouseButton.Pre event) {
|
||||
if (ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getModifiers()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInputEvent(InputEvent.MouseButton.Post event) {
|
||||
ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getModifiers());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventInputEvent(InputEvent.Key event) {
|
||||
ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(Minecraft.getInstance(), event.getKey(), event.getScanCode(), event.getAction(), event.getModifiers());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(RegisterClientCommandsEvent event) {
|
||||
ClientCommandRegistrationEvent.EVENT.invoker().register((CommandDispatcher<ClientCommandRegistrationEvent.ClientCommandSourceStack>)
|
||||
(CommandDispatcher<?>) event.getDispatcher(), event.getBuildContext());
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class ModBasedEventHandler {
|
||||
// @SubscribeEvent(priority = EventPriority.HIGH)
|
||||
// public static void eventTextureStitchEvent(TextureStitchEvent.Post event) {
|
||||
// ClientTextureStitchEvent.POST.invoker().stitch(event.getAtlas());
|
||||
// }
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(FMLClientSetupEvent event) {
|
||||
ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(Minecraft.getInstance());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(RegisterShadersEvent event) {
|
||||
ClientReloadShadersEvent.EVENT.invoker().reload(event.getResourceProvider(), event::registerShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import dev.architectury.event.CompoundEventResult;
|
||||
import dev.architectury.event.EventResult;
|
||||
import dev.architectury.event.events.common.PlayerEvent;
|
||||
import dev.architectury.event.events.common.*;
|
||||
import dev.architectury.utils.value.IntValue;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.LogicalSide;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.neoforged.neoforge.event.CommandEvent;
|
||||
import net.neoforged.neoforge.event.LootTableLoadEvent;
|
||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||
import net.neoforged.neoforge.event.ServerChatEvent;
|
||||
import net.neoforged.neoforge.event.TickEvent.LevelTickEvent;
|
||||
import net.neoforged.neoforge.event.TickEvent.Phase;
|
||||
import net.neoforged.neoforge.event.TickEvent.PlayerTickEvent;
|
||||
import net.neoforged.neoforge.event.TickEvent.ServerTickEvent;
|
||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
||||
import net.neoforged.neoforge.event.entity.item.ItemTossEvent;
|
||||
import net.neoforged.neoforge.event.entity.living.AnimalTameEvent;
|
||||
import net.neoforged.neoforge.event.entity.living.LivingAttackEvent;
|
||||
import net.neoforged.neoforge.event.entity.living.LivingDeathEvent;
|
||||
import net.neoforged.neoforge.event.entity.living.MobSpawnEvent;
|
||||
import net.neoforged.neoforge.event.entity.player.*;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent.*;
|
||||
import net.neoforged.neoforge.event.level.BlockEvent.BreakEvent;
|
||||
import net.neoforged.neoforge.event.level.BlockEvent.EntityPlaceEvent;
|
||||
import net.neoforged.neoforge.event.level.BlockEvent.FarmlandTrampleEvent;
|
||||
import net.neoforged.neoforge.event.level.ChunkDataEvent;
|
||||
import net.neoforged.neoforge.event.level.ExplosionEvent.Detonate;
|
||||
import net.neoforged.neoforge.event.level.ExplosionEvent.Start;
|
||||
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||
import net.neoforged.neoforge.event.server.*;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
|
||||
public class EventHandlerImplCommon {
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerTickEvent event) {
|
||||
if (event.phase == Phase.START)
|
||||
TickEvent.SERVER_PRE.invoker().tick(ServerLifecycleHooks.getCurrentServer());
|
||||
else if (event.phase == Phase.END)
|
||||
TickEvent.SERVER_POST.invoker().tick(ServerLifecycleHooks.getCurrentServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(LevelTickEvent event) {
|
||||
if (event.side == LogicalSide.SERVER) {
|
||||
if (event.phase == Phase.START)
|
||||
TickEvent.SERVER_LEVEL_PRE.invoker().tick((ServerLevel) event.level);
|
||||
else if (event.phase == Phase.END)
|
||||
TickEvent.SERVER_LEVEL_POST.invoker().tick((ServerLevel) event.level);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerStartingEvent event) {
|
||||
LifecycleEvent.SERVER_STARTING.invoker().stateChanged(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerStartedEvent event) {
|
||||
LifecycleEvent.SERVER_STARTED.invoker().stateChanged(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerStoppingEvent event) {
|
||||
LifecycleEvent.SERVER_STOPPING.invoker().stateChanged(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerStoppedEvent event) {
|
||||
LifecycleEvent.SERVER_STOPPED.invoker().stateChanged(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(RegisterCommandsEvent event) {
|
||||
CommandRegistrationEvent.EVENT.invoker().register(event.getDispatcher(), event.getBuildContext(), event.getCommandSelection());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(PlayerLoggedInEvent event) {
|
||||
PlayerEvent.PLAYER_JOIN.invoker().join((ServerPlayer) event.getEntity());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(PlayerLoggedOutEvent event) {
|
||||
PlayerEvent.PLAYER_QUIT.invoker().quit((ServerPlayer) event.getEntity());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(PlayerRespawnEvent event) {
|
||||
PlayerEvent.PLAYER_RESPAWN.invoker().respawn((ServerPlayer) event.getEntity(), event.isEndConquered());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(CommandEvent event) {
|
||||
CommandPerformEvent performEvent = new CommandPerformEvent(event.getParseResults(), event.getException());
|
||||
if (CommandPerformEvent.EVENT.invoker().act(performEvent).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
event.setParseResults(performEvent.getResults());
|
||||
event.setException(performEvent.getThrowable());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(PlayerTickEvent event) {
|
||||
if (event.phase == Phase.START) {
|
||||
TickEvent.PLAYER_PRE.invoker().tick(event.player);
|
||||
} else if (event.phase == Phase.END) {
|
||||
TickEvent.PLAYER_POST.invoker().tick(event.player);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerChatEvent event) {
|
||||
class ChatComponentImpl implements ChatEvent.ChatComponent {
|
||||
@Override
|
||||
public Component get() {
|
||||
return event.getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Component component) {
|
||||
event.setMessage(component);
|
||||
}
|
||||
}
|
||||
ChatEvent.DECORATE.invoker().decorate(event.getPlayer(), new ChatComponentImpl());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
public static void eventAfter(ServerChatEvent event) {
|
||||
EventResult process = ChatEvent.RECEIVED.invoker().received(event.getPlayer(), event.getMessage());
|
||||
if (process.isFalse())
|
||||
event.setCanceled(true);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventWorldEvent(LevelEvent.Load event) {
|
||||
if (event.getLevel() instanceof ServerLevel) {
|
||||
ServerLevel world = (ServerLevel) event.getLevel();
|
||||
LifecycleEvent.SERVER_LEVEL_LOAD.invoker().act(world);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventWorldEvent(LevelEvent.Unload event) {
|
||||
if (event.getLevel() instanceof ServerLevel) {
|
||||
ServerLevel world = (ServerLevel) event.getLevel();
|
||||
LifecycleEvent.SERVER_LEVEL_UNLOAD.invoker().act(world);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventWorldEvent(LevelEvent.Save event) {
|
||||
if (event.getLevel() instanceof ServerLevel) {
|
||||
ServerLevel world = (ServerLevel) event.getLevel();
|
||||
LifecycleEvent.SERVER_LEVEL_SAVE.invoker().act(world);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(LivingDeathEvent event) {
|
||||
if (EntityEvent.LIVING_DEATH.invoker().die(event.getEntity(), event.getSource()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(AdvancementEvent.AdvancementEarnEvent event) {
|
||||
if (event.getEntity() instanceof ServerPlayer) {
|
||||
PlayerEvent.PLAYER_ADVANCEMENT.invoker().award((ServerPlayer) event.getEntity(), event.getAdvancement());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerEvent(Clone event) {
|
||||
if (event.getOriginal() instanceof ServerPlayer && event.getEntity() instanceof ServerPlayer) {
|
||||
PlayerEvent.PLAYER_CLONE.invoker().clone((ServerPlayer) event.getOriginal(), (ServerPlayer) event.getEntity(), !event.isWasDeath());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventExplosionEvent(Start event) {
|
||||
if (ExplosionEvent.PRE.invoker().explode(event.getLevel(), event.getExplosion()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventExplosionEvent(Detonate event) {
|
||||
ExplosionEvent.DETONATE.invoker().explode(event.getLevel(), event.getExplosion(), event.getAffectedEntities());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(LivingAttackEvent event) {
|
||||
if (EntityEvent.LIVING_HURT.invoker().hurt(event.getEntity(), event.getSource(), event.getAmount()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(EntityJoinLevelEvent event) {
|
||||
if (EntityEvent.ADD.invoker().add(event.getEntity(), event.getLevel()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(FarmlandTrampleEvent event) {
|
||||
if (event.getLevel() instanceof Level && InteractionEvent.FARMLAND_TRAMPLE.invoker().trample((Level) event.getLevel(), event.getPos(), event.getState(), event.getFallDistance(), event.getEntity()).value() != null) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(FillBucketEvent event) {
|
||||
ItemStack oldItem = event.getEmptyBucket();
|
||||
CompoundEventResult<ItemStack> result = PlayerEvent.FILL_BUCKET.invoker().fill(event.getEntity(), event.getLevel(), oldItem, event.getTarget());
|
||||
if (result.interruptsFurtherEvaluation()) {
|
||||
event.setCanceled(true);
|
||||
event.setFilledBucket(result.object());
|
||||
|
||||
if (result.value() != null) {
|
||||
event.setResult(result.value() ? Event.Result.ALLOW : Event.Result.DENY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Hook ourselves when mixin is available
|
||||
// @SubscribeEvent(priority = EventPriority.HIGH)
|
||||
// public static void event(EnteringChunk event) {
|
||||
// EntityEvent.ENTER_SECTION.invoker().enterChunk(event.getEntity(), event.getNewChunkX(), event.getNewChunkZ(), event.getOldChunkX(), event.getOldChunkZ());
|
||||
// }
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventLivingSpawnEvent(MobSpawnEvent.FinalizeSpawn event) {
|
||||
EventResult result = EntityEvent.LIVING_CHECK_SPAWN.invoker().canSpawn(event.getEntity(), event.getLevel(), event.getX(), event.getY(), event.getZ(), event.getSpawnType(), event.getSpawner());
|
||||
if (result.interruptsFurtherEvaluation()) {
|
||||
if (!result.isEmpty()) {
|
||||
event.setSpawnCancelled(result.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(AnimalTameEvent event) {
|
||||
EventResult result = EntityEvent.ANIMAL_TAME.invoker().tame(event.getAnimal(), event.getTamer());
|
||||
event.setCanceled(result.isFalse());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ItemCraftedEvent event) {
|
||||
PlayerEvent.CRAFT_ITEM.invoker().craft(event.getEntity(), event.getCrafting(), event.getInventory());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ItemSmeltedEvent event) {
|
||||
PlayerEvent.SMELT_ITEM.invoker().smelt(event.getEntity(), event.getSmelting());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(EntityItemPickupEvent event) {
|
||||
// note: this event is weird, cancel is equivalent to denying the pickup,
|
||||
// and setting the result to ALLOW will pick it up without adding it to the player's inventory
|
||||
var result = PlayerEvent.PICKUP_ITEM_PRE.invoker().canPickup(event.getEntity(), event.getItem(), event.getItem().getItem());
|
||||
if (result.isFalse()) {
|
||||
event.setCanceled(true);
|
||||
} else if (result.isTrue()) {
|
||||
event.setResult(Event.Result.ALLOW);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ItemPickupEvent event) {
|
||||
PlayerEvent.PICKUP_ITEM_POST.invoker().pickup(event.getEntity(), event.getOriginalEntity(), event.getStack());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ItemTossEvent event) {
|
||||
PlayerEvent.DROP_ITEM.invoker().drop(event.getPlayer(), event.getEntity());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerContainerEvent(PlayerContainerEvent.Open event) {
|
||||
PlayerEvent.OPEN_MENU.invoker().open(event.getEntity(), event.getContainer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerContainerEvent(PlayerContainerEvent.Close event) {
|
||||
PlayerEvent.CLOSE_MENU.invoker().close(event.getEntity(), event.getContainer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.RightClickItem event) {
|
||||
CompoundEventResult<ItemStack> result = InteractionEvent.RIGHT_CLICK_ITEM.invoker().click(event.getEntity(), event.getHand());
|
||||
if (result.isPresent()) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(result.result().asMinecraft());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.RightClickBlock event) {
|
||||
EventResult result = InteractionEvent.RIGHT_CLICK_BLOCK.invoker().click(event.getEntity(), event.getHand(), event.getPos(), event.getFace());
|
||||
if (result.isPresent()) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(result.asMinecraft());
|
||||
event.setUseBlock(Event.Result.DENY);
|
||||
event.setUseItem(Event.Result.DENY);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.EntityInteract event) {
|
||||
EventResult result = InteractionEvent.INTERACT_ENTITY.invoker().interact(event.getEntity(), event.getTarget(), event.getHand());
|
||||
if (result.isPresent()) {
|
||||
event.setCanceled(true);
|
||||
event.setCancellationResult(result.asMinecraft());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventPlayerInteractEvent(PlayerInteractEvent.LeftClickBlock event) {
|
||||
if (event.getAction() != PlayerInteractEvent.LeftClickBlock.Action.START) return;
|
||||
EventResult result = InteractionEvent.LEFT_CLICK_BLOCK.invoker().click(event.getEntity(), event.getHand(), event.getPos(), event.getFace());
|
||||
if (result.isPresent()) {
|
||||
event.setCanceled(true);
|
||||
event.setUseBlock(result.value() ? Event.Result.ALLOW : Event.Result.DENY);
|
||||
event.setUseItem(result.value() ? Event.Result.ALLOW : Event.Result.DENY);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(BreakEvent event) {
|
||||
if (event.getPlayer() instanceof ServerPlayer && event.getLevel() instanceof Level) {
|
||||
EventResult result = BlockEvent.BREAK.invoker().breakBlock((Level) event.getLevel(), event.getPos(), event.getState(), (ServerPlayer) event.getPlayer(), new IntValue() {
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
return event.getExpToDrop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(int value) {
|
||||
event.setExpToDrop(value);
|
||||
}
|
||||
});
|
||||
if (result.isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(EntityPlaceEvent event) {
|
||||
if (event.getLevel() instanceof Level) {
|
||||
EventResult result = BlockEvent.PLACE.invoker().placeBlock((Level) event.getLevel(), event.getPos(), event.getState(), event.getEntity());
|
||||
if (result.isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(ServerAboutToStartEvent event) {
|
||||
LifecycleEvent.SERVER_BEFORE_START.invoker().stateChanged(event.getServer());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(PlayerChangedDimensionEvent event) {
|
||||
if (event.getEntity() instanceof ServerPlayer) {
|
||||
PlayerEvent.CHANGE_DIMENSION.invoker().change((ServerPlayer) event.getEntity(), event.getFrom(), event.getTo());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventChunkDataEvent(ChunkDataEvent.Save event) {
|
||||
if (event.getLevel() instanceof ServerLevel) {
|
||||
ChunkEvent.SAVE_DATA.invoker().save(event.getChunk(), (ServerLevel) event.getLevel(), event.getData());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void eventChunkDataEvent(ChunkDataEvent.Load event) {
|
||||
LevelAccessor level = event.getChunk().getWorldForge();
|
||||
if (!(level instanceof ServerLevel) && event instanceof LevelEventAttachment) {
|
||||
level = ((LevelEventAttachment) event).architectury$getAttachedLevel();
|
||||
}
|
||||
ChunkEvent.LOAD_DATA.invoker().load(event.getChunk(), level instanceof ServerLevel ? (ServerLevel) level : null, event.getData());
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(LootTableLoadEvent event) {
|
||||
LootEvent.MODIFY_LOOT_TABLE.invoker().modifyLootTable(ResourceKey.create(Registries.LOOT_TABLE, event.getName()), new LootTableModificationContextImpl(event.getTable()), true);
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(AttackEntityEvent event) {
|
||||
EventResult result = PlayerEvent.ATTACK_ENTITY.invoker().attack(event.getEntity(), event.getEntity().level(), event.getTarget(), event.getEntity().getUsedItemHand(), null);
|
||||
if (result.isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public interface LevelEventAttachment {
|
||||
LevelAccessor architectury$getAttachedLevel();
|
||||
|
||||
void architectury$attachLevel(LevelAccessor level);
|
||||
}
|
||||
|
||||
public static class ModBasedEventHandler {
|
||||
@SubscribeEvent(priority = EventPriority.HIGH)
|
||||
public static void event(FMLCommonSetupEvent event) {
|
||||
LifecycleEvent.SETUP.invoker().run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.DEDICATED_SERVER)
|
||||
public class EventHandlerImplServer {
|
||||
@OnlyIn(Dist.DEDICATED_SERVER)
|
||||
public static class ModBasedEventHandler {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.event.forge;
|
||||
|
||||
import dev.architectury.event.events.common.LootEvent;
|
||||
import net.minecraft.world.level.storage.loot.LootPool;
|
||||
import net.minecraft.world.level.storage.loot.LootTable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
final class LootTableModificationContextImpl implements LootEvent.LootTableModificationContext {
|
||||
private final LootTable table;
|
||||
private final List<LootPool> pools;
|
||||
|
||||
LootTableModificationContextImpl(LootTable table) {
|
||||
this.table = table;
|
||||
|
||||
// This field has the type changed to List<LootPool> by Forge
|
||||
// Since this is rather unsafe, we are making sure 100% we are getting it
|
||||
List<LootPool> pools = null;
|
||||
try {
|
||||
Field field = LootTable.class.getDeclaredField("pools");
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
pools = (List<LootPool>) field.get(table);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} catch (NoSuchFieldException ignored3) {
|
||||
for (Field field : LootTable.class.getDeclaredFields()) {
|
||||
if (field.getType().equals(List.class)) {
|
||||
// This is probably the field
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
pools = (List<LootPool>) field.get(table);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pools == null) {
|
||||
throw new RuntimeException("Unable to find pools field in LootTable!");
|
||||
}
|
||||
}
|
||||
|
||||
this.pools = pools;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPool(LootPool.Builder pool) {
|
||||
this.pools.add(pool.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.fluid.forge;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import dev.architectury.hooks.fluid.forge.FluidStackHooksForge;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.component.PatchedDataComponentMap;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import static dev.architectury.utils.Amount.toInt;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public enum FluidStackImpl implements dev.architectury.fluid.FluidStack.FluidStackAdapter<FluidStack> {
|
||||
INSTANCE;
|
||||
|
||||
static {
|
||||
dev.architectury.fluid.FluidStack.init();
|
||||
}
|
||||
|
||||
public static Function<dev.architectury.fluid.FluidStack, Object> toValue;
|
||||
public static Function<Object, dev.architectury.fluid.FluidStack> fromValue;
|
||||
|
||||
public static dev.architectury.fluid.FluidStack.FluidStackAdapter<Object> adapt(Function<dev.architectury.fluid.FluidStack, Object> toValue, Function<Object, dev.architectury.fluid.FluidStack> fromValue) {
|
||||
FluidStackImpl.toValue = toValue;
|
||||
FluidStackImpl.fromValue = fromValue;
|
||||
return (dev.architectury.fluid.FluidStack.FluidStackAdapter<Object>) (dev.architectury.fluid.FluidStack.FluidStackAdapter<?>) INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack create(Supplier<Fluid> fluid, long amount, @Nullable DataComponentPatch patch) {
|
||||
@SuppressWarnings("deprecation")
|
||||
Holder<Fluid> holder = Objects.requireNonNull(fluid).get().builtInRegistryHolder();
|
||||
if (patch == null) {
|
||||
return new FluidStack(holder, toInt(amount));
|
||||
} else {
|
||||
return new FluidStack(holder, toInt(amount), patch);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Fluid> getRawFluidSupplier(FluidStack object) {
|
||||
return () -> object.getFluidHolder().value();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fluid getFluid(FluidStack object) {
|
||||
return object.getFluid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAmount(FluidStack object) {
|
||||
return object.getAmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAmount(FluidStack object, long amount) {
|
||||
object.setAmount(toInt(amount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataComponentPatch getPatch(FluidStack value) {
|
||||
return value.getComponentsPatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PatchedDataComponentMap getComponents(FluidStack value) {
|
||||
return value.getComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyComponents(FluidStack value, DataComponentPatch patch) {
|
||||
value.applyComponents(patch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyComponents(FluidStack value, DataComponentMap patch) {
|
||||
value.applyComponents(patch);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D set(FluidStack value, DataComponentType<? super D> type, @Nullable D component) {
|
||||
return value.set(type, component);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D remove(FluidStack value, DataComponentType<? extends D> type) {
|
||||
return value.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D> D update(FluidStack value, DataComponentType<D> type, D component, UnaryOperator<D> updater) {
|
||||
return value.update(type, component, updater);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <D, U> D update(FluidStack value, DataComponentType<D> type, D component, U updateContext, BiFunction<D, U, D> updater) {
|
||||
return value.update(type, component, updateContext, updater);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FluidStack copy(FluidStack value) {
|
||||
return value.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(FluidStack value) {
|
||||
var code = 1;
|
||||
code = 31 * code + value.getFluid().hashCode();
|
||||
code = 31 * code + value.getAmount();
|
||||
code = 31 * code + value.getComponents().hashCode();
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Codec<dev.architectury.fluid.FluidStack> codec() {
|
||||
return FluidStack.CODEC.xmap(FluidStackHooksForge::fromForge, FluidStackHooksForge::toForge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamCodec<RegistryFriendlyByteBuf, dev.architectury.fluid.FluidStack> streamCodec() {
|
||||
return FluidStack.STREAM_CODEC.map(FluidStackHooksForge::fromForge, FluidStackHooksForge::toForge);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.client.screen.forge;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Renderable;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ScreenHooksImpl {
|
||||
public static List<NarratableEntry> getNarratables(Screen screen) {
|
||||
return screen.narratables;
|
||||
}
|
||||
|
||||
public static List<Renderable> getRenderables(Screen screen) {
|
||||
return screen.renderables;
|
||||
}
|
||||
|
||||
public static <T extends AbstractWidget & Renderable & NarratableEntry> T addRenderableWidget(Screen screen, T widget) {
|
||||
return screen.addRenderableWidget(widget);
|
||||
}
|
||||
|
||||
public static <T extends Renderable> T addRenderableOnly(Screen screen, T listener) {
|
||||
return screen.addRenderableOnly(listener);
|
||||
}
|
||||
|
||||
public static <T extends GuiEventListener & NarratableEntry> T addWidget(Screen screen, T listener) {
|
||||
return screen.addWidget(listener);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.fluid.forge;
|
||||
|
||||
import net.minecraft.world.item.BucketItem;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
public class FluidBucketHooksImpl {
|
||||
public static Fluid getFluid(BucketItem item) {
|
||||
return item.getFluid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.fluid.forge;
|
||||
|
||||
import dev.architectury.fluid.FluidStack;
|
||||
import dev.architectury.fluid.forge.FluidStackImpl;
|
||||
|
||||
public final class FluidStackHooksForge {
|
||||
private FluidStackHooksForge() {
|
||||
}
|
||||
|
||||
public static FluidStack fromForge(net.neoforged.neoforge.fluids.FluidStack stack) {
|
||||
return FluidStackImpl.fromValue.apply(stack);
|
||||
}
|
||||
|
||||
public static net.neoforged.neoforge.fluids.FluidStack toForge(FluidStack stack) {
|
||||
return (net.neoforged.neoforge.fluids.FluidStack) FluidStackImpl.toValue.apply(stack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.fluid.forge;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.architectury.fluid.FluidStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.client.extensions.common.IClientFluidTypeExtensions;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class FluidStackHooksImpl {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static Component getName(FluidStack stack) {
|
||||
return stack.getFluid().getFluidType().getDescription(FluidStackHooksForge.toForge(stack));
|
||||
}
|
||||
|
||||
public static String getTranslationKey(FluidStack stack) {
|
||||
return stack.getFluid().getFluidType().getDescriptionId(FluidStackHooksForge.toForge(stack));
|
||||
}
|
||||
|
||||
public static FluidStack read(RegistryFriendlyByteBuf buf) {
|
||||
return FluidStack.STREAM_CODEC.decode(buf);
|
||||
}
|
||||
|
||||
public static void write(FluidStack stack, RegistryFriendlyByteBuf buf) {
|
||||
FluidStack.STREAM_CODEC.encode(buf, stack);
|
||||
}
|
||||
|
||||
public static Optional<FluidStack> read(HolderLookup.Provider provider, Tag tag) {
|
||||
return FluidStack.CODEC.parse(provider.createSerializationContext(NbtOps.INSTANCE), tag)
|
||||
.resultOrPartial(string -> LOGGER.error("Tried to load invalid fluid stack: '{}'", string));
|
||||
}
|
||||
|
||||
public static FluidStack readOptional(HolderLookup.Provider provider, CompoundTag tag) {
|
||||
return tag.isEmpty() ? FluidStack.empty() : read(provider, tag).orElse(FluidStack.empty());
|
||||
}
|
||||
|
||||
public static Tag write(HolderLookup.Provider provider, FluidStack stack, Tag tag) {
|
||||
return FluidStack.CODEC.encode(stack, provider.createSerializationContext(NbtOps.INSTANCE), tag).getOrThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
public static long bucketAmount() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getStillTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, FluidState state) {
|
||||
if (state.getType() == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(state).getStillTexture(state, level, pos);
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getStillTexture(FluidStack stack) {
|
||||
if (stack.getFluid() == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(stack.getFluid()).getStillTexture(FluidStackHooksForge.toForge(stack));
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getStillTexture(Fluid fluid) {
|
||||
if (fluid == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(fluid).getStillTexture();
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getFlowingTexture(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, FluidState state) {
|
||||
if (state.getType() == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(state).getFlowingTexture(state, level, pos);
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getFlowingTexture(FluidStack stack) {
|
||||
if (stack.getFluid() == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(stack.getFluid()).getFlowingTexture(FluidStackHooksForge.toForge(stack));
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Nullable
|
||||
public static TextureAtlasSprite getFlowingTexture(Fluid fluid) {
|
||||
if (fluid == Fluids.EMPTY) return null;
|
||||
ResourceLocation texture = IClientFluidTypeExtensions.of(fluid).getFlowingTexture();
|
||||
return Minecraft.getInstance().getTextureAtlas(TextureAtlas.LOCATION_BLOCKS).apply(texture);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static int getColor(@Nullable BlockAndTintGetter level, @Nullable BlockPos pos, FluidState state) {
|
||||
if (state.getType() == Fluids.EMPTY) return -1;
|
||||
return IClientFluidTypeExtensions.of(state).getTintColor(state, level, pos);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static int getColor(FluidStack stack) {
|
||||
if (stack.getFluid() == Fluids.EMPTY) return -1;
|
||||
return IClientFluidTypeExtensions.of(stack.getFluid()).getTintColor(FluidStackHooksForge.toForge(stack));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static int getColor(Fluid fluid) {
|
||||
if (fluid == Fluids.EMPTY) return -1;
|
||||
return IClientFluidTypeExtensions.of(fluid).getTintColor();
|
||||
}
|
||||
|
||||
public static int getLuminosity(FluidStack fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
return fluid.getFluid().getFluidType().getLightLevel(FluidStackHooksForge.toForge(fluid));
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public static int getLuminosity(Fluid fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
if (level != null && pos != null) {
|
||||
var state = level.getFluidState(pos);
|
||||
return fluid.getFluidType().getLightLevel(state, level, pos);
|
||||
}
|
||||
|
||||
return fluid.getFluidType().getLightLevel();
|
||||
}
|
||||
|
||||
public static int getTemperature(FluidStack fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
return fluid.getFluid().getFluidType().getTemperature(FluidStackHooksForge.toForge(fluid));
|
||||
}
|
||||
|
||||
public static int getTemperature(Fluid fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
if (level != null && pos != null) {
|
||||
var state = level.getFluidState(pos);
|
||||
return fluid.getFluidType().getTemperature(state, level, pos);
|
||||
}
|
||||
|
||||
return fluid.getFluidType().getTemperature();
|
||||
}
|
||||
|
||||
public static int getViscosity(FluidStack fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
return fluid.getFluid().getFluidType().getViscosity(FluidStackHooksForge.toForge(fluid));
|
||||
}
|
||||
|
||||
public static int getViscosity(Fluid fluid, @Nullable Level level, @Nullable BlockPos pos) {
|
||||
if (level != null && pos != null) {
|
||||
var state = level.getFluidState(pos);
|
||||
return fluid.getFluidType().getViscosity(state, level, pos);
|
||||
}
|
||||
|
||||
return fluid.getFluidType().getViscosity();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.fluid.forge;
|
||||
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
|
||||
public class LiquidBlockHooksImpl {
|
||||
public static FlowingFluid getFluid(LiquidBlock block) {
|
||||
return block.getFluid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.forge;
|
||||
|
||||
import net.minecraft.world.item.DyeColor;
|
||||
|
||||
public class DyeColorHooksImpl {
|
||||
public static int getColorValue(DyeColor dyeColor) {
|
||||
var colors = dyeColor.getTextureDiffuseColors();
|
||||
return ((int) (colors[0] * 255.0F + 0.5D) & 255) << 16 | ((int) (colors[1] * 255.0F + 0.5D) & 255) << 8 | (int) (colors[2] * 255.0F + 0.5D);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.forge;
|
||||
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.server.packs.repository.RepositorySource;
|
||||
|
||||
public class PackRepositoryHooksImpl {
|
||||
public static void addSource(PackRepository repository, RepositorySource source) {
|
||||
repository.addPackFinder(source);
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.forgelike.forge;
|
||||
|
||||
import dev.architectury.event.events.client.ClientRawInputEvent;
|
||||
import dev.architectury.event.events.client.ClientScreenInputEvent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent;
|
||||
import net.neoforged.neoforge.client.event.InputEvent;
|
||||
import net.neoforged.neoforge.client.event.ScreenEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ForgeLikeClientHooksImpl {
|
||||
public static void preMouseScroll(ScreenEvent.MouseScrolled.Pre event) {
|
||||
if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getScrollDeltaX(), event.getScrollDeltaY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void postMouseScroll(ScreenEvent.MouseScrolled.Post event) {
|
||||
ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getScreen(), event.getMouseX(), event.getMouseY(), event.getScrollDeltaX(), event.getScrollDeltaY());
|
||||
}
|
||||
|
||||
public static void inputMouseScroll(InputEvent.MouseScrollingEvent event) {
|
||||
if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDeltaX(), event.getScrollDeltaY()).isFalse()) {
|
||||
event.setCanceled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getLeft(CustomizeGuiOverlayEvent.DebugText event) {
|
||||
return event.getLeft();
|
||||
}
|
||||
|
||||
public static List<String> getRight(CustomizeGuiOverlayEvent.DebugText event) {
|
||||
return event.getRight();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.item.food.forge;
|
||||
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class FoodPropertiesHooksImpl {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void effect(FoodProperties.Builder builder,
|
||||
Supplier<? extends MobEffectInstance> effectSupplier, float chance) {
|
||||
builder.effect((Supplier<MobEffectInstance>) effectSupplier, chance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.item.forge;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public class ItemStackHooksImpl {
|
||||
public static boolean hasCraftingRemainingItem(ItemStack stack) {
|
||||
return stack.hasCraftingRemainingItem();
|
||||
}
|
||||
|
||||
public static ItemStack getCraftingRemainingItem(ItemStack stack) {
|
||||
return stack.getCraftingRemainingItem();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.item.tool.forge;
|
||||
|
||||
import net.minecraft.world.item.context.UseOnContext;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.common.ToolActions;
|
||||
import net.neoforged.neoforge.event.level.BlockEvent;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class HoeItemHooksImpl {
|
||||
public static void addTillable(Block input, Predicate<UseOnContext> predicate, Consumer<UseOnContext> action, Function<UseOnContext, BlockState> function) {
|
||||
NeoForge.EVENT_BUS.<BlockEvent.BlockToolModificationEvent>addListener(event -> {
|
||||
UseOnContext context = event.getContext();
|
||||
if (ToolActions.HOE_TILL == event.getToolAction() && context.getItemInHand().canPerformAction(ToolActions.HOE_TILL)
|
||||
&& event.getState().is(input) && predicate.test(context)) {
|
||||
if (!event.isSimulated()) {
|
||||
action.accept(context);
|
||||
}
|
||||
|
||||
event.setFinalState(function.apply(context));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.level.biome.forge;
|
||||
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
|
||||
public class BiomeHooksImpl {
|
||||
public static Biome.ClimateSettings extractClimateSettings(Biome biome) {
|
||||
return biome.getModifiedClimateSettings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.level.entity.forge;
|
||||
|
||||
import dev.architectury.utils.value.IntValue;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
|
||||
public class ItemEntityHooksImpl {
|
||||
public static IntValue lifespan(ItemEntity entity) {
|
||||
return new IntValue() {
|
||||
@Override
|
||||
public void accept(int value) {
|
||||
entity.lifespan = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
return entity.lifespan;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.hooks.level.entity.forge;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public class PlayerHooksImpl {
|
||||
public static boolean isFake(Player playerEntity) {
|
||||
return playerEntity instanceof ServerPlayer && playerEntity.getClass() != ServerPlayer.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge;
|
||||
|
||||
import dev.architectury.event.events.client.ClientTickEvent;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(ClientLevel.class)
|
||||
public abstract class MixinClientLevel extends Level {
|
||||
protected MixinClientLevel(WritableLevelData arg, ResourceKey<Level> arg2, RegistryAccess arg3, Holder<DimensionType> arg4, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
|
||||
super(arg, arg2, arg3, arg4, supplier, bl, bl2, l, i);
|
||||
}
|
||||
|
||||
@Inject(method = "tickEntities", at = @At("HEAD"))
|
||||
private void tickEntities(CallbackInfo ci) {
|
||||
ProfilerFiller profiler = getProfiler();
|
||||
profiler.push("architecturyClientLevelPreTick");
|
||||
ClientTickEvent.CLIENT_LEVEL_PRE.invoker().tick((ClientLevel) (Object) this);
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
@Inject(method = "tickEntities", at = @At("RETURN"))
|
||||
private void tickEntitiesPost(CallbackInfo ci) {
|
||||
ProfilerFiller profiler = getProfiler();
|
||||
profiler.push("architecturyClientLevelPostTick");
|
||||
ClientTickEvent.CLIENT_LEVEL_POST.invoker().tick((ClientLevel) (Object) this);
|
||||
profiler.pop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge;
|
||||
|
||||
import dev.architectury.event.events.common.BlockEvent;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(FallingBlockEntity.class)
|
||||
public abstract class MixinFallingBlockEntity extends Entity {
|
||||
public MixinFallingBlockEntity(EntityType<?> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private BlockState blockState;
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/Fallable;onLand(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/item/FallingBlockEntity;)V"),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
public void handleLand(CallbackInfo ci, Block block, BlockPos blockPos2, boolean bl, boolean bl2, double d, BlockState blockState) {
|
||||
BlockEvent.FALLING_LAND.invoker().onLand(this.level(), blockPos2, this.blockState, blockState, (FallingBlockEntity) (Object) this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge;
|
||||
|
||||
import dev.architectury.extensions.ItemExtension;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.neoforged.neoforge.common.extensions.IItemExtension;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(ItemExtension.class)
|
||||
public interface MixinItemExtension extends IItemExtension {
|
||||
@Override
|
||||
default void onArmorTick(ItemStack stack, Level world, Player player) {
|
||||
((ItemExtension) this).tickArmor(stack, player);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
default EquipmentSlot getEquipmentSlot(ItemStack stack) {
|
||||
return ((ItemExtension) this).getCustomEquipmentSlot(stack);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge;
|
||||
|
||||
import dev.architectury.event.forge.EventHandlerImplCommon;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.neoforged.neoforge.event.level.LevelEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
@Mixin(LevelEvent.class)
|
||||
public class MixinLevelEvent implements EventHandlerImplCommon.LevelEventAttachment {
|
||||
@Unique
|
||||
private WeakReference<LevelAccessor> level;
|
||||
|
||||
@Override
|
||||
public LevelAccessor architectury$getAttachedLevel() {
|
||||
return level == null ? null : level.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void architectury$attachLevel(LevelAccessor level) {
|
||||
this.level = new WeakReference<>(level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge;
|
||||
|
||||
import dev.architectury.event.events.client.ClientLifecycleEvent;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
// adopted from fabric
|
||||
@Mixin(Minecraft.class)
|
||||
public abstract class MixinMinecraft {
|
||||
@Inject(at = @At(value = "INVOKE", target = "Ljava/lang/Runtime;getRuntime()Ljava/lang/Runtime;", ordinal = 0), method = "run")
|
||||
private void onStart(CallbackInfo ci) {
|
||||
ClientLifecycleEvent.CLIENT_STARTED.invoker().stateChanged((Minecraft) (Object) this);
|
||||
}
|
||||
|
||||
// using {1} rather than Log4j directly for 1.18.2+ support
|
||||
@Inject(at = @At(value = "INVOKE", target = "{1}(Ljava/lang/String;)V" /* Logger.info */, shift = At.Shift.AFTER, remap = false), method = "destroy")
|
||||
private void onStopping(CallbackInfo ci) {
|
||||
ClientLifecycleEvent.CLIENT_STOPPING.invoker().stateChanged((Minecraft) (Object) this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.mixin.forge.client;
|
||||
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import dev.architectury.event.events.client.ClientCommandRegistrationEvent;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Mixin(CommandSourceStack.class)
|
||||
public abstract class MixinCommandSourceStack implements ClientCommandRegistrationEvent.ClientCommandSourceStack {
|
||||
@Override
|
||||
public void arch$sendSuccess(Supplier<Component> message, boolean broadcastToAdmins) {
|
||||
((CommandSourceStack) (Object) this).sendSuccess(message, broadcastToAdmins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void arch$sendFailure(Component message) {
|
||||
((CommandSourceStack) (Object) this).sendFailure(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalPlayer arch$getPlayer() {
|
||||
try {
|
||||
return (LocalPlayer) ((CommandSourceStack) (Object) this).getEntityOrException();
|
||||
} catch (CommandSyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 arch$getPosition() {
|
||||
return ((CommandSourceStack) (Object) this).getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2 arch$getRotation() {
|
||||
return ((CommandSourceStack) (Object) this).getRotation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientLevel arch$getLevel() {
|
||||
return (ClientLevel) ((CommandSourceStack) (Object) this).getUnsidedLevel();
|
||||
}
|
||||
}
|
||||
@@ -34,5 +34,6 @@ public class ArchitecturyNeoForge {
|
||||
BiomeModificationsImpl.init();
|
||||
|
||||
EnvExecutor.runInEnv(Env.CLIENT, () -> SpawnEntityPacket.Client::register);
|
||||
EnvExecutor.runInEnv(Env.SERVER, () -> SpawnEntityPacket::register);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,27 +19,26 @@
|
||||
|
||||
package dev.architectury.networking.forge;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Wraps a {@link FriendlyByteBuf} because NeoForge doesn't easily let us use the buf directly.
|
||||
*/
|
||||
public record BufCustomPacketPayload(ResourceLocation type, byte[] payload) implements CustomPacketPayload {
|
||||
public BufCustomPacketPayload(FriendlyByteBuf buf) {
|
||||
this(buf.readResourceLocation(), buf.readByteArray());
|
||||
public record BufCustomPacketPayload(Type<BufCustomPacketPayload> type, byte[] payload) implements CustomPacketPayload {
|
||||
public BufCustomPacketPayload(Type<BufCustomPacketPayload> type, RegistryFriendlyByteBuf buf) {
|
||||
this(type, buf.readByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
buf.writeResourceLocation(type);
|
||||
public void write(RegistryFriendlyByteBuf buf) {
|
||||
buf.writeByteArray(payload);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return NetworkManagerImpl.CHANNEL_ID;
|
||||
public static StreamCodec<ByteBuf, BufCustomPacketPayload> streamCodec(Type<BufCustomPacketPayload> type) {
|
||||
return ByteBufCodecs.BYTE_ARRAY.map(bytes -> new BufCustomPacketPayload(type, bytes), BufCustomPacketPayload::payload);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
package dev.architectury.networking.forge;
|
||||
|
||||
import dev.architectury.impl.NetworkAggregator;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
@@ -28,18 +30,16 @@ import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.network.handling.IPlayPayloadHandler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ClientNetworkingManager {
|
||||
public static IPlayPayloadHandler<BufCustomPacketPayload> initClient() {
|
||||
var handler = NetworkManagerImpl.createPacketHandler(NetworkManager.Side.S2C, NetworkManagerImpl.S2C_TRANSFORMERS);
|
||||
public static void initClient() {
|
||||
NeoForge.EVENT_BUS.register(ClientNetworkingManager.class);
|
||||
|
||||
NetworkManagerImpl.registerS2CReceiver(NetworkManagerImpl.SYNC_IDS, Collections.emptyList(), (buffer, context) -> {
|
||||
NetworkManager.registerReceiver(NetworkManager.Side.S2C, NetworkManagerImpl.SYNC_IDS_S2C, Collections.emptyList(), (buffer, context) -> {
|
||||
Set<ResourceLocation> receivables = NetworkManagerImpl.serverReceivables;
|
||||
int size = buffer.readInt();
|
||||
receivables.clear();
|
||||
@@ -47,17 +47,23 @@ public class ClientNetworkingManager {
|
||||
receivables.add(buffer.readResourceLocation());
|
||||
}
|
||||
context.queue(() -> {
|
||||
NetworkManager.sendToServer(NetworkManagerImpl.SYNC_IDS, NetworkManagerImpl.sendSyncPacket(NetworkManagerImpl.C2S));
|
||||
NetworkManager.sendToServer(NetworkManagerImpl.SYNC_IDS_C2S, NetworkManagerImpl.sendSyncPacket(NetworkAggregator.C2S_RECEIVER, context.registryAccess()));
|
||||
});
|
||||
});
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
public static Player getClientPlayer() {
|
||||
return Minecraft.getInstance().player;
|
||||
}
|
||||
|
||||
public static RegistryAccess getClientRegistryAccess() {
|
||||
if (Minecraft.getInstance().level != null) {
|
||||
return Minecraft.getInstance().level.registryAccess();
|
||||
}
|
||||
|
||||
return Minecraft.getInstance().getConnection().registryAccess();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void loggedOut(ClientPlayerNetworkEvent.LoggingOut event) {
|
||||
NetworkManagerImpl.serverReceivables.clear();
|
||||
|
||||
@@ -22,152 +22,133 @@ package dev.architectury.networking.forge;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.architectury.impl.NetworkAggregator;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.NetworkManager.NetworkReceiver;
|
||||
import dev.architectury.networking.SpawnEntityPacket;
|
||||
import dev.architectury.networking.transformers.PacketSink;
|
||||
import dev.architectury.networking.transformers.PacketTransformer;
|
||||
import dev.architectury.platform.hooks.forge.EventBusesHooksImpl;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import dev.architectury.utils.Env;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import dev.architectury.utils.EnvExecutor;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.DistExecutor;
|
||||
import net.neoforged.fml.LogicalSide;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
|
||||
import net.neoforged.neoforge.network.handling.IPlayPayloadHandler;
|
||||
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import net.neoforged.neoforge.network.handling.ISynchronizedWorkHandler;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dev.architectury.networking.forge.ClientNetworkingManager.getClientPlayer;
|
||||
import static dev.architectury.networking.forge.ClientNetworkingManager.getClientRegistryAccess;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ArchitecturyConstants.MOD_ID)
|
||||
public class NetworkManagerImpl {
|
||||
public static void registerReceiver(NetworkManager.Side side, ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
Objects.requireNonNull(id, "Cannot register receiver with a null ID!");
|
||||
packetTransformers = Objects.requireNonNullElse(packetTransformers, List.of());
|
||||
Objects.requireNonNull(receiver, "Cannot register a null receiver!");
|
||||
if (side == NetworkManager.Side.C2S) {
|
||||
registerC2SReceiver(id, packetTransformers, receiver);
|
||||
} else if (side == NetworkManager.Side.S2C) {
|
||||
registerS2CReceiver(id, packetTransformers, receiver);
|
||||
}
|
||||
}
|
||||
|
||||
public static Packet<?> toPacket(NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buffer) {
|
||||
try {
|
||||
return side == NetworkManager.Side.C2S ? new ServerboundCustomPayloadPacket(new BufCustomPacketPayload(id, ByteBufUtil.getBytes(buffer))) : new ClientboundCustomPayloadPacket(new BufCustomPacketPayload(id, ByteBufUtil.getBytes(buffer)));
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectPackets(PacketSink sink, NetworkManager.Side side, ResourceLocation id, FriendlyByteBuf buf) {
|
||||
PacketTransformer transformer = side == NetworkManager.Side.C2S ? C2S_TRANSFORMERS.get(id) : S2C_TRANSFORMERS.get(id);
|
||||
if (transformer != null) {
|
||||
transformer.outbound(side, id, buf, (side1, id1, buf1) -> {
|
||||
sink.accept(toPacket(side1, id1, buf1));
|
||||
});
|
||||
} else {
|
||||
sink.accept(toPacket(side, id, buf));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
static final ResourceLocation CHANNEL_ID = new ResourceLocation("architectury:network");
|
||||
static final ResourceLocation SYNC_IDS = new ResourceLocation("architectury:sync_ids");
|
||||
static final Map<ResourceLocation, NetworkReceiver> S2C = Maps.newHashMap();
|
||||
static final Map<ResourceLocation, NetworkReceiver> C2S = Maps.newHashMap();
|
||||
static final Map<ResourceLocation, PacketTransformer> S2C_TRANSFORMERS = Maps.newHashMap();
|
||||
static final Map<ResourceLocation, PacketTransformer> C2S_TRANSFORMERS = Maps.newHashMap();
|
||||
static final ResourceLocation SYNC_IDS_S2C = new ResourceLocation("architectury:sync_ids_s2c");
|
||||
static final ResourceLocation SYNC_IDS_C2S = new ResourceLocation("architectury:sync_ids_c2s");
|
||||
static final Set<ResourceLocation> serverReceivables = Sets.newHashSet();
|
||||
private static final Multimap<Player, ResourceLocation> clientReceivables = Multimaps.newMultimap(Maps.newHashMap(), Sets::newHashSet);
|
||||
|
||||
static {
|
||||
EventBusesHooksImpl.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.addListener(NetworkManagerImpl::registerPackets);
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient);
|
||||
NetworkManager.registerReceiver(NetworkManager.Side.C2S, SYNC_IDS_C2S, Collections.emptyList(), (buffer, context) -> {
|
||||
Set<ResourceLocation> receivables = (Set<ResourceLocation>) clientReceivables.get(context.getPlayer());
|
||||
int size = buffer.readInt();
|
||||
receivables.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
receivables.add(buffer.readResourceLocation());
|
||||
}
|
||||
});
|
||||
EnvExecutor.runInEnv(Env.SERVER, () -> () -> NetworkManager.registerS2CPayloadType(SYNC_IDS_S2C));
|
||||
}
|
||||
|
||||
static IPlayPayloadHandler<BufCustomPacketPayload> createPacketHandler(NetworkManager.Side direction, Map<ResourceLocation, PacketTransformer> map) {
|
||||
return (arg, context) -> {
|
||||
NetworkManager.Side side = side(context.flow());
|
||||
if (side != direction) return;
|
||||
ResourceLocation type = arg.type();
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(arg.payload()));
|
||||
PacketTransformer transformer = map.get(type);
|
||||
|
||||
try {
|
||||
if (transformer != null) {
|
||||
NetworkManager.PacketContext packetContext = new NetworkManager.PacketContext() {
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return getEnvironment() == Env.CLIENT ? getClientPlayer() : context.player().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queue(Runnable runnable) {
|
||||
context.workHandler().submitAsync(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Env getEnvironment() {
|
||||
return context.flow().getReceptionSide() == LogicalSide.CLIENT ? Env.CLIENT : Env.SERVER;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private Player getClientPlayer() {
|
||||
return DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::getClientPlayer);
|
||||
}
|
||||
};
|
||||
|
||||
transformer.inbound(side, type, buf, packetContext, (side1, id1, buf1) -> {
|
||||
NetworkReceiver networkReceiver = side == NetworkManager.Side.C2S ? C2S.get(id1) : S2C.get(id1);
|
||||
if (networkReceiver == null) {
|
||||
throw new IllegalArgumentException("Network Receiver not found! " + id1);
|
||||
}
|
||||
networkReceiver.receive(buf1, packetContext);
|
||||
public static NetworkAggregator.Adaptor getAdaptor() {
|
||||
return new NetworkAggregator.Adaptor() {
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> void registerC2S(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkReceiver<T> receiver) {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterPayloadHandlerEvent>addListener(event -> {
|
||||
event.registrar(type.id().getNamespace()).optional().play(type, codec, (arg, context) -> {
|
||||
receiver.receive(arg, context(context.player().orElse(null), context.workHandler(), false));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
LOGGER.error("Unknown message ID: " + type);
|
||||
}
|
||||
} finally {
|
||||
buf.release();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> void registerS2C(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec, NetworkReceiver<T> receiver) {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterPayloadHandlerEvent>addListener(event -> {
|
||||
event.registrar(type.id().getNamespace()).optional().play(type, codec, (arg, context) -> {
|
||||
receiver.receive(arg, context(context.player().orElse(null), context.workHandler(), true));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> Packet<?> toC2SPacket(T payload) {
|
||||
return new ServerboundCustomPayloadPacket(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> Packet<?> toS2CPacket(T payload) {
|
||||
return new ClientboundCustomPayloadPacket(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends CustomPacketPayload> void registerS2CType(CustomPacketPayload.Type<T> type, StreamCodec<? super RegistryFriendlyByteBuf, T> codec) {
|
||||
registerS2C(type, codec, (payload, context) -> {
|
||||
});
|
||||
}
|
||||
|
||||
public NetworkManager.PacketContext context(Player player, ISynchronizedWorkHandler taskQueue, boolean client) {
|
||||
return new NetworkManager.PacketContext() {
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
return getEnvironment() == Env.CLIENT ? getClientPlayer() : player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queue(Runnable runnable) {
|
||||
taskQueue.submitAsync(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Env getEnvironment() {
|
||||
return client ? Env.CLIENT : Env.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegistryAccess registryAccess() {
|
||||
return getEnvironment() == Env.CLIENT ? getClientRegistryAccess() : player.registryAccess();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void registerS2CReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
LOGGER.info("Registering S2C receiver with id {}", id);
|
||||
S2C.put(id, receiver);
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
S2C_TRANSFORMERS.put(id, transformer);
|
||||
}
|
||||
|
||||
public static void registerC2SReceiver(ResourceLocation id, List<PacketTransformer> packetTransformers, NetworkReceiver receiver) {
|
||||
LOGGER.info("Registering C2S receiver with id {}", id);
|
||||
C2S.put(id, receiver);
|
||||
PacketTransformer transformer = PacketTransformer.concat(packetTransformers);
|
||||
C2S_TRANSFORMERS.put(id, transformer);
|
||||
}
|
||||
|
||||
public static boolean canServerReceive(ResourceLocation id) {
|
||||
return serverReceivables.contains(id);
|
||||
}
|
||||
@@ -180,9 +161,9 @@ public class NetworkManagerImpl {
|
||||
return SpawnEntityPacket.create(entity);
|
||||
}
|
||||
|
||||
static FriendlyByteBuf sendSyncPacket(Map<ResourceLocation, NetworkReceiver> map) {
|
||||
static RegistryFriendlyByteBuf sendSyncPacket(Map<ResourceLocation, ?> map, RegistryAccess access) {
|
||||
List<ResourceLocation> availableIds = Lists.newArrayList(map.keySet());
|
||||
FriendlyByteBuf packetBuffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
RegistryFriendlyByteBuf packetBuffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), access);
|
||||
packetBuffer.writeInt(availableIds.size());
|
||||
for (ResourceLocation availableId : availableIds) {
|
||||
packetBuffer.writeResourceLocation(availableId);
|
||||
@@ -192,7 +173,7 @@ public class NetworkManagerImpl {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void loggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
NetworkManager.sendToPlayer((ServerPlayer) event.getEntity(), SYNC_IDS, sendSyncPacket(C2S));
|
||||
NetworkManager.sendToPlayer((ServerPlayer) event.getEntity(), SYNC_IDS_S2C, sendSyncPacket(NetworkAggregator.C2S_RECEIVER, event.getEntity().registryAccess()));
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@@ -200,29 +181,6 @@ public class NetworkManagerImpl {
|
||||
clientReceivables.removeAll(event.getEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* Needs to be on the mod bus for some reason...
|
||||
*/
|
||||
public static void registerPackets(RegisterPayloadHandlerEvent event) {
|
||||
//noinspection removal
|
||||
@Nullable
|
||||
IPlayPayloadHandler<BufCustomPacketPayload> s2c = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientNetworkingManager::initClient);
|
||||
|
||||
IPayloadRegistrar registrar = event.registrar(ArchitecturyConstants.MOD_ID).optional();
|
||||
registrar.play(CHANNEL_ID, BufCustomPacketPayload::new, builder -> {
|
||||
builder.server(createPacketHandler(NetworkManager.Side.C2S, C2S_TRANSFORMERS)).client(Objects.requireNonNullElseGet(s2c, IPlayPayloadHandler::noop));
|
||||
});
|
||||
|
||||
registerC2SReceiver(SYNC_IDS, Collections.emptyList(), (buffer, context) -> {
|
||||
Set<ResourceLocation> receivables = (Set<ResourceLocation>) clientReceivables.get(context.getPlayer());
|
||||
int size = buffer.readInt();
|
||||
receivables.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
receivables.add(buffer.readResourceLocation());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static NetworkManager.Side side(PacketFlow flow) {
|
||||
return flow.isClientbound() ? NetworkManager.Side.S2C : flow.isServerbound() ? NetworkManager.Side.C2S : null;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import net.neoforged.fml.loading.FMLEnvironment;
|
||||
import net.neoforged.fml.loading.FMLLoader;
|
||||
import net.neoforged.fml.loading.FMLPaths;
|
||||
import net.neoforged.fml.loading.moddiscovery.ModFileInfo;
|
||||
import net.neoforged.neoforge.client.ConfigScreenHandler;
|
||||
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
||||
import net.neoforged.neoforgespi.language.IModFileInfo;
|
||||
import net.neoforged.neoforgespi.language.IModInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -178,8 +178,7 @@ public class PlatformImpl {
|
||||
|
||||
@Override
|
||||
public void registerConfigurationScreen(ConfigurationScreenProvider configurationScreenProvider) {
|
||||
container.registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () ->
|
||||
new ConfigScreenHandler.ConfigScreenFactory((minecraft, screen) -> configurationScreenProvider.provide(screen)));
|
||||
container.registerExtensionPoint(IConfigScreenFactory.class, (minecraft, screen) -> configurationScreenProvider.provide(screen));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.platform.hooks.forge;
|
||||
package dev.architectury.platform.hooks;
|
||||
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModContainer;
|
||||
@@ -26,7 +26,10 @@ import net.neoforged.fml.ModList;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class EventBusesHooksImpl {
|
||||
public final class EventBusesHooks {
|
||||
private EventBusesHooks() {
|
||||
}
|
||||
|
||||
public static void whenAvailable(String modId, Consumer<IEventBus> busConsumer) {
|
||||
IEventBus bus = getModEventBus(modId).orElseThrow(() -> new IllegalStateException("Mod '" + modId + "' is not available!"));
|
||||
busConsumer.accept(bus);
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.plugin.forge;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ArchitecturyMixinPlugin implements IMixinConfigPlugin {
|
||||
@Override
|
||||
public void onLoad(String mixinPackage) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
return List.of("neoforge.MixinChunkSerializer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.gui.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
|
||||
import net.minecraft.world.inventory.tooltip.TooltipComponent;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.bus.api.EventPriority;
|
||||
import net.neoforged.neoforge.client.event.RegisterClientTooltipComponentFactoriesEvent;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@ApiStatus.Internal
|
||||
public class ClientTooltipComponentRegistryImpl {
|
||||
@Nullable
|
||||
private static List<Entry<?>> entries = new ArrayList<>();
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterClientTooltipComponentFactoriesEvent>addListener(EventPriority.HIGH, event -> {
|
||||
if (entries != null) {
|
||||
for (Entry<?> entry : entries) {
|
||||
Entry<TooltipComponent> casted = (Entry<TooltipComponent>) entry;
|
||||
event.register(casted.clazz(), casted.factory());
|
||||
}
|
||||
|
||||
entries = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static <T extends TooltipComponent> void register(Class<T> clazz, Function<? super T, ? extends ClientTooltipComponent> factory) {
|
||||
if (entries == null) {
|
||||
throw new IllegalStateException("Cannot register ClientTooltipComponent factory when factories are already aggregated!");
|
||||
}
|
||||
entries.add(new Entry<>(clazz, factory));
|
||||
}
|
||||
|
||||
public record Entry<T extends TooltipComponent>(
|
||||
Class<T> clazz, Function<? super T, ? extends ClientTooltipComponent> factory
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.keymappings.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class KeyMappingRegistryImpl {
|
||||
private static final Logger LOGGER = LogManager.getLogger(KeyMappingRegistryImpl.class);
|
||||
private static final List<KeyMapping> MAPPINGS = new ArrayList<>();
|
||||
private static boolean eventCalled = false;
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.addListener(KeyMappingRegistryImpl::event);
|
||||
});
|
||||
}
|
||||
|
||||
public static void register(KeyMapping mapping) {
|
||||
if (eventCalled) {
|
||||
Options options = Minecraft.getInstance().options;
|
||||
options.keyMappings = ArrayUtils.add(options.keyMappings, mapping);
|
||||
LOGGER.warn("Key mapping %s registered after event".formatted(mapping.getName()), new RuntimeException());
|
||||
} else {
|
||||
MAPPINGS.add(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
public static void event(RegisterKeyMappingsEvent event) {
|
||||
MAPPINGS.forEach(event::register);
|
||||
eventCalled = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.level.entity.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EntityModelLayerRegistryImpl {
|
||||
private static final Map<ModelLayerLocation, Supplier<LayerDefinition>> DEFINITIONS = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(EntityModelLayerRegistryImpl.class);
|
||||
});
|
||||
}
|
||||
|
||||
public static void register(ModelLayerLocation location, Supplier<LayerDefinition> definition) {
|
||||
DEFINITIONS.put(location, definition);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void event(EntityRenderersEvent.RegisterLayerDefinitions event) {
|
||||
for (Map.Entry<ModelLayerLocation, Supplier<LayerDefinition>> entry : DEFINITIONS.entrySet()) {
|
||||
event.registerLayerDefinition(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.level.entity.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EntityRendererRegistryImpl {
|
||||
private static final Map<Supplier<EntityType<?>>, EntityRendererProvider<?>> RENDERERS = new ConcurrentHashMap<>();
|
||||
|
||||
public static <T extends Entity> void register(Supplier<? extends EntityType<? extends T>> type, EntityRendererProvider<T> factory) {
|
||||
RENDERERS.put((Supplier<EntityType<?>>) (Supplier<? extends EntityType<?>>) type, factory);
|
||||
}
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(EntityRendererRegistryImpl.class);
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void event(EntityRenderersEvent.RegisterRenderers event) {
|
||||
for (Map.Entry<Supplier<EntityType<?>>, EntityRendererProvider<?>> entry : RENDERERS.entrySet()) {
|
||||
event.registerEntityRenderer(entry.getKey().get(), (EntityRendererProvider<Entity>) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.particle.forge;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.registry.client.particle.ParticleProviderRegistry;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.ParticleEngine;
|
||||
import net.minecraft.client.particle.ParticleProvider;
|
||||
import net.minecraft.client.particle.SpriteSet;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleType;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.neoforged.neoforge.client.event.RegisterParticleProvidersEvent;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ParticleProviderRegistryImpl {
|
||||
public static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.addListener(ParticleProviderRegistryImpl::onParticleFactoryRegister);
|
||||
});
|
||||
}
|
||||
|
||||
private static final class ExtendedSpriteSetImpl implements ParticleProviderRegistry.ExtendedSpriteSet {
|
||||
private final ParticleEngine engine;
|
||||
private final SpriteSet delegate;
|
||||
|
||||
private ExtendedSpriteSetImpl(ParticleEngine engine, SpriteSet delegate) {
|
||||
this.engine = engine;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlas getAtlas() {
|
||||
return engine.textureAtlas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextureAtlasSprite> getSprites() {
|
||||
return ((ParticleEngine.MutableSpriteSet) delegate).sprites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite get(int i, int j) {
|
||||
return delegate.get(i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite get(RandomSource random) {
|
||||
return delegate.get(random);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Consumer<ParticleProviderRegistrar>> deferred = new ArrayList<>();
|
||||
|
||||
private static <T extends ParticleOptions> void doRegister(ParticleProviderRegistrar registrar, ParticleType<T> type, ParticleProvider<T> provider) {
|
||||
registrar.register(type, provider);
|
||||
}
|
||||
|
||||
private static <T extends ParticleOptions> void doRegister(ParticleProviderRegistrar registrar, ParticleType<T> type, ParticleProviderRegistry.DeferredParticleProvider<T> provider) {
|
||||
registrar.register(type, sprites ->
|
||||
provider.create(new ExtendedSpriteSetImpl(Minecraft.getInstance().particleEngine, sprites)));
|
||||
}
|
||||
|
||||
public static <T extends ParticleOptions> void register(ParticleType<T> type, ParticleProvider<T> provider) {
|
||||
if (deferred == null) {
|
||||
LOGGER.warn("Something is attempting to register particle providers at a later point than intended! This might cause issues!", new Throwable());
|
||||
doRegister(ParticleProviderRegistrar.ofFallback(), type, provider);
|
||||
} else {
|
||||
deferred.add(registrar -> doRegister(registrar, type, provider));
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends ParticleOptions> void register(ParticleType<T> type, ParticleProviderRegistry.DeferredParticleProvider<T> provider) {
|
||||
if (deferred == null) {
|
||||
LOGGER.warn("Something is attempting to register particle providers at a later point than intended! This might cause issues!", new Throwable());
|
||||
doRegister(ParticleProviderRegistrar.ofFallback(), type, provider);
|
||||
} else {
|
||||
deferred.add(registrar -> doRegister(registrar, type, provider));
|
||||
}
|
||||
}
|
||||
|
||||
public static void onParticleFactoryRegister(RegisterParticleProvidersEvent event) {
|
||||
if (deferred != null) {
|
||||
ParticleProviderRegistrar registrar = ParticleProviderRegistrar.ofForge(event);
|
||||
// run all deferred registrations
|
||||
for (Consumer<ParticleProviderRegistrar> consumer : deferred) {
|
||||
consumer.accept(registrar);
|
||||
}
|
||||
// yeet deferred list - register immediately from now on
|
||||
deferred = null;
|
||||
}
|
||||
}
|
||||
|
||||
private interface ParticleProviderRegistrar {
|
||||
<T extends ParticleOptions> void register(ParticleType<T> type, ParticleProvider<T> provider);
|
||||
|
||||
<T extends ParticleOptions> void register(ParticleType<T> type, ParticleEngine.SpriteParticleRegistration<T> registration);
|
||||
|
||||
static ParticleProviderRegistrar ofForge(RegisterParticleProvidersEvent event) {
|
||||
return new ParticleProviderRegistrar() {
|
||||
@Override
|
||||
public <T extends ParticleOptions> void register(ParticleType<T> type, ParticleProvider<T> provider) {
|
||||
event.registerSpecial(type, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleOptions> void register(ParticleType<T> type, ParticleEngine.SpriteParticleRegistration<T> registration) {
|
||||
event.registerSpriteSet(type, registration);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ParticleProviderRegistrar ofFallback() {
|
||||
return new ParticleProviderRegistrar() {
|
||||
@Override
|
||||
public <T extends ParticleOptions> void register(ParticleType<T> type, ParticleProvider<T> provider) {
|
||||
Minecraft.getInstance().particleEngine.register(type, provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ParticleOptions> void register(ParticleType<T> type, ParticleEngine.SpriteParticleRegistration<T> registration) {
|
||||
Minecraft.getInstance().particleEngine.register(type, registration);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.rendering.forge;
|
||||
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
||||
public class BlockEntityRendererRegistryImpl {
|
||||
public static <T extends BlockEntity> void register(BlockEntityType<T> type, BlockEntityRendererProvider<? super T> provider) {
|
||||
BlockEntityRenderers.register(type, provider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.rendering.forge;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.block.BlockColor;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ColorHandlerRegistryImpl {
|
||||
private static final List<Pair<ItemColor, Supplier<? extends ItemLike>[]>> ITEM_COLORS = Lists.newArrayList();
|
||||
private static final List<Pair<BlockColor, Supplier<? extends Block>[]>> BLOCK_COLORS = Lists.newArrayList();
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(ColorHandlerRegistryImpl.class);
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onItemColorEvent(RegisterColorHandlersEvent.Item event) {
|
||||
for (Pair<ItemColor, Supplier<? extends ItemLike>[]> pair : ITEM_COLORS) {
|
||||
event.register(pair.getLeft(), unpackItems(pair.getRight()));
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onBlockColorEvent(RegisterColorHandlersEvent.Block event) {
|
||||
for (Pair<BlockColor, Supplier<? extends Block>[]> pair : BLOCK_COLORS) {
|
||||
event.register(pair.getLeft(), unpackBlocks(pair.getRight()));
|
||||
}
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static void registerItemColors(ItemColor itemColor, Supplier<? extends ItemLike>... items) {
|
||||
Objects.requireNonNull(itemColor, "color is null!");
|
||||
if (Minecraft.getInstance().getItemColors() == null) {
|
||||
ITEM_COLORS.add(Pair.of(itemColor, items));
|
||||
} else {
|
||||
Minecraft.getInstance().getItemColors().register(itemColor, unpackItems(items));
|
||||
}
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static void registerBlockColors(BlockColor blockColor, Supplier<? extends Block>... blocks) {
|
||||
Objects.requireNonNull(blockColor, "color is null!");
|
||||
if (Minecraft.getInstance().getBlockColors() == null) {
|
||||
BLOCK_COLORS.add(Pair.of(blockColor, blocks));
|
||||
} else {
|
||||
Minecraft.getInstance().getBlockColors().register(blockColor, unpackBlocks(blocks));
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemLike[] unpackItems(Supplier<? extends ItemLike>[] items) {
|
||||
ItemLike[] array = new ItemLike[items.length];
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
array[i] = Objects.requireNonNull(items[i].get());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private static Block[] unpackBlocks(Supplier<? extends Block>[] blocks) {
|
||||
Block[] array = new Block[blocks.length];
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
array[i] = Objects.requireNonNull(blocks[i].get());
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.client.rendering.forge;
|
||||
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
public class RenderTypeRegistryImpl {
|
||||
public static void register(RenderType type, Block... blocks) {
|
||||
for (Block block : blocks) {
|
||||
ItemBlockRenderTypes.setRenderLayer(block, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(RenderType type, Fluid... fluids) {
|
||||
for (Fluid fluid : fluids) {
|
||||
ItemBlockRenderTypes.setRenderLayer(fluid, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.forge;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.registry.CreativeTabOutput;
|
||||
import dev.architectury.registry.CreativeTabRegistry;
|
||||
import dev.architectury.registry.registries.DeferredSupplier;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.common.CreativeModeTabRegistry;
|
||||
import net.neoforged.neoforge.common.util.MutableHashedLinkedMap;
|
||||
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CreativeTabRegistryImpl {
|
||||
private static final Logger LOGGER = LogManager.getLogger(CreativeTabRegistryImpl.class);
|
||||
|
||||
private static final List<Consumer<BuildCreativeModeTabContentsEvent>> BUILD_CONTENTS_LISTENERS = new ArrayList<>();
|
||||
private static final Multimap<TabKey, Supplier<ItemStack>> APPENDS = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.addListener(CreativeTabRegistryImpl::event);
|
||||
});
|
||||
|
||||
BUILD_CONTENTS_LISTENERS.add(event -> {
|
||||
for (Map.Entry<TabKey, Collection<Supplier<ItemStack>>> keyEntry : APPENDS.asMap().entrySet()) {
|
||||
Supplier<List<ItemStack>> stacks = Suppliers.memoize(() -> keyEntry.getValue().stream()
|
||||
.map(Supplier::get)
|
||||
.toList());
|
||||
if (keyEntry.getKey() instanceof TabKey.SupplierTabKey supplierTabKey) {
|
||||
if (Objects.equals(CreativeModeTabRegistry.getName(event.getTab()), supplierTabKey.supplier().getId())) {
|
||||
for (ItemStack stack : stacks.get()) {
|
||||
event.getEntries().put(stack, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS);
|
||||
}
|
||||
}
|
||||
} else if (keyEntry.getKey() instanceof TabKey.DirectTabKey directTabKey) {
|
||||
if (event.getTab().equals(directTabKey.tab())) {
|
||||
for (ItemStack stack : stacks.get()) {
|
||||
event.getEntries().put(stack, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void event(BuildCreativeModeTabContentsEvent event) {
|
||||
for (Consumer<BuildCreativeModeTabContentsEvent> listener : BUILD_CONTENTS_LISTENERS) {
|
||||
listener.accept(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static CreativeModeTab create(Consumer<CreativeModeTab.Builder> callback) {
|
||||
CreativeModeTab.Builder builder = CreativeModeTab.builder();
|
||||
callback.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static DeferredSupplier<CreativeModeTab> ofBuiltin(CreativeModeTab tab) {
|
||||
ResourceLocation key = BuiltInRegistries.CREATIVE_MODE_TAB.getKey(tab);
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("Builtin tab %s is not registered!".formatted(tab));
|
||||
}
|
||||
return new DeferredSupplier<>() {
|
||||
@Override
|
||||
public ResourceLocation getRegistryId() {
|
||||
return Registries.CREATIVE_MODE_TAB.location();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return BuiltInRegistries.CREATIVE_MODE_TAB.getKey(tab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPresent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreativeModeTab get() {
|
||||
return tab;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static DeferredSupplier<CreativeModeTab> defer(ResourceLocation name) {
|
||||
return new DeferredSupplier<>() {
|
||||
@Nullable
|
||||
private CreativeModeTab tab;
|
||||
|
||||
@Override
|
||||
public ResourceLocation getRegistryId() {
|
||||
return Registries.CREATIVE_MODE_TAB.location();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreativeModeTab get() {
|
||||
resolve();
|
||||
if (tab == null)
|
||||
throw new IllegalStateException("Creative tab %s was not registered yet!".formatted(name));
|
||||
return tab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPresent() {
|
||||
resolve();
|
||||
return tab != null;
|
||||
}
|
||||
|
||||
private void resolve() {
|
||||
if (this.tab == null) {
|
||||
this.tab = BuiltInRegistries.CREATIVE_MODE_TAB.get(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void modify(DeferredSupplier<CreativeModeTab> tab, CreativeTabRegistry.ModifyTabCallback filler) {
|
||||
BUILD_CONTENTS_LISTENERS.add(event -> {
|
||||
if (tab.isPresent()) {
|
||||
if (event.getTab().equals(tab.get())) {
|
||||
filler.accept(event.getFlags(), wrapTabOutput(event.getEntries()), event.hasPermissions());
|
||||
}
|
||||
} else if (Objects.equals(CreativeModeTabRegistry.getName(event.getTab()), tab.getId())) {
|
||||
filler.accept(event.getFlags(), wrapTabOutput(event.getEntries()), event.hasPermissions());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static CreativeTabOutput wrapTabOutput(MutableHashedLinkedMap<ItemStack, CreativeModeTab.TabVisibility> entries) {
|
||||
return new CreativeTabOutput() {
|
||||
@Override
|
||||
public void acceptAfter(ItemStack after, ItemStack stack, CreativeModeTab.TabVisibility visibility) {
|
||||
if (after.isEmpty()) {
|
||||
entries.put(stack, visibility);
|
||||
} else {
|
||||
entries.putAfter(after, stack, visibility);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptBefore(ItemStack before, ItemStack stack, CreativeModeTab.TabVisibility visibility) {
|
||||
if (before.isEmpty()) {
|
||||
entries.put(stack, visibility);
|
||||
} else {
|
||||
entries.putBefore(before, stack, visibility);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public static void appendStack(DeferredSupplier<CreativeModeTab> tab, Supplier<ItemStack> item) {
|
||||
APPENDS.put(new TabKey.SupplierTabKey(tab), item);
|
||||
}
|
||||
|
||||
private interface TabKey {
|
||||
record SupplierTabKey(DeferredSupplier<CreativeModeTab> supplier) implements TabKey {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SupplierTabKey that)) return false;
|
||||
return Objects.equals(supplier.getId(), that.supplier.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(supplier.getId());
|
||||
}
|
||||
}
|
||||
|
||||
record DirectTabKey(CreativeModeTab tab) implements TabKey {
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DirectTabKey that)) return false;
|
||||
return tab == that.tab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.forge;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.AddReloadListenerEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class ReloadListenerRegistryImpl {
|
||||
private static List<PreparableReloadListener> serverDataReloadListeners = Lists.newArrayList();
|
||||
|
||||
static {
|
||||
NeoForge.EVENT_BUS.addListener(ReloadListenerRegistryImpl::addReloadListeners);
|
||||
}
|
||||
|
||||
public static void register(PackType type, PreparableReloadListener listener, @Nullable ResourceLocation listenerId, Collection<ResourceLocation> dependencies) {
|
||||
if (type == PackType.SERVER_DATA) {
|
||||
serverDataReloadListeners.add(listener);
|
||||
} else if (type == PackType.CLIENT_RESOURCES) {
|
||||
registerClient(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
private static void registerClient(PreparableReloadListener listener) {
|
||||
((ReloadableResourceManager) Minecraft.getInstance().getResourceManager()).registerReloadListener(listener);
|
||||
}
|
||||
|
||||
public static void addReloadListeners(AddReloadListenerEvent event) {
|
||||
for (PreparableReloadListener listener : serverDataReloadListeners) {
|
||||
event.addListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.fuel.forge;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.furnace.FurnaceFuelBurnTimeEvent;
|
||||
|
||||
public class FuelRegistryImpl {
|
||||
private static final Object2IntMap<ItemLike> ITEMS = new Object2IntLinkedOpenHashMap<>();
|
||||
|
||||
static {
|
||||
NeoForge.EVENT_BUS.register(FuelRegistryImpl.class);
|
||||
}
|
||||
|
||||
public static void register(int time, ItemLike... items) {
|
||||
for (ItemLike item : items) {
|
||||
ITEMS.put(item, time);
|
||||
}
|
||||
}
|
||||
|
||||
public static int get(ItemStack stack) {
|
||||
return stack.getBurnTime(null);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void event(FurnaceFuelBurnTimeEvent event) {
|
||||
if (event.getItemStack().isEmpty()) return;
|
||||
int time = ITEMS.getOrDefault(event.getItemStack().getItem(), Integer.MIN_VALUE);
|
||||
if (time != Integer.MIN_VALUE) {
|
||||
event.setBurnTime(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.item.forge;
|
||||
|
||||
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
|
||||
public class ItemPropertiesRegistryImpl {
|
||||
public static ClampedItemPropertyFunction registerGeneric(ResourceLocation propertyId, ClampedItemPropertyFunction function) {
|
||||
ItemProperties.registerGeneric(propertyId, function);
|
||||
return function;
|
||||
}
|
||||
|
||||
public static ClampedItemPropertyFunction register(ItemLike item, ResourceLocation propertyId, ClampedItemPropertyFunction function) {
|
||||
ItemProperties.register(item.asItem(), propertyId, function);
|
||||
return function;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.level.biome.forge;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dev.architectury.hooks.level.biome.*;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.registry.level.biome.BiomeModifications.BiomeContext;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import dev.architectury.utils.GameInstance;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.sounds.Music;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.MobCategory;
|
||||
import net.minecraft.world.level.biome.*;
|
||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
||||
import net.minecraft.world.level.levelgen.carver.ConfiguredWorldCarver;
|
||||
import net.minecraft.world.level.levelgen.placement.PlacedFeature;
|
||||
import net.neoforged.neoforge.common.world.*;
|
||||
import net.neoforged.neoforge.registries.NeoForgeRegistries;
|
||||
import net.neoforged.neoforge.registries.RegisterEvent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BiomeModificationsImpl {
|
||||
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> ADDITIONS = Lists.newArrayList();
|
||||
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> POST_PROCESSING = Lists.newArrayList();
|
||||
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REMOVALS = Lists.newArrayList();
|
||||
private static final List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> REPLACEMENTS = Lists.newArrayList();
|
||||
@Nullable
|
||||
private static MapCodec<BiomeModifierImpl> noneBiomeModCodec = null;
|
||||
|
||||
public static void init() {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<RegisterEvent>addListener(event -> {
|
||||
event.register(NeoForgeRegistries.Keys.BIOME_MODIFIER_SERIALIZERS, registry -> {
|
||||
registry.register(new ResourceLocation(ArchitecturyConstants.MOD_ID, "none_biome_mod_codec"),
|
||||
noneBiomeModCodec = MapCodec.unit(BiomeModifierImpl.INSTANCE));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static void addProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
|
||||
ADDITIONS.add(Pair.of(predicate, modifier));
|
||||
}
|
||||
|
||||
public static void postProcessProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
|
||||
POST_PROCESSING.add(Pair.of(predicate, modifier));
|
||||
}
|
||||
|
||||
public static void removeProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
|
||||
REMOVALS.add(Pair.of(predicate, modifier));
|
||||
}
|
||||
|
||||
public static void replaceProperties(Predicate<BiomeContext> predicate, BiConsumer<BiomeContext, BiomeProperties.Mutable> modifier) {
|
||||
REPLACEMENTS.add(Pair.of(predicate, modifier));
|
||||
}
|
||||
|
||||
private static class BiomeModifierImpl implements BiomeModifier {
|
||||
// cry about it
|
||||
private static final BiomeModifierImpl INSTANCE = new BiomeModifierImpl();
|
||||
|
||||
@Override
|
||||
public void modify(Holder<Biome> arg, Phase phase, ModifiableBiomeInfo.BiomeInfo.Builder builder) {
|
||||
List<Pair<Predicate<BiomeContext>, BiConsumer<BiomeContext, BiomeProperties.Mutable>>> list = switch (phase) {
|
||||
case ADD -> ADDITIONS;
|
||||
case REMOVE -> REMOVALS;
|
||||
case MODIFY -> REPLACEMENTS;
|
||||
case AFTER_EVERYTHING -> POST_PROCESSING;
|
||||
default -> null;
|
||||
};
|
||||
|
||||
if (list == null) return;
|
||||
BiomeContext biomeContext = wrapSelectionContext(arg.unwrapKey(), builder);
|
||||
BiomeProperties.Mutable mutableBiome = new MutableBiomeWrapped(builder);
|
||||
for (var pair : list) {
|
||||
if (pair.getLeft().test(biomeContext)) {
|
||||
pair.getRight().accept(biomeContext, mutableBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends BiomeModifier> codec() {
|
||||
if (noneBiomeModCodec != null) {
|
||||
return noneBiomeModCodec;
|
||||
} else {
|
||||
return MapCodec.unit(INSTANCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BiomeContext wrapSelectionContext(Optional<ResourceKey<Biome>> biomeResourceKey, ModifiableBiomeInfo.BiomeInfo.Builder event) {
|
||||
return new BiomeContext() {
|
||||
BiomeProperties properties = new BiomeWrapped(event);
|
||||
|
||||
@Override
|
||||
public Optional<ResourceLocation> getKey() {
|
||||
return biomeResourceKey.map(ResourceKey::location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProperties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTag(TagKey<Biome> tag) {
|
||||
MinecraftServer server = GameInstance.getServer();
|
||||
if (server != null) {
|
||||
Optional<? extends Registry<Biome>> registry = server.registryAccess().registry(Registries.BIOME);
|
||||
if (registry.isPresent()) {
|
||||
Optional<Holder.Reference<Biome>> holder = registry.get().getHolder(biomeResourceKey.get());
|
||||
if (holder.isPresent()) {
|
||||
return holder.get().is(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class BiomeWrapped implements BiomeProperties {
|
||||
protected final ModifiableBiomeInfo.BiomeInfo.Builder event;
|
||||
protected final ClimateProperties climateProperties;
|
||||
protected final EffectsProperties effectsProperties;
|
||||
protected final GenerationProperties generationProperties;
|
||||
protected final SpawnProperties spawnProperties;
|
||||
|
||||
public BiomeWrapped(ModifiableBiomeInfo.BiomeInfo.Builder event) {
|
||||
this(event,
|
||||
new MutableClimatePropertiesWrapped(event.getClimateSettings()),
|
||||
new MutableEffectsPropertiesWrapped(event.getSpecialEffects()),
|
||||
new GenerationSettingsBuilderWrapped(event.getGenerationSettings()),
|
||||
new SpawnSettingsBuilderWrapped(event.getMobSpawnSettings())
|
||||
);
|
||||
}
|
||||
|
||||
public BiomeWrapped(ModifiableBiomeInfo.BiomeInfo.Builder event, ClimateProperties climateProperties, EffectsProperties effectsProperties, GenerationProperties generationProperties, SpawnProperties spawnProperties) {
|
||||
this.event = event;
|
||||
this.climateProperties = climateProperties;
|
||||
this.effectsProperties = effectsProperties;
|
||||
this.generationProperties = generationProperties;
|
||||
this.spawnProperties = spawnProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClimateProperties getClimateProperties() {
|
||||
return climateProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EffectsProperties getEffectsProperties() {
|
||||
return effectsProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenerationProperties getGenerationProperties() {
|
||||
return generationProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpawnProperties getSpawnProperties() {
|
||||
return spawnProperties;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GenerationSettingsBuilderWrapped implements GenerationProperties {
|
||||
protected final BiomeGenerationSettingsBuilder generation;
|
||||
|
||||
public GenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {
|
||||
this.generation = generation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Holder<ConfiguredWorldCarver<?>>> getCarvers(GenerationStep.Carving carving) {
|
||||
return generation.getCarvers(carving);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Holder<PlacedFeature>> getFeatures(GenerationStep.Decoration decoration) {
|
||||
return generation.getFeatures(decoration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Iterable<Holder<PlacedFeature>>> getFeatures() {
|
||||
return (List<Iterable<Holder<PlacedFeature>>>) (List<?>) generation.features;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpawnSettingsBuilderWrapped implements SpawnProperties {
|
||||
protected final MobSpawnSettingsBuilder builder;
|
||||
|
||||
public SpawnSettingsBuilderWrapped(MobSpawnSettingsBuilder builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCreatureProbability() {
|
||||
return builder.getProbability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<MobCategory, List<MobSpawnSettings.SpawnerData>> getSpawners() {
|
||||
return builder.spawners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> getMobSpawnCosts() {
|
||||
return builder.mobSpawnCosts;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MutableBiomeWrapped extends BiomeWrapped implements BiomeProperties.Mutable {
|
||||
public MutableBiomeWrapped(ModifiableBiomeInfo.BiomeInfo.Builder event) {
|
||||
super(event,
|
||||
new MutableClimatePropertiesWrapped(event.getClimateSettings()),
|
||||
new MutableEffectsPropertiesWrapped(event.getSpecialEffects()),
|
||||
new MutableGenerationSettingsBuilderWrapped(event.getGenerationSettings()),
|
||||
new MutableSpawnSettingsBuilderWrapped(event.getMobSpawnSettings())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClimateProperties.Mutable getClimateProperties() {
|
||||
return (ClimateProperties.Mutable) super.getClimateProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EffectsProperties.Mutable getEffectsProperties() {
|
||||
return (EffectsProperties.Mutable) super.getEffectsProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenerationProperties.Mutable getGenerationProperties() {
|
||||
return (GenerationProperties.Mutable) super.getGenerationProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpawnProperties.Mutable getSpawnProperties() {
|
||||
return (SpawnProperties.Mutable) super.getSpawnProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MutableClimatePropertiesWrapped implements ClimateProperties.Mutable {
|
||||
public ClimateSettingsBuilder builder;
|
||||
|
||||
public MutableClimatePropertiesWrapped(ClimateSettingsBuilder builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrecipitation() {
|
||||
return builder.hasPrecipitation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTemperature() {
|
||||
return builder.getTemperature();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome.TemperatureModifier getTemperatureModifier() {
|
||||
return builder.getTemperatureModifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDownfall() {
|
||||
return builder.getDownfall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setHasPrecipitation(boolean hasPrecipitation) {
|
||||
this.builder.setHasPrecipitation(hasPrecipitation);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setTemperature(float temperature) {
|
||||
this.builder.setTemperature(temperature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setTemperatureModifier(Biome.TemperatureModifier temperatureModifier) {
|
||||
this.builder.setTemperatureModifier(temperatureModifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setDownfall(float downfall) {
|
||||
this.builder.setDownfall(downfall);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MutableEffectsPropertiesWrapped implements EffectsProperties.Mutable {
|
||||
public BiomeSpecialEffects.Builder builder;
|
||||
|
||||
public MutableEffectsPropertiesWrapped(BiomeSpecialEffects.Builder builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFogColor() {
|
||||
if (builder instanceof BiomeSpecialEffectsBuilder b) return b.getFogColor();
|
||||
return builder.fogColor.orElse(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWaterColor() {
|
||||
if (builder instanceof BiomeSpecialEffectsBuilder b) return b.getWaterFogColor();
|
||||
return builder.waterColor.orElse(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWaterFogColor() {
|
||||
if (builder instanceof BiomeSpecialEffectsBuilder b) return b.getWaterFogColor();
|
||||
return builder.waterFogColor.orElse(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyColor() {
|
||||
if (builder instanceof BiomeSpecialEffectsBuilder b) return b.getSkyColor();
|
||||
return builder.skyColor.orElse(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getFoliageColorOverride() {
|
||||
return builder.foliageColorOverride.map(OptionalInt::of).orElseGet(OptionalInt::empty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getGrassColorOverride() {
|
||||
return builder.grassColorOverride.map(OptionalInt::of).orElseGet(OptionalInt::empty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeSpecialEffects.GrassColorModifier getGrassColorModifier() {
|
||||
return builder.grassColorModifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AmbientParticleSettings> getAmbientParticle() {
|
||||
return builder.ambientParticle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Holder<SoundEvent>> getAmbientLoopSound() {
|
||||
return builder.ambientLoopSoundEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AmbientMoodSettings> getAmbientMoodSound() {
|
||||
return builder.ambientMoodSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AmbientAdditionsSettings> getAmbientAdditionsSound() {
|
||||
return builder.ambientAdditionsSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Music> getBackgroundMusic() {
|
||||
return builder.backgroundMusic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setFogColor(int color) {
|
||||
builder.fogColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setWaterColor(int color) {
|
||||
builder.waterColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setWaterFogColor(int color) {
|
||||
builder.waterFogColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setSkyColor(int color) {
|
||||
builder.skyColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setFoliageColorOverride(@Nullable Integer colorOverride) {
|
||||
builder.foliageColorOverride = Optional.ofNullable(colorOverride);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setGrassColorOverride(@Nullable Integer colorOverride) {
|
||||
builder.foliageColorOverride = Optional.ofNullable(colorOverride);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setGrassColorModifier(BiomeSpecialEffects.GrassColorModifier modifier) {
|
||||
builder.grassColorModifier(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setAmbientParticle(@Nullable AmbientParticleSettings settings) {
|
||||
builder.ambientParticle = Optional.ofNullable(settings);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setAmbientLoopSound(@Nullable Holder<SoundEvent> sound) {
|
||||
builder.ambientLoopSoundEvent = Optional.ofNullable(sound);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setAmbientMoodSound(@Nullable AmbientMoodSettings settings) {
|
||||
builder.ambientMoodSettings = Optional.ofNullable(settings);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setAmbientAdditionsSound(@Nullable AmbientAdditionsSettings settings) {
|
||||
builder.ambientAdditionsSettings = Optional.ofNullable(settings);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setBackgroundMusic(@Nullable Music music) {
|
||||
builder.backgroundMusic = Optional.ofNullable(music);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MutableGenerationSettingsBuilderWrapped extends GenerationSettingsBuilderWrapped implements GenerationProperties.Mutable {
|
||||
public MutableGenerationSettingsBuilderWrapped(BiomeGenerationSettingsBuilder generation) {
|
||||
super(generation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addFeature(GenerationStep.Decoration decoration, Holder<PlacedFeature> feature) {
|
||||
generation.addFeature(decoration, feature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addFeature(GenerationStep.Decoration decoration, ResourceKey<PlacedFeature> feature) {
|
||||
MinecraftServer server = GameInstance.getServer();
|
||||
if (server != null) {
|
||||
Optional<? extends Registry<PlacedFeature>> registry = server.registryAccess().registry(Registries.PLACED_FEATURE);
|
||||
if (registry.isPresent()) {
|
||||
Optional<Holder.Reference<PlacedFeature>> holder = registry.get().getHolder(feature);
|
||||
if (holder.isPresent()) {
|
||||
return addFeature(decoration, holder.get());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown feature: " + feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addCarver(GenerationStep.Carving carving, Holder<ConfiguredWorldCarver<?>> feature) {
|
||||
generation.addCarver(carving, feature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addCarver(GenerationStep.Carving carving, ResourceKey<ConfiguredWorldCarver<?>> feature) {
|
||||
MinecraftServer server = GameInstance.getServer();
|
||||
if (server != null) {
|
||||
Optional<? extends Registry<ConfiguredWorldCarver<?>>> registry = server.registryAccess().registry(Registries.CONFIGURED_CARVER);
|
||||
if (registry.isPresent()) {
|
||||
Optional<Holder.Reference<ConfiguredWorldCarver<?>>> holder = registry.get().getHolder(feature);
|
||||
if (holder.isPresent()) {
|
||||
return addCarver(carving, holder.get());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown carver: " + feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable removeFeature(GenerationStep.Decoration decoration, ResourceKey<PlacedFeature> feature) {
|
||||
generation.getFeatures(decoration).removeIf(supplier -> supplier.is(feature));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable removeCarver(GenerationStep.Carving carving, ResourceKey<ConfiguredWorldCarver<?>> feature) {
|
||||
generation.getCarvers(carving).removeIf(supplier -> supplier.is(feature));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MutableSpawnSettingsBuilderWrapped extends SpawnSettingsBuilderWrapped implements SpawnProperties.Mutable {
|
||||
public MutableSpawnSettingsBuilderWrapped(MobSpawnSettingsBuilder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setCreatureProbability(float probability) {
|
||||
builder.creatureGenerationProbability(probability);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addSpawn(MobCategory category, MobSpawnSettings.SpawnerData data) {
|
||||
builder.addSpawn(category, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSpawns(BiPredicate<MobCategory, MobSpawnSettings.SpawnerData> predicate) {
|
||||
boolean removed = false;
|
||||
for (MobCategory type : builder.getSpawnerTypes()) {
|
||||
if (builder.getSpawner(type).removeIf(data -> predicate.test(type, data))) {
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setSpawnCost(EntityType<?> entityType, MobSpawnSettings.MobSpawnCost cost) {
|
||||
builder.addMobCharge(entityType, cost.charge(), cost.energyBudget());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable setSpawnCost(EntityType<?> entityType, double charge, double energyBudget) {
|
||||
builder.addMobCharge(entityType, charge, energyBudget);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable clearSpawnCost(EntityType<?> entityType) {
|
||||
getMobSpawnCosts().remove(entityType);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.level.entity.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.neoforge.event.entity.EntityAttributeCreationEvent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class EntityAttributeRegistryImpl {
|
||||
private static final Map<Supplier<? extends EntityType<? extends LivingEntity>>, Supplier<AttributeSupplier.Builder>> ATTRIBUTES = new ConcurrentHashMap<>();
|
||||
|
||||
public static void register(Supplier<? extends EntityType<? extends LivingEntity>> type, Supplier<AttributeSupplier.Builder> attribute) {
|
||||
ATTRIBUTES.put(type, attribute);
|
||||
}
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.register(EntityAttributeRegistryImpl.class);
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void event(EntityAttributeCreationEvent event) {
|
||||
for (Map.Entry<Supplier<? extends EntityType<? extends LivingEntity>>, Supplier<AttributeSupplier.Builder>> entry : ATTRIBUTES.entrySet()) {
|
||||
event.put(entry.getKey().get(), entry.getValue().get().build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.level.entity.forge;
|
||||
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.utils.ArchitecturyConstants;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.SpawnPlacementType;
|
||||
import net.minecraft.world.entity.SpawnPlacements;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.neoforged.neoforge.event.entity.SpawnPlacementRegisterEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SpawnPlacementsRegistryImpl {
|
||||
private static List<Entry<?>> entries = new ArrayList<>();
|
||||
|
||||
private record Entry<T extends Mob>(Supplier<? extends EntityType<T>> type, SpawnPlacementType spawnPlacement,
|
||||
Heightmap.Types heightmapType,
|
||||
SpawnPlacements.SpawnPredicate<T> spawnPredicate) {
|
||||
}
|
||||
|
||||
static {
|
||||
EventBusesHooks.whenAvailable(ArchitecturyConstants.MOD_ID, bus -> {
|
||||
bus.<SpawnPlacementRegisterEvent>addListener(event -> {
|
||||
for (Entry<?> entry : entries) {
|
||||
Entry<Mob> casted = (Entry<Mob>) entry;
|
||||
event.register(casted.type().get(), casted.spawnPlacement(), casted.heightmapType(), casted.spawnPredicate(), SpawnPlacementRegisterEvent.Operation.OR);
|
||||
}
|
||||
entries = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static <T extends Mob> void register(Supplier<? extends EntityType<T>> type, SpawnPlacementType spawnPlacement, Heightmap.Types heightmapType, SpawnPlacements.SpawnPredicate<T> spawnPredicate) {
|
||||
if (entries != null) {
|
||||
entries.add(new Entry<>(type, spawnPlacement, heightmapType, spawnPredicate));
|
||||
} else {
|
||||
throw new IllegalStateException("SpawnPlacementsRegistry.register must not be called after the registry has been collected!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.registry.level.entity.trade.forge;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
||||
import net.minecraft.world.entity.npc.VillagerTrades;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.event.village.VillagerTradesEvent;
|
||||
import net.neoforged.neoforge.event.village.WandererTradesEvent;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class TradeRegistryImpl {
|
||||
private static final Map<VillagerProfession, Int2ObjectMap<List<VillagerTrades.ItemListing>>> TRADES_TO_ADD = new HashMap<>();
|
||||
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_GENERIC = new ArrayList<>();
|
||||
private static final List<VillagerTrades.ItemListing> WANDERER_TRADER_TRADES_RARE = new ArrayList<>();
|
||||
|
||||
static {
|
||||
NeoForge.EVENT_BUS.addListener(TradeRegistryImpl::onTradeRegistering);
|
||||
NeoForge.EVENT_BUS.addListener(TradeRegistryImpl::onWanderingTradeRegistering);
|
||||
}
|
||||
|
||||
public static void registerVillagerTrade0(VillagerProfession profession, int level, VillagerTrades.ItemListing... trades) {
|
||||
Int2ObjectMap<List<VillagerTrades.ItemListing>> tradesForProfession = TRADES_TO_ADD.computeIfAbsent(profession, $ -> new Int2ObjectOpenHashMap<>());
|
||||
List<VillagerTrades.ItemListing> tradesForLevel = tradesForProfession.computeIfAbsent(level, $ -> new ArrayList<>());
|
||||
Collections.addAll(tradesForLevel, trades);
|
||||
}
|
||||
|
||||
public static void registerTradeForWanderingTrader(boolean rare, VillagerTrades.ItemListing... trades) {
|
||||
if (rare) {
|
||||
Collections.addAll(WANDERER_TRADER_TRADES_RARE, trades);
|
||||
} else {
|
||||
Collections.addAll(WANDERER_TRADER_TRADES_GENERIC, trades);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onTradeRegistering(VillagerTradesEvent event) {
|
||||
Int2ObjectMap<List<VillagerTrades.ItemListing>> trades = TRADES_TO_ADD.get(event.getType());
|
||||
|
||||
if (trades != null) {
|
||||
for (Int2ObjectMap.Entry<List<VillagerTrades.ItemListing>> entry : trades.int2ObjectEntrySet()) {
|
||||
event.getTrades().computeIfAbsent(entry.getIntKey(), $ -> NonNullList.create()).addAll(entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onWanderingTradeRegistering(WandererTradesEvent event) {
|
||||
if (!WANDERER_TRADER_TRADES_GENERIC.isEmpty()) {
|
||||
event.getGenericTrades().addAll(WANDERER_TRADER_TRADES_GENERIC);
|
||||
}
|
||||
if (!WANDERER_TRADER_TRADES_RARE.isEmpty()) {
|
||||
event.getRareTrades().addAll(WANDERER_TRADER_TRADES_RARE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import dev.architectury.impl.RegistrySupplierImpl;
|
||||
import dev.architectury.platform.hooks.forge.EventBusesHooksImpl;
|
||||
import dev.architectury.platform.hooks.EventBusesHooks;
|
||||
import dev.architectury.registry.registries.Registrar;
|
||||
import dev.architectury.registry.registries.RegistrarBuilder;
|
||||
import dev.architectury.registry.registries.RegistrarManager;
|
||||
@@ -109,7 +109,7 @@ public class RegistrarManagerImpl {
|
||||
|
||||
public RegistryProviderImpl(String modId) {
|
||||
this.modId = modId;
|
||||
EventBusesHooksImpl.getModEventBus(modId).get().register(new EventListener());
|
||||
EventBusesHooks.getModEventBus(modId).get().register(new EventListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of architectury.
|
||||
* Copyright (C) 2020, 2021, 2022 architectury
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package dev.architectury.utils.forge;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
|
||||
public class GameInstanceImpl {
|
||||
public static MinecraftServer getServer() {
|
||||
return ServerLifecycleHooks.getCurrentServer();
|
||||
}
|
||||
}
|
||||
21
neoforge/src/main/resources/architectury.mixins.json
Normal file
21
neoforge/src/main/resources/architectury.mixins.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "dev.architectury.mixin.forge",
|
||||
"plugin": "dev.architectury.plugin.forge.ArchitecturyMixinPlugin",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"minVersion": "0.8",
|
||||
"client": [
|
||||
"client.MixinCommandSourceStack",
|
||||
"MixinClientLevel",
|
||||
"MixinMinecraft"
|
||||
],
|
||||
"mixins": [
|
||||
"neoforge.MixinChunkSerializer",
|
||||
"MixinFallingBlockEntity",
|
||||
"MixinItemExtension",
|
||||
"MixinLevelEvent"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,10 @@ include("common")
|
||||
include("fabric")
|
||||
//include("forge")
|
||||
//include("minecraftforge")
|
||||
//include("neoforge")
|
||||
include("neoforge")
|
||||
include("testmod-common")
|
||||
include("testmod-fabric")
|
||||
//include("testmod-forge")
|
||||
//include("testmod-neoforge")
|
||||
include("testmod-neoforge")
|
||||
|
||||
rootProject.name = "architectury"
|
||||
|
||||
@@ -25,6 +25,7 @@ import dev.architectury.networking.NetworkManager;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -56,7 +57,7 @@ public class TestEntity extends Cow {
|
||||
if (this.getLastAttacker() instanceof ServerPlayer player) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.putString("DeathCauser", player.getStringUUID());
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), this.registryAccess());
|
||||
buf.writeNbt(compoundTag);
|
||||
NetworkManager.sendToPlayer(player, new ResourceLocation("architectury_test", "sync_data"), buf);
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ import net.minecraft.world.level.storage.loot.entries.LootItem;
|
||||
|
||||
public class TestLoot {
|
||||
public static void init() {
|
||||
/*LootEvent.MODIFY_LOOT_TABLE.register((lootTables, id, context, builtin) -> {
|
||||
LootEvent.MODIFY_LOOT_TABLE.register((key, context, builtin) -> {
|
||||
// Check that the loot table is dirt and built-in
|
||||
if (builtin && Blocks.DIRT.getLootTable().equals(id)) {
|
||||
if (builtin && Blocks.DIRT.getLootTable().equals(key)) {
|
||||
// Create a loot pool with a single item entry of Items.DIAMOND
|
||||
LootPool.Builder pool = LootPool.lootPool().add(LootItem.lootTableItem(Items.DIAMOND));
|
||||
context.addPool(pool);
|
||||
}
|
||||
});*/
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ package dev.architectury.test.networking;
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.simple.BaseC2SMessage;
|
||||
import dev.architectury.networking.simple.MessageType;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
public class ButtonClickedMessage extends BaseC2SMessage {
|
||||
@@ -35,7 +35,7 @@ public class ButtonClickedMessage extends BaseC2SMessage {
|
||||
buttonId = id;
|
||||
}
|
||||
|
||||
public ButtonClickedMessage(FriendlyByteBuf buf) {
|
||||
public ButtonClickedMessage(RegistryFriendlyByteBuf buf) {
|
||||
buttonId = buf.readVarInt();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ButtonClickedMessage extends BaseC2SMessage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
public void write(RegistryFriendlyByteBuf buf) {
|
||||
buf.writeVarInt(buttonId);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import dev.architectury.networking.NetworkManager;
|
||||
import dev.architectury.networking.simple.BaseS2CMessage;
|
||||
import dev.architectury.networking.simple.MessageType;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
public class SyncDataMessage extends BaseS2CMessage {
|
||||
@@ -38,7 +38,7 @@ public class SyncDataMessage extends BaseS2CMessage {
|
||||
serverData = tag;
|
||||
}
|
||||
|
||||
public SyncDataMessage(FriendlyByteBuf buf) {
|
||||
public SyncDataMessage(RegistryFriendlyByteBuf buf) {
|
||||
serverData = buf.readNbt();
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SyncDataMessage extends BaseS2CMessage {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buf) {
|
||||
public void write(RegistryFriendlyByteBuf buf) {
|
||||
buf.writeNbt(serverData);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,16 @@ import dev.architectury.networking.transformers.SplitPacketTransformer;
|
||||
import dev.architectury.test.TestMod;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public interface TestModNet {
|
||||
SimpleNetworkManager NET = SimpleNetworkManager.create(TestMod.MOD_ID);
|
||||
@@ -41,6 +47,7 @@ public interface TestModNet {
|
||||
// An example Server to Client message
|
||||
MessageType SYNC_DATA = NET.registerS2C("sync_data", SyncDataMessage::new);
|
||||
ResourceLocation BIG_DATA = new ResourceLocation(TestMod.MOD_ID, "big_data");
|
||||
CustomPacketPayload.Type<BigDataPayload> BIG_DATA_PAYLOAD = new CustomPacketPayload.Type<>(new ResourceLocation(TestMod.MOD_ID, "big_data_payload"));
|
||||
String BIG_STRING = StringUtils.repeat('a', 100000);
|
||||
|
||||
static void initialize() {
|
||||
@@ -58,15 +65,40 @@ public interface TestModNet {
|
||||
throw new AssertionError(utf);
|
||||
}
|
||||
});
|
||||
NetworkManager.registerReceiver(NetworkManager.Side.C2S, BIG_DATA_PAYLOAD, new StreamCodec<>() {
|
||||
@Override
|
||||
public BigDataPayload decode(RegistryFriendlyByteBuf object) {
|
||||
return new BigDataPayload(object.readUtf(Integer.MAX_VALUE / 4));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(RegistryFriendlyByteBuf object, BigDataPayload payload) {
|
||||
object.writeUtf(payload.data, Integer.MAX_VALUE / 4);
|
||||
}
|
||||
}, List.of(new SplitPacketTransformer()), (value, context) -> {
|
||||
if (value.data().equals(BIG_STRING)) {
|
||||
TestMod.SINK.accept("Network Split Packets worked");
|
||||
} else {
|
||||
throw new AssertionError(value.data());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void initializeClient() {
|
||||
ClientPlayerEvent.CLIENT_PLAYER_JOIN.register(player -> {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
RegistryFriendlyByteBuf buf = new RegistryFriendlyByteBuf(Unpooled.buffer(), player.registryAccess());
|
||||
buf.writeUtf(BIG_STRING, Integer.MAX_VALUE / 4);
|
||||
// write twice
|
||||
buf.writeUtf(BIG_STRING, Integer.MAX_VALUE / 4);
|
||||
NetworkManager.sendToServer(BIG_DATA, buf);
|
||||
NetworkManager.sendToServer(new BigDataPayload(BIG_STRING));
|
||||
});
|
||||
}
|
||||
|
||||
record BigDataPayload(String data) implements CustomPacketPayload {
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() {
|
||||
return TestModNet.BIG_DATA_PAYLOAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,21 +17,15 @@ architectury {
|
||||
platformSetupLoomIde()
|
||||
neoForge {
|
||||
platformPackage = "forge"
|
||||
remapForgeLike "net/minecraftforge/common/extensions/IForgeItem", "net/neoforged/neoforge/common/extensions/IItemExtension"
|
||||
remapForgeLike "net/minecraftforge/client/event/TextureStitchEvent\$Post", "net/neoforged/neoforge/client/event/TextureAtlasStitchedEvent"
|
||||
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid", "net/neoforged/neoforge/fluids/BaseFlowingFluid"
|
||||
remapForgeLike "net/minecraftforge/fluids/ForgeFlowingFluid\$Properties", "net/neoforged/neoforge/fluids/BaseFlowingFluid\$Properties"
|
||||
remapForgeLike "net/minecraftforge/common/ForgeHooks", "net/neoforged/neoforge/common/CommonHooks"
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
common
|
||||
forgeLike
|
||||
compileClasspath.extendsFrom common, forgeLike
|
||||
runtimeClasspath.extendsFrom common, forgeLike
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentNeoForge.extendsFrom common
|
||||
developmentForgeLike.extendsFrom forgeLike
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -40,5 +34,4 @@ dependencies {
|
||||
implementation(project(path: ":neoforge", configuration: "namedElements")) { transitive false }
|
||||
common(project(path: ":common", configuration: "namedElements")) { transitive false }
|
||||
common(project(path: ":testmod-common", configuration: "namedElements")) { transitive false }
|
||||
forgeLike(project(path: ":forge", configuration: "namedElements")) { transitive false }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user