diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index ead3bafb5..9108bc88f 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; @@ -16,12 +17,25 @@ import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import ru.dbotthepony.mc.otm.block.BlockAndroidStation; import ru.dbotthepony.mc.otm.block.entity.BlockEntityAndroidStation; +import ru.dbotthepony.mc.otm.item.ItemPill; import ru.dbotthepony.mc.otm.menu.AndroidStationMenu; import ru.dbotthepony.mc.otm.screen.AndroidStationScreen; public class Registry { + public static final DamageSource DAMAGE_BECOME_ANDROID = new DamageSource("otmBecomeAndroid"); + public static final DamageSource DAMAGE_BECOME_HUMANE = new DamageSource("otmBecomeHumane"); + + static { + DAMAGE_BECOME_ANDROID.bypassArmor().bypassInvul().bypassMagic(); + DAMAGE_BECOME_HUMANE.bypassArmor().bypassInvul().bypassMagic(); + } + public static class Names { public static final ResourceLocation ANDROID_STATION = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_station"); + public static final ResourceLocation ANDROID_CAPABILITY = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_capability"); + + public static final ResourceLocation PILL_ANDROID = new ResourceLocation(OverdriveThatMatters.MOD_ID, "pill_android"); + public static final ResourceLocation PILL_HUMANE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "pill_humane"); } public static class Blocks { @@ -35,10 +49,19 @@ public class Registry { } public static class Items { - public static Item ANDROID_STATION = new BlockItem(Blocks.ANDROID_STATION, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC)).setRegistryName(Names.ANDROID_STATION); + public static final Item ANDROID_STATION = new BlockItem(Blocks.ANDROID_STATION, new Item.Properties().stacksTo(64).tab(CreativeModeTab.TAB_MISC)).setRegistryName(Names.ANDROID_STATION); + public static final ItemPill PILL_ANDROID = new ItemPill(ItemPill.PillType.BECOME_ANDROID); + public static final ItemPill PILL_HUMANE = new ItemPill(ItemPill.PillType.BECOME_HUMANE); + + static { + PILL_ANDROID.setRegistryName(Names.PILL_ANDROID); + PILL_HUMANE.setRegistryName(Names.PILL_HUMANE); + } public static void register(final RegistryEvent.Register event) { event.getRegistry().register(ANDROID_STATION); + event.getRegistry().register(PILL_ANDROID); + event.getRegistry().register(PILL_HUMANE); // OverdriveThatMatters.LOGGER.info("Registered items"); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/BlockAndroidStation.java b/src/main/java/ru/dbotthepony/mc/otm/block/BlockAndroidStation.java index 32ff01598..7ada752c1 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/BlockAndroidStation.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/BlockAndroidStation.java @@ -1,6 +1,9 @@ package ru.dbotthepony.mc.otm.block; import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EntityBlock; @@ -8,11 +11,15 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import net.minecraftforge.common.util.LazyOptional; import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityAndroidStation; +import ru.dbotthepony.mc.otm.capability.IAndroidCapability; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; import javax.annotation.Nullable; @@ -24,6 +31,16 @@ public class BlockAndroidStation extends BlockMatteryMachineBase implements Enti this.setRegistryName(Registry.Names.ANDROID_STATION); } + @Override + public InteractionResult use(BlockState p_60503_, Level level, BlockPos pos, Player ply, InteractionHand p_60507_, BlockHitResult p_60508_) { + LazyOptional cap = ply.getCapability(MatteryCapability.ANDROID); + + if (cap.resolve().isEmpty() || !cap.resolve().get().isAndroid()) + return InteractionResult.FAIL; + + return super.use(p_60503_, level, pos, ply, p_60507_, p_60508_); + } + @Override public VoxelShape getShape(BlockState p_151964_, BlockGetter p_151965_, BlockPos p_151966_, CollisionContext p_151967_) { return SHAPE; diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityAndroidStation.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityAndroidStation.java index f5f47ce5c..d085e503a 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityAndroidStation.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityAndroidStation.java @@ -20,6 +20,7 @@ import ru.dbotthepony.mc.otm.menu.AndroidStationMenu; import javax.annotation.Nullable; import java.math.BigDecimal; import java.util.List; +import java.util.Optional; public class BlockEntityAndroidStation extends BlockEntityMatteryPoweredMachine implements MenuProvider { @Nullable @@ -42,23 +43,27 @@ public class BlockEntityAndroidStation extends BlockEntityMatteryPoweredMachine List entities = tile.getLevel().getEntitiesOfClass(LivingEntity.class, new AABB(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 2, pos.getZ() + 1)); for (LivingEntity ent : entities) { - LazyOptional resolver = ent.getCapability(MatteryCapability.ANDROID); + Optional resolver = ent.getCapability(MatteryCapability.ANDROID).resolve(); - if (resolver.isPresent()) { - IAndroidCapability capability = resolver.resolve().get(); + if (resolver.isEmpty()) + continue; - BigDecimal missing = capability.getMissingPower(); + IAndroidCapability capability = resolver.get(); - if (missing.compareTo(BigDecimal.ZERO) == 1) { - BigDecimal extract = tile.energy.extractEnergyInner(missing, true); + if (!capability.isAndroid()) + continue; - if (extract.compareTo(BigDecimal.ZERO) == 1) { - BigDecimal received = capability.receiveEnergyOuter(extract, true); + BigDecimal missing = capability.getMissingPower(); - if (received.compareTo(BigDecimal.ZERO) == 1) { - tile.energy.extractEnergyInner(extract, false); - capability.receiveEnergyOuter(extract, false); - } + if (missing.compareTo(BigDecimal.ZERO) == 1) { + BigDecimal extract = tile.energy.extractEnergyInner(missing, true); + + if (extract.compareTo(BigDecimal.ZERO) == 1) { + BigDecimal received = capability.receiveEnergyOuter(extract, true); + + if (received.compareTo(BigDecimal.ZERO) == 1) { + tile.energy.extractEnergyInner(extract, false); + capability.receiveEnergyOuter(extract, false); } } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java index d14405761..f28da4d89 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapability.java @@ -34,6 +34,13 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit private BigDecimal network_energy_max = new BigDecimal(-1); private ItemStack network_battery = ItemStack.EMPTY; + @Override + public void invalidateNetworkState() { + network_energy = new BigDecimal(-1); + network_energy_max = new BigDecimal(-1); + network_battery = ItemStack.EMPTY; + } + public static final BigDecimal ENERGY_FOR_HUNGER_POINT = new BigDecimal(200); public AndroidCapability(LivingEntity ent) { @@ -70,6 +77,14 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit battery = ItemStack.of(compound.getCompound("battery")); } + public void dropBattery() { + if (battery.isEmpty()) + return; + + ent.spawnAtLocation(battery); + battery = ItemStack.EMPTY; + } + protected void tickNetwork() { } @@ -77,6 +92,9 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit @Override @Nullable public AndroidCapabilityChangePacket writeChanges() { + if (!isAndroid()) + return null; + AndroidCapabilityChangePacket packet = null; if (!energy_stored.equals(network_energy)) { @@ -119,7 +137,9 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit @Override public void tick() { - tickInner(); + if (isAndroid()) + tickInner(); + tickNetwork(); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java index 1f9c9d80d..a237882d6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/AndroidCapabilityPlayer.java @@ -1,6 +1,6 @@ package ru.dbotthepony.mc.otm.capability; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; @@ -11,22 +11,107 @@ import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fmllegacy.network.PacketDistributor; import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.network.AndroidCapabilityChangePacket; import ru.dbotthepony.mc.otm.network.MatteryNetwork; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.math.BigDecimal; -import java.util.Random; public class AndroidCapabilityPlayer extends AndroidCapability { - public static final ResourceLocation ANDROID_CAPABILITY_LOCATION = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_capability"); + private boolean is_android = false; + private boolean network_is_android = false; + + @Override + public void invalidateNetworkState() { + super.invalidateNetworkState(); + network_is_android = false; + } + + @Override + public void readChanges(AndroidCapabilityChangePacket packet) { + super.readChanges(packet); + + if (packet.is_android != null) { + is_android = packet.is_android; + } + } + + @Nullable + @Override + public AndroidCapabilityChangePacket writeChanges() { + AndroidCapabilityChangePacket packet = super.writeChanges(); + + if (is_android != network_is_android) { + network_is_android = is_android; + if (packet == null) packet = new AndroidCapabilityChangePacket(); + packet.isAndroid(is_android); + } + + return packet; + } + + @Override + public boolean isAndroid() { + return is_android; + } + + public void becomeAndroid() { + if (is_android) + return; + + is_android = true; + energy_stored = new BigDecimal(32_000); + energy_stored_max = new BigDecimal(32_000); + + ply.setHealth(0.0F); + ply.die(Registry.DAMAGE_BECOME_ANDROID); + } + + @Override + public void deserializeNBT(CompoundTag compound) { + super.deserializeNBT(compound); + + if (compound.contains("is_android")) + is_android = compound.getByte("is_android") > 0; + } + + @Nonnull + @Override + public CompoundTag serializeNBT() { + CompoundTag tag = super.serializeNBT(); + tag.putByte("is_android", is_android ? (byte) 1 : (byte) 0); + return tag; + } + + public void becomeHumane() { + if (!is_android) + return; + + is_android = false; + + energy_stored = new BigDecimal(0); + energy_stored_max = new BigDecimal(32_000); + + dropBattery(); + + ply.setHealth(0.0F); + ply.die(Registry.DAMAGE_BECOME_HUMANE); + } @SubscribeEvent public static void onAttachCapabilityEvent(AttachCapabilitiesEvent event) { if (event.getObject() instanceof Player ply) { - event.addCapability(ANDROID_CAPABILITY_LOCATION, new AndroidCapabilityPlayer(ply)); + event.addCapability(Registry.Names.ANDROID_CAPABILITY, new AndroidCapabilityPlayer(ply)); } } + @SubscribeEvent + public static void onPlayerChangeDimensionEvent(PlayerEvent.PlayerChangedDimensionEvent event) { + event.getPlayer().getCapability(MatteryCapability.ANDROID).ifPresent(IAndroidCapability::invalidateNetworkState); + } + @SubscribeEvent public static void onPlayerCloneEvent(PlayerEvent.Clone event) { event.getPlayer().getCapability(MatteryCapability.ANDROID).ifPresent((cap) -> { @@ -43,6 +128,7 @@ public class AndroidCapabilityPlayer extends AndroidCapability { } cap.deserializeNBT(resolver.resolve().get().serializeNBT()); + cap.invalidateNetworkState(); event.getOriginal().invalidateCaps(); }); } diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java index 64540a14a..782d291e6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/IAndroidCapability.java @@ -15,11 +15,16 @@ public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializa void tickClient(); LivingEntity getEntity(); + default boolean isAndroid() { + return true; + } + @Nonnull ItemStack getBatteryItemStack(); void setBatteryItemStack(@Nonnull ItemStack stack); // networking - AndroidCapabilityChangePacket writeChanges(); - void readChanges(AndroidCapabilityChangePacket packet); + void invalidateNetworkState(); // tell capability that player forgot everything + AndroidCapabilityChangePacket writeChanges(); // write changes to network + void readChanges(AndroidCapabilityChangePacket packet); // read changes from network } 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 5e203603a..38dd2d77d 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/AndroidGui.java @@ -51,7 +51,7 @@ public class AndroidGui { android = last_state; } - if (android != null && mc.gui instanceof ForgeIngameGui gui) { + if (android != null && android.isAndroid() && mc.gui instanceof ForgeIngameGui gui) { event.setCanceled(true); last_state = android; diff --git a/src/main/java/ru/dbotthepony/mc/otm/item/ItemPill.java b/src/main/java/ru/dbotthepony/mc/otm/item/ItemPill.java new file mode 100644 index 000000000..bc78b6242 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/item/ItemPill.java @@ -0,0 +1,87 @@ +package ru.dbotthepony.mc.otm.item; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.*; +import net.minecraft.world.level.Level; +import net.minecraftforge.common.util.FakePlayer; +import org.apache.logging.log4j.core.jmx.Server; +import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer; +import ru.dbotthepony.mc.otm.capability.IAndroidCapability; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; + +import java.util.Optional; + +public class ItemPill extends Item { + public enum PillType { + BECOME_ANDROID, + BECOME_HUMANE + } + + public final PillType pill_type; + + public ItemPill(PillType type) { + super(new Properties().stacksTo(64).rarity(Rarity.UNCOMMON).tab(CreativeModeTab.TAB_MISC)); + this.pill_type = type; + } + + @Override + public int getUseDuration(ItemStack p_41454_) { + return 32; + } + + @Override + public InteractionResultHolder use(Level level, Player ply, InteractionHand hand) { + if (ply instanceof FakePlayer) + return super.use(level, ply, hand); + + Optional resolver = ply.getCapability(MatteryCapability.ANDROID).resolve(); + + if (resolver.isEmpty() || !(resolver.get() instanceof AndroidCapabilityPlayer)) + return super.use(level, ply, hand); + + if (this.pill_type == PillType.BECOME_ANDROID && !resolver.get().isAndroid() || this.pill_type == PillType.BECOME_HUMANE && resolver.get().isAndroid()) { + ply.startUsingItem(hand); + return InteractionResultHolder.consume(ply.getItemInHand(hand)); + } + + return super.use(level, ply, hand); + } + + @Override + public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity ent) { + if (ent instanceof FakePlayer) + super.finishUsingItem(stack, level, ent); + + if (ent instanceof Player ply) { + Optional resolver = ply.getCapability(MatteryCapability.ANDROID).resolve(); + + if (resolver.isEmpty() || !(resolver.get() instanceof AndroidCapabilityPlayer)) + return super.finishUsingItem(stack, level, ply); + + if (this.pill_type == PillType.BECOME_ANDROID && !resolver.get().isAndroid()) { + stack.shrink(1); + + if (ply instanceof ServerPlayer) + ((AndroidCapabilityPlayer) resolver.get()).becomeAndroid(); + } else if (this.pill_type == PillType.BECOME_HUMANE && resolver.get().isAndroid()) { + stack.shrink(1); + + if (ply instanceof ServerPlayer) + ((AndroidCapabilityPlayer) resolver.get()).becomeHumane(); + } + + return stack; + } + + return super.finishUsingItem(stack, level, ent); + } + + @Override + public UseAnim getUseAnimation(ItemStack p_41452_) { + return UseAnim.EAT; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/network/AndroidCapabilityChangePacket.java b/src/main/java/ru/dbotthepony/mc/otm/network/AndroidCapabilityChangePacket.java index ac6703a7a..b8eb68439 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/AndroidCapabilityChangePacket.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/AndroidCapabilityChangePacket.java @@ -20,6 +20,7 @@ public class AndroidCapabilityChangePacket { ENERGY_CHANGED, MAX_ENERGY_CHANGED, BATTERY_STACK_CHANGED, + IS_ANDROID, } public static ChangeType[] CHANGE_MAP = new ChangeType[] { @@ -27,11 +28,13 @@ public class AndroidCapabilityChangePacket { ChangeType.ENERGY_CHANGED, ChangeType.MAX_ENERGY_CHANGED, ChangeType.BATTERY_STACK_CHANGED, + ChangeType.IS_ANDROID, }; public BigDecimal energy; public BigDecimal max_energy; public ItemStack battery; + public Boolean is_android; public boolean isEmpty() { return energy == null && max_energy == null && battery == null; @@ -46,6 +49,10 @@ public class AndroidCapabilityChangePacket { this.max_energy = energy; } + public void isAndroid(boolean is_android) { + this.is_android = is_android; + } + public void batteryStackChanged(ItemStack stack) { this.battery = stack; } @@ -67,6 +74,11 @@ public class AndroidCapabilityChangePacket { buffer.writeItem(battery); } + if (is_android != null) { + buffer.writeByte(ChangeType.IS_ANDROID.ordinal()); + buffer.writeByte(is_android ? 1 : 0); + } + buffer.writeByte(ChangeType.TERMINATION.ordinal()); } @@ -90,6 +102,7 @@ public class AndroidCapabilityChangePacket { case ENERGY_CHANGED -> packet.energy = NetworkHelper.readDecimal(buffer); case MAX_ENERGY_CHANGED -> packet.max_energy = NetworkHelper.readDecimal(buffer); case BATTERY_STACK_CHANGED -> packet.battery = buffer.readItem(); + case IS_ANDROID -> packet.is_android = buffer.readByte() > 0; } read = CHANGE_MAP[buffer.readByte()];