diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index a17a82dbf..f31eca465 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -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(); diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java b/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java index 868ac9e59..bd933dfa4 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java @@ -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; } }); diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/EventHandler.java b/src/main/java/ru/dbotthepony/mc/otm/client/EventHandler.java deleted file mode 100644 index 54d63c96a..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/client/EventHandler.java +++ /dev/null @@ -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--; - } - } - } - }); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java index 07787bc1a..5952cff76 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -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, diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidBatteryPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidBatteryPacket.java deleted file mode 100644 index 3febcc368..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidBatteryPacket.java +++ /dev/null @@ -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 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()); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidEnergyPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidEnergyPacket.java deleted file mode 100644 index aa952c297..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidEnergyPacket.java +++ /dev/null @@ -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 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)); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java deleted file mode 100644 index 4ca835b86..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidFeaturePacket.java +++ /dev/null @@ -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 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); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchPacket.java deleted file mode 100644 index ce87552f3..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchPacket.java +++ /dev/null @@ -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 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); - } - }); - } - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchRequestPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchRequestPacket.java deleted file mode 100644 index 976326f9f..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchRequestPacket.java +++ /dev/null @@ -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 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()))); - } -} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidStatusPacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidStatusPacket.java deleted file mode 100644 index fbf5b962a..000000000 --- a/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidStatusPacket.java +++ /dev/null @@ -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 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()); - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/FriendlyStreams.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/FriendlyStreams.kt new file mode 100644 index 000000000..605cb976c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/FriendlyStreams.kt @@ -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.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.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) + } +} + + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt index 557ef4f68..31b76edbd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt @@ -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 { 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 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt index 2b8657b73..82881c07f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -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 { 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 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt index 88306412b..cc380c227 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchBuilder.kt @@ -174,6 +174,10 @@ class AndroidResearchBuilder( return object : AndroidResearchType(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] diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/AndroidStationBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/AndroidStationBlock.kt index 0d6e04409..0ef05aa49 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/AndroidStationBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/AndroidStationBlock.kt @@ -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) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt index d1edbc3cb..9c6bffc39 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt @@ -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 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt index 752fc8051..727ada42e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.kt @@ -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, AndroidFeature>() protected val networkQueue = ArrayList() protected val queuedTicks = ArrayList() - 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,41 +342,49 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil return receiveEnergyOuter(howMuch, simulate) } - override val batteryLevel: ImpreciseFraction get() { - if (!batteryItemStack.isEmpty) { - val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() + override var batteryLevel: ImpreciseFraction + get() { + if (!batteryItemStack.isEmpty) { + val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() - if (resolver.isPresent) { - val it = resolver.get() + if (resolver.isPresent) { + val it = resolver.get() - if (it is IMatteryEnergyStorage) { - return battery + it.batteryLevel - } else { - return battery + it.energyStored + if (it is IMatteryEnergyStorage) { + return battery + it.batteryLevel + } else { + return battery + it.energyStored + } } } + + return battery + } + set(value) { + maxBattery = value } - return battery - } + override var maxBatteryLevel: ImpreciseFraction + get() { + if (batteryItemStack != ItemStack.EMPTY) { + val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() - override val maxBatteryLevel: ImpreciseFraction get() { - if (batteryItemStack != ItemStack.EMPTY) { - val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() + if (resolver.isPresent) { + val it = resolver.get() - if (resolver.isPresent) { - val it = resolver.get() - - if (it is IMatteryEnergyStorage) { - return maxBattery + it.maxBatteryLevel - } else { - return maxBattery + it.maxEnergyStored + if (it is IMatteryEnergyStorage) { + return maxBattery + it.maxBatteryLevel + } else { + return maxBattery + it.maxEnergyStored + } } } - } - return maxBattery - } + return maxBattery + } + set(value) { + maxBattery = value + } private val resolver = LazyOptional.of { this } @@ -484,4 +438,6 @@ open class AndroidCapability(final override val entity: LivingEntity) : ICapabil event.entity.getCapability(MatteryCapability.ANDROID).ifPresentK { cap: IAndroidCapability -> cap.onHurt(event) } } } -} \ No newline at end of file +} + +val ICapabilityProvider.android get() = getCapability(MatteryCapability.ANDROID).orNull() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapabilityPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapabilityPlayer.kt index 40aa29095..437d0cabe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapabilityPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/AndroidCapabilityPlayer.kt @@ -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() - 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,35 +319,35 @@ 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 { - var resolver = event.original.getCapability(MatteryCapability.ANDROID) + val it = event.player.android as AndroidCapabilityPlayer? ?: return - if (!resolver.isPresent || resolver.resolve().isEmpty) { - event.original.reviveCaps() - resolver = event.original.getCapability(MatteryCapability.ANDROID) - } + var resolver = event.original.getCapability(MatteryCapability.ANDROID) - if (!resolver.isPresent || resolver.resolve().isEmpty) { - event.original.invalidateCaps() - return@ifPresent - } - - val original = resolver.resolve().get() as AndroidCapabilityPlayer - - if (original.willBecomeAndroid && event.isWasDeath) { - original.becomeAndroid() - (event.player as? ServerPlayer)?.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) - } - - it.deserializeNBT(original.serializeNBT()) - it.invalidateNetworkState() - event.original.invalidateCaps() + if (!resolver.isPresent || resolver.resolve().isEmpty) { + event.original.reviveCaps() + resolver = event.original.getCapability(MatteryCapability.ANDROID) } + + if (!resolver.isPresent || resolver.resolve().isEmpty) { + event.original.invalidateCaps() + return + } + + val original = resolver.resolve().get() as AndroidCapabilityPlayer + + if (original.willBecomeAndroid && event.isWasDeath) { + original.becomeAndroid() + (event.player as? ServerPlayer)?.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) + } + + it.deserializeNBT(original.serializeNBT()) + it.invalidateNetworkState() + event.original.invalidateCaps() } val ENERGY_FOR_HUNGER_POINT = ImpreciseFraction(1000) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt index e487c72ee..c58df17a6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/android/IAndroidCapability.kt @@ -22,6 +22,10 @@ interface IAndroidCapability : IMatteryEnergyStorage, INBTSerializable getFeature(feature: AndroidFeatureType): T? + fun computeIfAbsent(feature: AndroidFeatureType): T { + return getFeature(feature) ?: addFeature(feature) + } + fun getFeatureO(feature: AndroidFeatureType): Optional { val get = getFeature(feature) return if (get != null) Optional.of(get) else Optional.empty() @@ -35,11 +39,11 @@ interface IAndroidCapability : IMatteryEnergyStorage, INBTSerializable { 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) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/AndroidNetworking.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/AndroidNetworking.kt new file mode 100644 index 000000000..6299e73cb --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/AndroidNetworking.kt @@ -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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt new file mode 100644 index 000000000..6bf550d4a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt @@ -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) +} + +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 add( + packetClass: Class, + writer: BiConsumer, + reader: Function, + handler: BiConsumer>, + direction: NetworkDirection? = null + ) { + @Suppress("INACCESSIBLE_TYPE") + channel.registerMessage(nextNetworkPacketID++, packetClass, writer, reader, handler, if (direction == null) Optional.empty() else Optional.of(direction)) + } + + fun add( + packetClass: Class, + reader: Function, + direction: NetworkDirection? = null + ) { + add(packetClass, MatteryPacket::write, reader, MatteryPacket::play, direction) + } +}