Android networking reworked

This commit is contained in:
DBotThePony 2022-08-17 17:02:07 +07:00
parent 20425015ea
commit 2f6f40d5f4
Signed by: DBot
GPG Key ID: DCC23B5715498507
24 changed files with 559 additions and 548 deletions

View File

@ -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();

View File

@ -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;
}
});

View File

@ -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--;
}
}
}
});
}
}

View File

@ -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,

View File

@ -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());
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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);
}
});
}
}
}

View File

@ -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())));
}
}

View File

@ -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());
}
}

View 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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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
}

View File

@ -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()

View File

@ -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))

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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)
}
}