Android networking reworked
This commit is contained in:
parent
20425015ea
commit
2f6f40d5f4
@ -21,7 +21,7 @@ import ru.dbotthepony.mc.otm.capability.android.AndroidCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
|
||||
import ru.dbotthepony.mc.otm.client.AndroidGui;
|
||||
import ru.dbotthepony.mc.otm.client.EventHandler;
|
||||
import ru.dbotthepony.mc.otm.client.EventHandlerKt;
|
||||
import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel;
|
||||
import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel;
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.QIOKt;
|
||||
@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.item.weapon.AbstractWeaponItem;
|
||||
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterDataKt;
|
||||
import ru.dbotthepony.mc.otm.matter.MatterRegistryKt;
|
||||
import ru.dbotthepony.mc.otm.network.AndroidNetworkChannel;
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
|
||||
import ru.dbotthepony.mc.otm.registry.*;
|
||||
import ru.dbotthepony.mc.otm.storage.*;
|
||||
@ -108,6 +109,8 @@ public final class OverdriveThatMatters {
|
||||
AndroidFeatureType.Companion.markRegistryLoaded();
|
||||
|
||||
MatteryNetworking.register();
|
||||
AndroidNetworkChannel.INSTANCE.register();
|
||||
|
||||
ITEM_STORAGE = StorageRegistry.register(ItemStackWrapper.class, ItemStackWrapper.EMPTY, new ImpreciseFraction("3.125"));
|
||||
|
||||
if (ModList.get().isLoaded("mekanism")) {
|
||||
@ -120,7 +123,7 @@ public final class OverdriveThatMatters {
|
||||
ANDROID_GUI = new AndroidGui();
|
||||
MinecraftForge.EVENT_BUS.register(ANDROID_GUI);
|
||||
MinecraftForge.EVENT_BUS.register(AndroidGui.class);
|
||||
MinecraftForge.EVENT_BUS.register(EventHandler.class);
|
||||
MinecraftForge.EVENT_BUS.register(EventHandlerKt.class);
|
||||
|
||||
TritaniumArmorModel.register();
|
||||
GravitationStabilizerModel.register();
|
||||
|
@ -71,7 +71,7 @@ public class AndroidGui {
|
||||
}
|
||||
|
||||
mc.player.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (!((AndroidCapabilityPlayer) cap).willBecomeAndroid) {
|
||||
if (!((AndroidCapabilityPlayer) cap).getWillBecomeAndroid()) {
|
||||
known_button.x = known_button_x;
|
||||
known_button.y = known_button_y;
|
||||
known_button_x = -1;
|
||||
@ -81,7 +81,7 @@ public class AndroidGui {
|
||||
return;
|
||||
}
|
||||
|
||||
int dispersion = (int) ((10.0 * Math.max(0, ((AndroidCapabilityPlayer) cap).sleep_ticks - 20)) / (AndroidCapabilityPlayer.SLEEP_TICKS_LIMIT - 20));
|
||||
int dispersion = (int) ((10.0 * Math.max(0, ((AndroidCapabilityPlayer) cap).getSleepTicks() - 20)) / (AndroidCapabilityPlayer.SLEEP_TICKS_LIMIT - 20));
|
||||
|
||||
known_button.x = known_button_x - dispersion / 2 + (int) (button_shaker.nextDouble() * dispersion);
|
||||
known_button.y = known_button_y - dispersion / 2 + (int) (button_shaker.nextDouble() * dispersion);
|
||||
@ -110,7 +110,7 @@ public class AndroidGui {
|
||||
known_button_screen = screen;
|
||||
|
||||
mc.player.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (((AndroidCapabilityPlayer) cap).willBecomeAndroid) {
|
||||
if (((AndroidCapabilityPlayer) cap).getWillBecomeAndroid()) {
|
||||
known_button_screen = screen;
|
||||
}
|
||||
});
|
||||
|
@ -1,44 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.client;
|
||||
|
||||
import net.minecraftforge.client.event.MovementInputUpdateEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures;
|
||||
|
||||
public class EventHandler {
|
||||
@SubscribeEvent
|
||||
public static void inputEvent(MovementInputUpdateEvent event) {
|
||||
var ply = event.getPlayer();
|
||||
var input = event.getInput();
|
||||
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(_cap -> {
|
||||
if (!(_cap instanceof AndroidCapabilityPlayer cap))
|
||||
return;
|
||||
|
||||
if (cap.hasFeature(AndroidFeatures.INSTANCE.getAIR_BAGS()))
|
||||
return;
|
||||
|
||||
if (ply.getAbilities().mayfly) {
|
||||
cap.last_jump_ticks = 14;
|
||||
} else {
|
||||
if (ply.isInWater()) {
|
||||
if (ply.isOnGround()) {
|
||||
cap.last_jump_ticks = 14;
|
||||
}
|
||||
|
||||
if (ply.isSwimming()) {
|
||||
ply.setSwimming(false);
|
||||
}
|
||||
|
||||
if (cap.last_jump_ticks <= 0) {
|
||||
event.getInput().jumping = false;
|
||||
event.getInput().up = false;
|
||||
} else {
|
||||
cap.last_jump_ticks--;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -16,12 +16,10 @@ import ru.dbotthepony.mc.otm.matter.RegistryPacketClear;
|
||||
import ru.dbotthepony.mc.otm.matter.RegistryPacketFullUpdate;
|
||||
import ru.dbotthepony.mc.otm.matter.RegistryPacketRemove;
|
||||
import ru.dbotthepony.mc.otm.matter.RegistryPacketUpdate;
|
||||
import ru.dbotthepony.mc.otm.menu.DriveViewerMenu;
|
||||
import ru.dbotthepony.mc.otm.menu.data.*;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.NumberPlayerInputPacket;
|
||||
import ru.dbotthepony.mc.otm.menu.widget.OneWayPlayerInputPacket;
|
||||
import ru.dbotthepony.mc.otm.network.android.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@ -54,42 +52,6 @@ public class MatteryNetworking {
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidBatteryPacket.class,
|
||||
AndroidBatteryPacket::write,
|
||||
AndroidBatteryPacket::read,
|
||||
AndroidBatteryPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidEnergyPacket.class,
|
||||
AndroidEnergyPacket::write,
|
||||
AndroidEnergyPacket::read,
|
||||
AndroidEnergyPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidStatusPacket.class,
|
||||
AndroidStatusPacket::write,
|
||||
AndroidStatusPacket::read,
|
||||
AndroidStatusPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidFeaturePacket.class,
|
||||
AndroidFeaturePacket::write,
|
||||
AndroidFeaturePacket::read,
|
||||
AndroidFeaturePacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
PatternGridPacket.class,
|
||||
@ -162,24 +124,6 @@ public class MatteryNetworking {
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidResearchRequestPacket.class,
|
||||
AndroidResearchRequestPacket::write,
|
||||
AndroidResearchRequestPacket::read,
|
||||
AndroidResearchRequestPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_SERVER)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
AndroidResearchPacket.class,
|
||||
AndroidResearchPacket::write,
|
||||
AndroidResearchPacket::read,
|
||||
AndroidResearchPacket::play,
|
||||
Optional.of(NetworkDirection.PLAY_TO_CLIENT)
|
||||
);
|
||||
|
||||
CHANNEL.registerMessage(
|
||||
next_network_id++,
|
||||
ClearPacket.class,
|
||||
|
@ -1,36 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidBatteryPacket(ItemStack battery) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeItem(battery);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
|
||||
});
|
||||
}
|
||||
|
||||
public void playClient() {
|
||||
var ply = Minecraft.getInstance().player;
|
||||
|
||||
if (ply != null) {
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> cap.setBatteryItemStack(battery));
|
||||
}
|
||||
}
|
||||
|
||||
public static AndroidBatteryPacket read(FriendlyByteBuf buffer) {
|
||||
return new AndroidBatteryPacket(buffer.readItem());
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidEnergyPacket(boolean is_maximal, ImpreciseFraction energy) {
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(is_maximal);
|
||||
energy.write(buffer);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
|
||||
});
|
||||
}
|
||||
|
||||
public void playClient() {
|
||||
var ply = Minecraft.getInstance().player;
|
||||
|
||||
if (ply != null) {
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (is_maximal) {
|
||||
cap.setMaxEnergy(energy);
|
||||
} else {
|
||||
cap.setEnergy(energy);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static AndroidEnergyPacket read(FriendlyByteBuf buffer) {
|
||||
return new AndroidEnergyPacket(buffer.readBoolean(), ImpreciseFraction.read(buffer));
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeature;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidFeaturePacket(boolean is_added, AndroidFeatureType<?> feature) {
|
||||
public AndroidFeaturePacket(boolean is_added, AndroidFeature feature) {
|
||||
this(is_added, feature.getType());
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(is_added);
|
||||
buffer.writeInt(MRegistry.INSTANCE.getANDROID_FEATURES().getID(feature));
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
|
||||
});
|
||||
}
|
||||
|
||||
public void playClient() {
|
||||
var ply = Minecraft.getInstance().player;
|
||||
|
||||
if (ply != null) {
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (cap instanceof AndroidCapabilityPlayer pcap) {
|
||||
pcap.addFeature(feature);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static AndroidFeaturePacket read(FriendlyByteBuf buffer) {
|
||||
var is_added = buffer.readBoolean();
|
||||
var feature = Objects.requireNonNull(MRegistry.INSTANCE.getANDROID_FEATURES().getValue(buffer.readInt()));
|
||||
|
||||
return new AndroidFeaturePacket(is_added, feature);
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearch;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidResearchPacket(AndroidResearchType<?> type, CompoundTag payload) {
|
||||
public AndroidResearchPacket(AndroidResearch research) {
|
||||
this(research.getType(), research.serializeNBT());
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(MRegistry.INSTANCE.getANDROID_RESEARCH().getID(type));
|
||||
buffer.writeNbt(payload);
|
||||
}
|
||||
|
||||
public static AndroidResearchPacket read(FriendlyByteBuf buffer) {
|
||||
return new AndroidResearchPacket(MRegistry.INSTANCE.getANDROID_RESEARCH().getValue(buffer.readInt()), buffer.readNbt());
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
|
||||
});
|
||||
}
|
||||
|
||||
public void playClient() {
|
||||
var ply = Minecraft.getInstance().player;
|
||||
|
||||
if (ply != null) {
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (cap instanceof AndroidCapabilityPlayer pcap) {
|
||||
pcap.getResearch(type).deserializeNBT(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearch;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu;
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidResearchRequestPacket(AndroidResearchType<?> research) {
|
||||
public AndroidResearchRequestPacket(AndroidResearchType<?> research) {
|
||||
this.research = research;
|
||||
}
|
||||
|
||||
public AndroidResearchRequestPacket(AndroidResearch feature) {
|
||||
this(feature.getType());
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeInt(MRegistry.INSTANCE.getANDROID_RESEARCH().getID(research));
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> context.get().getSender().getCapability(MatteryCapability.ANDROID).ifPresent(cap -> this.playServer((AndroidCapabilityPlayer) cap, context.get().getSender())));
|
||||
}
|
||||
|
||||
public void playServer(AndroidCapabilityPlayer cap, ServerPlayer ply) {
|
||||
if (!cap.isAndroid())
|
||||
return;
|
||||
|
||||
if (ply.containerMenu instanceof AndroidStationMenu)
|
||||
cap.getResearch(research).research(false);
|
||||
}
|
||||
|
||||
public static AndroidResearchRequestPacket read(FriendlyByteBuf buffer) {
|
||||
return new AndroidResearchRequestPacket(Objects.requireNonNull(MRegistry.INSTANCE.getANDROID_RESEARCH().getValue(buffer.readInt())));
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package ru.dbotthepony.mc.otm.network.android;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
import ru.dbotthepony.mc.otm.registry.MSoundEvents;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AndroidStatusPacket(Type type, boolean status, boolean playSound) {
|
||||
public enum Type {
|
||||
IS_ANDROID,
|
||||
WILL_BECOME_ANDROID,
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeByte(type.ordinal());
|
||||
buffer.writeBoolean(status);
|
||||
buffer.writeBoolean(playSound);
|
||||
}
|
||||
|
||||
public void play(Supplier<NetworkEvent.Context> context) {
|
||||
context.get().setPacketHandled(true);
|
||||
context.get().enqueueWork(() -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::playClient);
|
||||
});
|
||||
}
|
||||
|
||||
public void playClient() {
|
||||
var ply = Minecraft.getInstance().player;
|
||||
|
||||
if (ply != null) {
|
||||
ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> {
|
||||
if (cap instanceof AndroidCapabilityPlayer pcap) {
|
||||
if (type == Type.IS_ANDROID)
|
||||
pcap.isAndroid = status;
|
||||
else if (type == Type.WILL_BECOME_ANDROID)
|
||||
pcap.willBecomeAndroid = status;
|
||||
}
|
||||
|
||||
if (playSound) {
|
||||
ply.level.playSound(ply, ply, MSoundEvents.INSTANCE.getPLAYER_BECOME_ANDROID(), SoundSource.PLAYERS, 1f, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static AndroidStatusPacket read(FriendlyByteBuf buffer) {
|
||||
return new AndroidStatusPacket(Type.values()[buffer.readByte()], buffer.readBoolean(), buffer.readBoolean());
|
||||
}
|
||||
}
|
37
src/main/kotlin/ru/dbotthepony/mc/otm/FriendlyStreams.kt
Normal file
37
src/main/kotlin/ru/dbotthepony/mc/otm/FriendlyStreams.kt
Normal file
@ -0,0 +1,37 @@
|
||||
package ru.dbotthepony.mc.otm
|
||||
|
||||
import io.netty.buffer.ByteBufInputStream
|
||||
import io.netty.handler.codec.EncoderException
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtAccounter
|
||||
import net.minecraft.nbt.NbtIo
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
// But seriously, Mojang, why would you need to derive from ByteBuf directly, when you can implement
|
||||
// your own InputStream and OutputStream, since ByteBuf is meant to be operated on most time like a stream anyway?
|
||||
|
||||
// netty ByteBuf -> netty ByteBufInputStream -> Minecraft FriendlyInputStream
|
||||
|
||||
fun <T : OutputStream> T.writeNbt(value: CompoundTag): T {
|
||||
try {
|
||||
NbtIo.write(value, if (this is DataOutputStream) this else DataOutputStream(this))
|
||||
} catch (ioexception: IOException) {
|
||||
throw EncoderException(ioexception)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : InputStream> T.readNbt(accounter: NbtAccounter = NbtAccounter.UNLIMITED): CompoundTag {
|
||||
return try {
|
||||
NbtIo.read(if (this is DataInputStream) this else DataInputStream(this), accounter)
|
||||
} catch (ioexception: IOException) {
|
||||
throw EncoderException(ioexception)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,20 @@ import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapability
|
||||
import ru.dbotthepony.mc.otm.readNbt
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
import ru.dbotthepony.mc.otm.writeNbt
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: AndroidCapability) : INBTSerializable<CompoundTag> {
|
||||
val entity get() = android.entity
|
||||
|
||||
/**
|
||||
* Whenever there are changes to network
|
||||
*/
|
||||
var isDirty = false
|
||||
|
||||
open var level = 0
|
||||
set(value) {
|
||||
if (value != field) {
|
||||
@ -30,6 +39,14 @@ abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: Andr
|
||||
|
||||
open fun onHurt(event: LivingHurtEvent) {}
|
||||
|
||||
open fun writeNetwork(stream: OutputStream) {
|
||||
stream.writeNbt(serializeNBT())
|
||||
}
|
||||
|
||||
open fun readNetwork(stream: InputStream) {
|
||||
deserializeNBT(stream.readNbt())
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["level"] = level
|
||||
|
@ -3,20 +3,33 @@ package ru.dbotthepony.mc.otm.android
|
||||
import com.google.common.collect.ImmutableList
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.TranslatableComponent
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer
|
||||
import ru.dbotthepony.mc.otm.client.render.SkinElement
|
||||
import ru.dbotthepony.mc.otm.readNbt
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
import ru.dbotthepony.mc.otm.writeNbt
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability: AndroidCapabilityPlayer) : INBTSerializable<CompoundTag> {
|
||||
var isResearched = false
|
||||
protected set
|
||||
|
||||
/**
|
||||
* Whenever there are changes to network
|
||||
*/
|
||||
var isDirty = false
|
||||
|
||||
/**
|
||||
* Called when it is required to network everything again
|
||||
*/
|
||||
abstract fun invalidateNetwork()
|
||||
|
||||
fun unResearch() {
|
||||
if (!isResearched) {
|
||||
return
|
||||
@ -46,6 +59,14 @@ abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability:
|
||||
*/
|
||||
abstract fun refund(simulate: Boolean): Boolean
|
||||
|
||||
open fun writeNetwork(buff: OutputStream) {
|
||||
buff.writeNbt(serializeNBT())
|
||||
}
|
||||
|
||||
open fun readNetwork(buff: InputStream) {
|
||||
deserializeNBT(buff.readNbt())
|
||||
}
|
||||
|
||||
open val canResearch: Boolean get() {
|
||||
if (!consumeResearchCost(simulate = true)) {
|
||||
return false
|
||||
|
@ -174,6 +174,10 @@ class AndroidResearchBuilder(
|
||||
|
||||
return object : AndroidResearchType<AndroidResearch>(factory@{ it, capability ->
|
||||
return@factory object : AndroidResearch(it, capability) {
|
||||
override fun invalidateNetwork() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
override fun onUnResearch() {
|
||||
for (feature in features) {
|
||||
val level = oldResearchLevel[feature.feature]
|
||||
|
@ -31,7 +31,7 @@ class AndroidStationBlock : MatteryBlock(), EntityBlock {
|
||||
): InteractionResult {
|
||||
val cap = ply.getCapability(MatteryCapability.ANDROID).orNull() ?: return InteractionResult.FAIL
|
||||
|
||||
if (!cap.isAndroid())
|
||||
if (!cap.isAndroid)
|
||||
return InteractionResult.FAIL
|
||||
|
||||
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
|
||||
|
@ -39,7 +39,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
|
||||
|
||||
for (ent in level.getEntitiesOfClass(LivingEntity::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0))) {
|
||||
ent.getCapability(MatteryCapability.ANDROID).ifPresent {
|
||||
if (!it.isAndroid())
|
||||
if (!it.isAndroid)
|
||||
return@ifPresent
|
||||
|
||||
val missing = it.missingPower
|
||||
|
@ -12,15 +12,12 @@ import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeature
|
||||
import java.lang.Runnable
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidFeaturePacket
|
||||
import net.minecraftforge.event.entity.living.LivingHurtEvent
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
||||
import net.minecraftforge.network.PacketDistributor
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidEnergyPacket
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidBatteryPacket
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import net.minecraftforge.energy.CapabilityEnergy
|
||||
@ -37,6 +34,10 @@ import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.ifHas
|
||||
import ru.dbotthepony.mc.otm.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.network.AndroidFeatureRemovePacket
|
||||
import ru.dbotthepony.mc.otm.network.AndroidFeatureSyncPacket
|
||||
import ru.dbotthepony.mc.otm.network.AndroidNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.orNull
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import ru.dbotthepony.mc.otm.registry.StatNames
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
@ -48,14 +49,10 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
override var batteryItemStack: ItemStack = ItemStack.EMPTY
|
||||
|
||||
private var remoteBattery = ImpreciseFraction(-1)
|
||||
private var remoteMaxBattery = ImpreciseFraction(-1)
|
||||
private var remoteBatteryStack = ItemStack.EMPTY
|
||||
|
||||
protected val features = Object2ObjectArrayMap<AndroidFeatureType<*>, AndroidFeature>()
|
||||
protected val networkQueue = ArrayList<Any>()
|
||||
protected val queuedTicks = ArrayList<Runnable>()
|
||||
protected var networkTickedOnce = false
|
||||
protected var tickedOnce = false
|
||||
|
||||
protected fun addFeature(feature: AndroidFeature): Boolean {
|
||||
if (features.containsKey(feature.type)) return false
|
||||
@ -66,7 +63,7 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
}
|
||||
|
||||
if (entity is ServerPlayer) {
|
||||
sendNetwork(AndroidFeaturePacket(true, feature))
|
||||
sendNetwork(AndroidFeatureSyncPacket(feature))
|
||||
}
|
||||
|
||||
return true
|
||||
@ -86,7 +83,7 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
}
|
||||
|
||||
if (entity is ServerPlayer) {
|
||||
sendNetwork(AndroidFeaturePacket(true, factory))
|
||||
sendNetwork(AndroidFeatureSyncPacket(factory))
|
||||
}
|
||||
|
||||
return factory
|
||||
@ -103,7 +100,7 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
}
|
||||
|
||||
if (entity is ServerPlayer) {
|
||||
sendNetwork(AndroidFeaturePacket(false, removed))
|
||||
sendNetwork(AndroidFeatureRemovePacket(removed.type))
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,27 +121,6 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
return features[feature] as T?
|
||||
}
|
||||
|
||||
override fun invalidateNetworkState() {
|
||||
remoteBattery = ImpreciseFraction.MINUS_ONE
|
||||
remoteMaxBattery = ImpreciseFraction.MINUS_ONE
|
||||
remoteBatteryStack = ItemStack.EMPTY
|
||||
|
||||
if (entity is ServerPlayer) {
|
||||
for (feature in features.values) {
|
||||
sendNetwork(AndroidFeaturePacket(true, feature))
|
||||
feature.invalidateNetwork()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setEnergy(value: ImpreciseFraction) {
|
||||
battery = value
|
||||
}
|
||||
|
||||
override fun setMaxEnergy(value: ImpreciseFraction) {
|
||||
maxBattery = value
|
||||
}
|
||||
|
||||
override fun onHurt(event: LivingHurtEvent) {
|
||||
for (feature in features.values) {
|
||||
feature.onHurt(event)
|
||||
@ -216,43 +192,14 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
protected fun sendNetwork(packet: Any) {
|
||||
if (entity is ServerPlayer) {
|
||||
if (networkTickedOnce) {
|
||||
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { entity }, packet)
|
||||
if (tickedOnce) {
|
||||
AndroidNetworkChannel.send(entity, packet)
|
||||
} else {
|
||||
networkQueue.add(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun tickNetwork() {
|
||||
networkTickedOnce = true
|
||||
|
||||
if (entity is ServerPlayer) {
|
||||
if (battery != remoteBattery) {
|
||||
remoteBattery = battery
|
||||
sendNetwork(AndroidEnergyPacket(false, battery))
|
||||
}
|
||||
|
||||
if (maxBattery != remoteMaxBattery) {
|
||||
remoteMaxBattery = maxBattery
|
||||
sendNetwork(AndroidEnergyPacket(true, maxBattery))
|
||||
}
|
||||
|
||||
if (!remoteBatteryStack.equals(batteryItemStack, false)) {
|
||||
remoteBatteryStack = batteryItemStack.copy()
|
||||
sendNetwork(AndroidBatteryPacket(batteryItemStack))
|
||||
}
|
||||
|
||||
if (networkQueue.size != 0) {
|
||||
for (packet in networkQueue) {
|
||||
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with { entity }, packet)
|
||||
}
|
||||
|
||||
networkQueue.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun tickInnerClient() {}
|
||||
protected open fun tickInnerClientAlways() {}
|
||||
|
||||
@ -264,7 +211,7 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
tickInnerClientAlways()
|
||||
|
||||
if (isAndroid()) {
|
||||
if (isAndroid) {
|
||||
tickInnerClient()
|
||||
|
||||
for (feature in features.values) {
|
||||
@ -278,7 +225,7 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
tickServerAlways()
|
||||
|
||||
if (isAndroid()) {
|
||||
if (isAndroid) {
|
||||
tickServer()
|
||||
|
||||
for (feature in features.values) {
|
||||
@ -291,7 +238,6 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
}
|
||||
|
||||
queuedTicks.clear()
|
||||
tickNetwork()
|
||||
}
|
||||
|
||||
protected open fun tickServerAlways() {}
|
||||
@ -396,7 +342,8 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
return receiveEnergyOuter(howMuch, simulate)
|
||||
}
|
||||
|
||||
override val batteryLevel: ImpreciseFraction get() {
|
||||
override var batteryLevel: ImpreciseFraction
|
||||
get() {
|
||||
if (!batteryItemStack.isEmpty) {
|
||||
val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve()
|
||||
|
||||
@ -413,8 +360,12 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
return battery
|
||||
}
|
||||
set(value) {
|
||||
maxBattery = value
|
||||
}
|
||||
|
||||
override val maxBatteryLevel: ImpreciseFraction get() {
|
||||
override var maxBatteryLevel: ImpreciseFraction
|
||||
get() {
|
||||
if (batteryItemStack != ItemStack.EMPTY) {
|
||||
val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve()
|
||||
|
||||
@ -431,6 +382,9 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
|
||||
return maxBattery
|
||||
}
|
||||
set(value) {
|
||||
maxBattery = value
|
||||
}
|
||||
|
||||
private val resolver = LazyOptional.of { this }
|
||||
|
||||
@ -485,3 +439,5 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ICapabilityProvider.android get() = getCapability(MatteryCapability.ANDROID).orNull()
|
||||
|
@ -9,45 +9,43 @@ 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.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent.Clone
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerChangedDimensionEvent
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent
|
||||
import net.minecraftforge.network.PacketDistributor
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearch
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidResearchPacket
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidStatusPacket
|
||||
import ru.dbotthepony.mc.otm.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.network.*
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.MNames
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
import java.util.*
|
||||
|
||||
class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply) {
|
||||
@JvmField
|
||||
var isAndroid = false
|
||||
private var isAndroidNetwork = false
|
||||
class AndroidCapabilityPlayer(val ply: Player) : AndroidCapability(ply) {
|
||||
override var isAndroid = false
|
||||
private var remoteIsAndroid = false
|
||||
|
||||
@JvmField
|
||||
var willBecomeAndroid = false
|
||||
private var willBecomeAndroidNetwork = false
|
||||
private var shouldPlaySound = false
|
||||
private val research = ArrayList<AndroidResearch>()
|
||||
|
||||
override fun invalidateNetworkState() {
|
||||
super.invalidateNetworkState()
|
||||
private var remoteBattery = ImpreciseFraction(-1)
|
||||
private var remoteMaxBattery = ImpreciseFraction(-1)
|
||||
private var remoteBatteryStack = ItemStack.EMPTY
|
||||
|
||||
isAndroidNetwork = false
|
||||
willBecomeAndroidNetwork = false
|
||||
private var invalidateNetworkIn = 10
|
||||
|
||||
for (instance in research) {
|
||||
instance.isDirty = true
|
||||
}
|
||||
fun invalidateNetworkState() {
|
||||
invalidateNetworkIn = 10
|
||||
}
|
||||
|
||||
override fun isAndroid(): Boolean = isAndroid
|
||||
fun isEverAndroid(): Boolean = isAndroid || willBecomeAndroid
|
||||
|
||||
fun becomeAndroidSoft() {
|
||||
@ -162,41 +160,91 @@ class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply
|
||||
return instance
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var last_jump_ticks = 14
|
||||
var lastJumpTicks = 14
|
||||
|
||||
override fun tickNetwork() {
|
||||
super.tickNetwork()
|
||||
if (isAndroid != isAndroidNetwork) {
|
||||
isAndroidNetwork = isAndroid
|
||||
sendNetwork(AndroidStatusPacket(AndroidStatusPacket.Type.IS_ANDROID, isAndroid, shouldPlaySound))
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (invalidateNetworkIn > 0 && --invalidateNetworkIn == 0) {
|
||||
remoteBattery = ImpreciseFraction.MINUS_ONE
|
||||
remoteMaxBattery = ImpreciseFraction.MINUS_ONE
|
||||
remoteBatteryStack = ItemStack.EMPTY
|
||||
|
||||
remoteIsAndroid = false
|
||||
willBecomeAndroidNetwork = false
|
||||
|
||||
for (instance in research) {
|
||||
instance.isDirty = true
|
||||
instance.invalidateNetwork()
|
||||
}
|
||||
|
||||
for (feature in features.values) {
|
||||
feature.isDirty = true
|
||||
feature.invalidateNetwork()
|
||||
}
|
||||
}
|
||||
|
||||
tickedOnce = true
|
||||
|
||||
if (battery != remoteBattery) {
|
||||
remoteBattery = battery
|
||||
sendNetwork(AndroidEnergyLevelPacket(level = battery, isMaxEnergy = false))
|
||||
}
|
||||
|
||||
if (maxBattery != remoteMaxBattery) {
|
||||
remoteMaxBattery = maxBattery
|
||||
sendNetwork(AndroidEnergyLevelPacket(level = maxBattery, isMaxEnergy = true))
|
||||
}
|
||||
|
||||
if (!remoteBatteryStack.equals(batteryItemStack, false)) {
|
||||
remoteBatteryStack = batteryItemStack.copy()
|
||||
sendNetwork(AndroidBatteryItemPacket(batteryItemStack))
|
||||
}
|
||||
|
||||
if (networkQueue.size != 0) {
|
||||
for (packet in networkQueue) {
|
||||
AndroidNetworkChannel.send(ply, packet)
|
||||
}
|
||||
|
||||
networkQueue.clear()
|
||||
}
|
||||
|
||||
if (isAndroid != remoteIsAndroid) {
|
||||
remoteIsAndroid = isAndroid
|
||||
sendNetwork(IsAndroidPacket(isAndroid))
|
||||
shouldPlaySound = false
|
||||
}
|
||||
|
||||
if (willBecomeAndroid != willBecomeAndroidNetwork) {
|
||||
willBecomeAndroidNetwork = willBecomeAndroid
|
||||
sendNetwork(AndroidStatusPacket(AndroidStatusPacket.Type.WILL_BECOME_ANDROID, willBecomeAndroid, false))
|
||||
sendNetwork(WillBecomeAndroidPacket(willBecomeAndroid))
|
||||
}
|
||||
|
||||
for (instance in research) {
|
||||
if (instance.isDirty) {
|
||||
instance.isDirty = false
|
||||
sendNetwork(AndroidResearchPacket(instance))
|
||||
sendNetwork(AndroidResearchSyncPacket(instance))
|
||||
}
|
||||
}
|
||||
|
||||
for (instance in features.values) {
|
||||
if (instance.isDirty) {
|
||||
instance.isDirty = false
|
||||
sendNetwork(AndroidFeatureSyncPacket(instance))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
var sleep_ticks = 0
|
||||
var sleepTicks = 0
|
||||
|
||||
override fun tickInnerClientAlways() {
|
||||
super.tickInnerClientAlways()
|
||||
|
||||
if (willBecomeAndroid) {
|
||||
if (ply.isSleeping) {
|
||||
sleep_ticks++
|
||||
sleepTicks++
|
||||
} else {
|
||||
sleep_ticks = 0
|
||||
sleepTicks = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,17 +254,17 @@ class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply
|
||||
|
||||
if (willBecomeAndroid) {
|
||||
if (ply.isSleeping) {
|
||||
sleep_ticks++
|
||||
sleepTicks++
|
||||
|
||||
if (sleep_ticks > SLEEP_TICKS_LIMIT) {
|
||||
if (sleepTicks > SLEEP_TICKS_LIMIT) {
|
||||
becomeAndroid()
|
||||
shouldPlaySound = true
|
||||
sleep_ticks = 0
|
||||
sleepTicks = 0
|
||||
|
||||
(ply as? ServerPlayer)?.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false)
|
||||
}
|
||||
} else {
|
||||
sleep_ticks = 0
|
||||
sleepTicks = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -271,12 +319,13 @@ class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply
|
||||
@SubscribeEvent
|
||||
fun onPlayerChangeDimensionEvent(event: PlayerChangedDimensionEvent) {
|
||||
event.player.getCapability(MatteryCapability.ANDROID)
|
||||
.ifPresent { it.invalidateNetworkState() }
|
||||
.ifPresentK { (it as AndroidCapabilityPlayer).invalidateNetworkState() }
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onPlayerCloneEvent(event: Clone) {
|
||||
event.player.getCapability(MatteryCapability.ANDROID).ifPresent {
|
||||
val it = event.player.android as AndroidCapabilityPlayer? ?: return
|
||||
|
||||
var resolver = event.original.getCapability(MatteryCapability.ANDROID)
|
||||
|
||||
if (!resolver.isPresent || resolver.resolve().isEmpty) {
|
||||
@ -286,7 +335,7 @@ class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply
|
||||
|
||||
if (!resolver.isPresent || resolver.resolve().isEmpty) {
|
||||
event.original.invalidateCaps()
|
||||
return@ifPresent
|
||||
return
|
||||
}
|
||||
|
||||
val original = resolver.resolve().get() as AndroidCapabilityPlayer
|
||||
@ -300,7 +349,6 @@ class AndroidCapabilityPlayer(@JvmField val ply: Player) : AndroidCapability(ply
|
||||
it.invalidateNetworkState()
|
||||
event.original.invalidateCaps()
|
||||
}
|
||||
}
|
||||
|
||||
val ENERGY_FOR_HUNGER_POINT = ImpreciseFraction(1000)
|
||||
const val SLEEP_TICKS_LIMIT = 80
|
||||
|
@ -22,6 +22,10 @@ interface IAndroidCapability : IMatteryEnergyStorage, INBTSerializable<CompoundT
|
||||
|
||||
fun <T : AndroidFeature> getFeature(feature: AndroidFeatureType<T>): T?
|
||||
|
||||
fun <T : AndroidFeature> computeIfAbsent(feature: AndroidFeatureType<T>): T {
|
||||
return getFeature(feature) ?: addFeature(feature)
|
||||
}
|
||||
|
||||
fun <T : AndroidFeature> getFeatureO(feature: AndroidFeatureType<T>): Optional<T> {
|
||||
val get = getFeature(feature)
|
||||
return if (get != null) Optional.of(get) else Optional.empty()
|
||||
@ -35,11 +39,11 @@ interface IAndroidCapability : IMatteryEnergyStorage, INBTSerializable<CompoundT
|
||||
}
|
||||
}
|
||||
|
||||
fun isAndroid(): Boolean = true
|
||||
val isAndroid: Boolean get() = true
|
||||
|
||||
fun onHurt(event: LivingHurtEvent) {}
|
||||
var batteryItemStack: ItemStack
|
||||
fun invalidateNetworkState() // tell capability that player forgot everything, and everything needs to be re-networked
|
||||
fun setEnergy(value: ImpreciseFraction)
|
||||
fun setMaxEnergy(value: ImpreciseFraction)
|
||||
|
||||
override var batteryLevel: ImpreciseFraction
|
||||
override var maxBatteryLevel: ImpreciseFraction
|
||||
}
|
@ -15,6 +15,7 @@ import org.lwjgl.opengl.GL30
|
||||
import ru.dbotthepony.mc.otm.block.entity.GravitationStabilizerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.android.android
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.registry.MItems
|
||||
import kotlin.math.PI
|
||||
@ -144,10 +145,8 @@ class BlackHoleRenderer(private val context: BlockEntityRendererProvider.Context
|
||||
if (!Minecraft.getInstance().options.hideGui && (
|
||||
(ply.mainHandItem.item == MItems.BLACK_HOLE_SCANNER || ply.offhandItem.item == MItems.BLACK_HOLE_SCANNER) &&
|
||||
poseStack.translation().length() < tile.gravitationStrength * 64.0 ||
|
||||
(ply.abilities.instabuild || ply.abilities.invulnerable ||
|
||||
ply.getCapability(MatteryCapability.ANDROID).isPresent &&
|
||||
ply.getCapability(MatteryCapability.ANDROID).resolve().get().isAndroid()) &&
|
||||
poseStack.translation().length() < tile.gravitationStrength * 32.0
|
||||
(ply.abilities.instabuild || ply.android?.isAndroid == true) &&
|
||||
poseStack.translation().length() < tile.gravitationStrength * 28.0
|
||||
)) {
|
||||
val facing = tile.blockPos.asVector() - Minecraft.getInstance().gameRenderer.mainCamera.position
|
||||
val distance = facing.length()
|
||||
|
@ -19,8 +19,9 @@ import ru.dbotthepony.mc.otm.client.screen.panels.*
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
|
||||
import ru.dbotthepony.mc.otm.core.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
|
||||
import ru.dbotthepony.mc.otm.network.AndroidNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
|
||||
import ru.dbotthepony.mc.otm.network.MatteryNetworking
|
||||
import ru.dbotthepony.mc.otm.network.android.AndroidResearchRequestPacket
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import java.util.*
|
||||
|
||||
@ -73,7 +74,7 @@ class AndroidStationScreen constructor(p_97741_: AndroidStationMenu, p_97742_: I
|
||||
override fun mouseClickedInner(mouse_x: Double, mouse_y: Double, mouse_click_type: Int): Boolean {
|
||||
if (mouse_click_type == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||
if (node.canResearch && !node.isResearched) {
|
||||
MatteryNetworking.CHANNEL.sendToServer(AndroidResearchRequestPacket(node.type))
|
||||
AndroidNetworkChannel.sendToServer(AndroidResearchRequestPacket(node.type))
|
||||
}
|
||||
|
||||
ru.dbotthepony.mc.otm.client.minecraft.soundManager.play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f))
|
||||
|
@ -41,7 +41,7 @@ class HealPillItem : Item(Properties().stacksTo(64).rarity(Rarity.UNCOMMON).tab(
|
||||
override fun use(level: Level, ply: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
|
||||
val resolver = ply.getCapability(MatteryCapability.ANDROID).resolve()
|
||||
|
||||
if (!resolver.isEmpty && resolver.get().isAndroid())
|
||||
if (!resolver.isEmpty && resolver.get().isAndroid)
|
||||
return super.use(level, ply, hand)
|
||||
|
||||
ply.startUsingItem(hand)
|
||||
@ -51,7 +51,7 @@ class HealPillItem : Item(Properties().stacksTo(64).rarity(Rarity.UNCOMMON).tab(
|
||||
override fun finishUsingItem(stack: ItemStack, level: Level, ent: LivingEntity): ItemStack {
|
||||
val resolver = ent.getCapability(MatteryCapability.ANDROID).resolve()
|
||||
|
||||
if (!resolver.isEmpty && resolver.get().isAndroid())
|
||||
if (!resolver.isEmpty && resolver.get().isAndroid)
|
||||
return super.finishUsingItem(stack, level, ent)
|
||||
|
||||
stack.shrink(1)
|
||||
@ -106,7 +106,7 @@ class PillItem(val pillType: PillType) :
|
||||
if (
|
||||
pillType == PillType.BECOME_ANDROID && !cap.isEverAndroid() ||
|
||||
pillType == PillType.BECOME_HUMANE && cap.isEverAndroid() ||
|
||||
pillType == PillType.OBLIVION && cap.isAndroid()
|
||||
pillType == PillType.OBLIVION && cap.isAndroid
|
||||
) {
|
||||
ply.startUsingItem(hand)
|
||||
return InteractionResultHolder.consume(ply.getItemInHand(hand))
|
||||
@ -127,7 +127,7 @@ class PillItem(val pillType: PillType) :
|
||||
|
||||
val cap = resolver.get() as AndroidCapabilityPlayer
|
||||
|
||||
if (pillType == PillType.OBLIVION && cap.isAndroid()) {
|
||||
if (pillType == PillType.OBLIVION && cap.isAndroid) {
|
||||
if (!ent.abilities.instabuild) {
|
||||
stack.shrink(1)
|
||||
}
|
||||
|
@ -0,0 +1,241 @@
|
||||
package ru.dbotthepony.mc.otm.network
|
||||
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT
|
||||
import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeature
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearch
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.capability.android.*
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.core.readImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.core.writeImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.function.Supplier
|
||||
|
||||
sealed class AndroidStatusPacket : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {}
|
||||
|
||||
protected abstract fun play(capability: AndroidCapabilityPlayer)
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
play(minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object IsAndroidPacket : AndroidStatusPacket() {
|
||||
override fun play(capability: AndroidCapabilityPlayer) {
|
||||
capability.isAndroid = true
|
||||
}
|
||||
}
|
||||
|
||||
object IsNotAndroidPacket : AndroidStatusPacket() {
|
||||
override fun play(capability: AndroidCapabilityPlayer) {
|
||||
capability.isAndroid = false
|
||||
}
|
||||
}
|
||||
|
||||
fun IsAndroidPacket(status: Boolean) = if (status) IsAndroidPacket else IsNotAndroidPacket
|
||||
|
||||
object WillBecomeAndroidPacket : AndroidStatusPacket() {
|
||||
override fun play(capability: AndroidCapabilityPlayer) {
|
||||
capability.willBecomeAndroid = true
|
||||
}
|
||||
}
|
||||
|
||||
object WillNotBecomeAndroidPacket : AndroidStatusPacket() {
|
||||
override fun play(capability: AndroidCapabilityPlayer) {
|
||||
capability.willBecomeAndroid = false
|
||||
}
|
||||
}
|
||||
|
||||
fun WillBecomeAndroidPacket(status: Boolean) = if (status) WillBecomeAndroidPacket else WillNotBecomeAndroidPacket
|
||||
|
||||
class AndroidResearchRequestPacket(val type: AndroidResearchType<*>) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeInt(MRegistry.ANDROID_RESEARCH.getID(type))
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val ply = context.get().sender ?: return@enqueueWork
|
||||
val android = ply.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
if (!android.isAndroid || ply.containerMenu !is AndroidStationMenu)
|
||||
return@enqueueWork
|
||||
|
||||
android.getResearch(type).research()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidResearchRequestPacket {
|
||||
return AndroidResearchRequestPacket(MRegistry.ANDROID_RESEARCH.getValue(buff.readInt()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getData(invoke: (stream: OutputStream) -> Unit): FastByteArrayOutputStream {
|
||||
val stream = FastByteArrayOutputStream()
|
||||
invoke(stream)
|
||||
return stream
|
||||
}
|
||||
|
||||
class AndroidResearchSyncPacket(val type: AndroidResearchType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket {
|
||||
constructor(feature: AndroidResearch) : this(feature.type, getData(feature::writeNetwork), null)
|
||||
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
dataList ?: throw NullPointerException("No byte list is present")
|
||||
buff.writeInt(MRegistry.ANDROID_RESEARCH.getID(type))
|
||||
buff.writeBytes(dataList.array, 0, dataList.length)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
dataBytes ?: throw NullPointerException("No data bytes array is present")
|
||||
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val android = minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
android.getResearch(type).readNetwork(ByteArrayInputStream(dataBytes))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidResearchSyncPacket {
|
||||
return AndroidResearchSyncPacket(
|
||||
MRegistry.ANDROID_RESEARCH.getValue(buff.readInt()),
|
||||
null, ByteArray(buff.readableBytes()).also { buff.readBytes(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket {
|
||||
constructor(feature: AndroidFeature) : this(feature.type, getData(feature::writeNetwork), null)
|
||||
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
dataList ?: throw NullPointerException("No byte list is present")
|
||||
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
|
||||
buff.writeBytes(dataList.array, 0, dataList.length)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
dataBytes ?: throw NullPointerException("No data bytes array is present")
|
||||
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val android = minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
android.computeIfAbsent(type).readNetwork(ByteArrayInputStream(dataBytes))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidFeatureSyncPacket {
|
||||
return AndroidFeatureSyncPacket(
|
||||
MRegistry.ANDROID_FEATURES.getValue(buff.readInt()),
|
||||
null, ByteArray(buff.readableBytes()).also { buff.readBytes(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidFeatureRemovePacket(val type: AndroidFeatureType<*>) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val android = minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
android.removeFeature(type)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidFeatureRemovePacket {
|
||||
return AndroidFeatureRemovePacket(MRegistry.ANDROID_FEATURES.getValue(buff.readInt()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidBatteryItemPacket(val item: ItemStack) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeItem(item)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val android = minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
android.batteryItemStack = item
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidBatteryItemPacket {
|
||||
return AndroidBatteryItemPacket(buff.readItem())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidEnergyLevelPacket(val level: ImpreciseFraction, val isMaxEnergy: Boolean) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeBoolean(isMaxEnergy)
|
||||
buff.writeImpreciseFraction(level)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
context.get().enqueueWork {
|
||||
val android = minecraft.player?.android as? AndroidCapabilityPlayer ?: return@enqueueWork
|
||||
|
||||
if (isMaxEnergy) {
|
||||
android.maxBatteryLevel = level
|
||||
} else {
|
||||
android.batteryLevel = level
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): AndroidEnergyLevelPacket {
|
||||
return AndroidEnergyLevelPacket(buff.readImpreciseFraction(), buff.readBoolean())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object AndroidNetworkChannel : MatteryNetworkChannel(
|
||||
version = "1",
|
||||
name = "android"
|
||||
) {
|
||||
fun register() {
|
||||
add(IsAndroidPacket::class.java, { IsAndroidPacket }, PLAY_TO_CLIENT)
|
||||
add(IsNotAndroidPacket::class.java, { IsNotAndroidPacket }, PLAY_TO_CLIENT)
|
||||
add(WillBecomeAndroidPacket::class.java, { WillBecomeAndroidPacket }, PLAY_TO_CLIENT)
|
||||
add(WillNotBecomeAndroidPacket::class.java, { WillNotBecomeAndroidPacket }, PLAY_TO_CLIENT)
|
||||
|
||||
add(AndroidResearchRequestPacket::class.java, AndroidResearchRequestPacket.Companion::read, PLAY_TO_SERVER)
|
||||
add(AndroidResearchSyncPacket::class.java, AndroidResearchSyncPacket.Companion::read, PLAY_TO_CLIENT)
|
||||
add(AndroidFeatureSyncPacket::class.java, AndroidFeatureSyncPacket.Companion::read, PLAY_TO_CLIENT)
|
||||
add(AndroidFeatureRemovePacket::class.java, AndroidFeatureRemovePacket.Companion::read, PLAY_TO_CLIENT)
|
||||
add(AndroidBatteryItemPacket::class.java, AndroidBatteryItemPacket.Companion::read, PLAY_TO_CLIENT)
|
||||
add(AndroidEnergyLevelPacket::class.java, AndroidEnergyLevelPacket.Companion::read, PLAY_TO_CLIENT)
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package ru.dbotthepony.mc.otm.network
|
||||
|
||||
import java.util.function.Function
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraftforge.network.NetworkDirection
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import net.minecraftforge.network.NetworkRegistry
|
||||
import net.minecraftforge.network.PacketDistributor
|
||||
import net.minecraftforge.network.simple.SimpleChannel
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import java.util.Optional
|
||||
import java.util.function.BiConsumer
|
||||
import java.util.function.Supplier
|
||||
|
||||
interface MatteryPacket {
|
||||
fun write(buff: FriendlyByteBuf)
|
||||
fun play(context: Supplier<NetworkEvent.Context>)
|
||||
}
|
||||
|
||||
abstract class MatteryNetworkChannel(val version: String, val name: String) {
|
||||
val channel: SimpleChannel = NetworkRegistry.newSimpleChannel(
|
||||
ResourceLocation(OverdriveThatMatters.MOD_ID, name),
|
||||
{ version },
|
||||
{ it == version },
|
||||
{ it == version },
|
||||
)
|
||||
|
||||
fun sendToServer(packet: Any) = channel.sendToServer(packet)
|
||||
|
||||
fun send(ply: Player, packet: Any) {
|
||||
if (ply is ServerPlayer) {
|
||||
channel.send(PacketDistributor.PLAYER.with { ply }, packet)
|
||||
}
|
||||
}
|
||||
|
||||
fun send(distributor: PacketDistributor.PacketTarget, packet: Any) = channel.send(distributor, packet)
|
||||
|
||||
private var nextNetworkPacketID = 0
|
||||
|
||||
fun <T> add(
|
||||
packetClass: Class<T>,
|
||||
writer: BiConsumer<T, FriendlyByteBuf>,
|
||||
reader: Function<FriendlyByteBuf, T>,
|
||||
handler: BiConsumer<T, Supplier<NetworkEvent.Context>>,
|
||||
direction: NetworkDirection? = null
|
||||
) {
|
||||
@Suppress("INACCESSIBLE_TYPE")
|
||||
channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction))
|
||||
}
|
||||
|
||||
fun <T : MatteryPacket> add(
|
||||
packetClass: Class<T>,
|
||||
reader: Function<FriendlyByteBuf, T>,
|
||||
direction: NetworkDirection? = null
|
||||
) {
|
||||
add(packetClass, MatteryPacket::write, reader, MatteryPacket::play, direction)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user