From 68930672a4158c091e893786b4102639a2157d92 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 19 Aug 2021 20:44:43 +0700 Subject: [PATCH] Android feature research test --- .../java/ru/dbotthepony/mc/otm/Registry.java | 3 +- .../android/AndroidAirBagsType.java | 15 ++++ .../capability/android/AndroidCapability.java | 2 +- .../android/AndroidFeatureResearchCost.java | 66 ++++++++++++++++ .../android/AndroidFeatureResearchNode.java | 75 +++++++++++++++++++ .../android/AndroidFeatureType.java | 21 ++++++ .../mc/otm/network/MatteryNetworking.java | 14 +++- .../android/AndroidResearchRequestPacket.java | 52 +++++++++++++ .../mc/otm/screen/AndroidStationScreen.java | 50 +++++++++++++ 9 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidAirBagsType.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchCost.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchNode.java create mode 100644 src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchRequestPacket.java diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index c78d8db04..7e5d91e2d 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -18,6 +18,7 @@ import net.minecraftforge.registries.RegistryBuilder; import ru.dbotthepony.mc.otm.block.*; import ru.dbotthepony.mc.otm.block.entity.*; import ru.dbotthepony.mc.otm.capability.android.AndroidAirBags; +import ru.dbotthepony.mc.otm.capability.android.AndroidAirBagsType; import ru.dbotthepony.mc.otm.capability.android.AndroidFeatureType; import ru.dbotthepony.mc.otm.item.ItemBattery; import ru.dbotthepony.mc.otm.item.ItemMatterCapacitor; @@ -265,7 +266,7 @@ public class Registry { } public static class AndroidFeatures { - public static final AndroidFeatureType AIR_BAGS = new AndroidFeatureType<>(AndroidAirBags::new); + public static final AndroidAirBagsType AIR_BAGS = new AndroidAirBagsType(); static { AIR_BAGS.setRegistryName(Names.AIR_BAGS); diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidAirBagsType.java b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidAirBagsType.java new file mode 100644 index 000000000..a7586b47b --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidAirBagsType.java @@ -0,0 +1,15 @@ +package ru.dbotthepony.mc.otm.capability.android; + +import javax.annotation.Nullable; + +public class AndroidAirBagsType extends AndroidFeatureType { + public AndroidAirBagsType() { + super(AndroidAirBags::new); + } + + @Nullable + @Override + public AndroidFeatureResearchNode getResearchNodeInner() { + return new AndroidFeatureResearchNode(this, new AndroidFeatureResearchCost(18)); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.java index 66b704cf3..100a19c87 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidCapability.java @@ -199,7 +199,7 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit if (_tag instanceof CompoundTag tag) { var get_feature = Registry.ANDROID_FEATURES().getValue(new ResourceLocation(tag.getString("id"))); - if (get_feature != null) { + if (get_feature != null && get_feature.isApplicable(this)) { var feature = get_feature.factory(this); if (feature instanceof INBTSerializable serializable) { diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchCost.java b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchCost.java new file mode 100644 index 000000000..8ccb1abc7 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchCost.java @@ -0,0 +1,66 @@ +package ru.dbotthepony.mc.otm.capability.android; + +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +public record AndroidFeatureResearchCost(int experience, ItemStack ...items) { + public boolean matches(Player ply) { + if (ply.experienceLevel < experience) + return false; + + for (var stack : items) { + boolean hit = false; + + if (stack.getTag() == null) { + for (var inv_stack : ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { + hit = true; + break; + } + } + } else { + for (var inv_stack : ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { + hit = true; + break; + } + } + } + + if (!hit) + return false; + } + + return true; + } + + public boolean research(Player ply) { + if (!matches(ply)) + return false; + + if (experience > 0) + ply.giveExperienceLevels(-experience); + + for (var stack : items) { + if (stack.getTag() == null) { + for (var inv_stack : ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount()) { + inv_stack.shrink(stack.getCount()); + break; + } + } + } else { + for (var inv_stack : ply.getInventory().items) { + if (inv_stack.is(stack.getItem()) && inv_stack.getCount() >= stack.getCount() && inv_stack.getTag() != null && inv_stack.getTag().equals(stack.getTag())) { + inv_stack.shrink(stack.getCount()); + break; + } + } + } + } + + ply.getInventory().setChanged(); + + return true; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchNode.java b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchNode.java new file mode 100644 index 000000000..5e02ccb29 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureResearchNode.java @@ -0,0 +1,75 @@ +package ru.dbotthepony.mc.otm.capability.android; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.world.entity.player.Player; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; +import ru.dbotthepony.mc.otm.network.MatteryNetworking; +import ru.dbotthepony.mc.otm.network.android.AndroidResearchRequestPacket; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class AndroidFeatureResearchNode { + public final AndroidFeatureType type; + public final AndroidFeatureResearchCost cost; + + public final Set> predecessors = new HashSet<>(); + + protected final Component name; + + public AndroidFeatureResearchNode(AndroidFeatureType type, AndroidFeatureResearchCost cost) { + this.type = type; + this.cost = cost; + name = new TranslatableComponent("android_feature." + type.getRegistryName().getNamespace() + "." + type.getRegistryName().getPath()); + } + + public AndroidFeatureResearchNode addPredecessor(AndroidFeatureType value) { + predecessors.add(value); + return this; + } + + public boolean canResearch(Player ply, AndroidCapabilityPlayer cap) { + for (var prec : predecessors) { + if (!cap.hasFeature(prec)) + return false; + } + + return cost.matches(ply); + } + + public void research(Player ply, AndroidCapabilityPlayer cap) { + if (cap.hasFeature(type)) + return; + + if (!canResearch(ply, cap)) + return; + + cost.research(ply); + cap.addFeature(type); + } + + public void researchClient() { + var ply = Minecraft.getInstance().player; + + ply.getCapability(MatteryCapability.ANDROID).ifPresent(cap -> { + if (cap.hasFeature(type)) + return; + + if (!canResearch(ply, (AndroidCapabilityPlayer) cap)) + return; + + MatteryNetworking.CHANNEL.sendToServer(new AndroidResearchRequestPacket(type)); + }); + } + + public Component getName() { + return name; + } + + public List getTooltip() { + return List.of(getName()); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureType.java b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureType.java index f93b70d25..b4d2454b6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureType.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/android/AndroidFeatureType.java @@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.capability.android; import net.minecraft.network.FriendlyByteBuf; import net.minecraftforge.registries.*; +import javax.annotation.Nullable; + public class AndroidFeatureType extends ForgeRegistryEntry> { public interface AndroidFeatureFactory { T factory(AndroidFeatureType entry, IAndroidCapability capability); @@ -21,4 +23,23 @@ public class AndroidFeatureType extends ForgeRegistryE public boolean isApplicable(IAndroidCapability capability) { return true; } + + public boolean isResearchable() { + return false; + } + + @Nullable + protected AndroidFeatureResearchNode getResearchNodeInner() { + return null; + } + + private AndroidFeatureResearchNode cache; + + @Nullable + public AndroidFeatureResearchNode getResearchNode() { + if (cache != null) + return cache; + + return cache = getResearchNodeInner(); + } } 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 057de9639..5e5c17899 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java +++ b/src/main/java/ru/dbotthepony/mc/otm/network/MatteryNetworking.java @@ -5,10 +5,7 @@ import net.minecraftforge.fmllegacy.network.NetworkDirection; import net.minecraftforge.fmllegacy.network.NetworkRegistry; import net.minecraftforge.fmllegacy.network.simple.SimpleChannel; import ru.dbotthepony.mc.otm.OverdriveThatMatters; -import ru.dbotthepony.mc.otm.network.android.AndroidBatteryPacket; -import ru.dbotthepony.mc.otm.network.android.AndroidEnergyPacket; -import ru.dbotthepony.mc.otm.network.android.AndroidFeaturePacket; -import ru.dbotthepony.mc.otm.network.android.AndroidStatusPacket; +import ru.dbotthepony.mc.otm.network.android.*; import java.util.Optional; @@ -105,5 +102,14 @@ public class MatteryNetworking { MatterRegistryPacket::play, 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) + ); } } 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 new file mode 100644 index 000000000..847cb8183 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/network/android/AndroidResearchRequestPacket.java @@ -0,0 +1,52 @@ +package ru.dbotthepony.mc.otm.network.android; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fmllegacy.network.NetworkEvent; +import ru.dbotthepony.mc.otm.Registry; +import ru.dbotthepony.mc.otm.capability.MatteryCapability; +import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer; +import ru.dbotthepony.mc.otm.capability.android.AndroidFeature; +import ru.dbotthepony.mc.otm.capability.android.AndroidFeatureType; +import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability; + +import java.util.Objects; +import java.util.function.Supplier; + +public record AndroidResearchRequestPacket(AndroidFeatureType feature) { + public AndroidResearchRequestPacket(AndroidFeatureType feature) { + this.feature = feature; + } + + public AndroidResearchRequestPacket(AndroidFeature feature) { + this(feature.type); + } + + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(Registry.ANDROID_FEATURES().getID(feature)); + } + + public void play(Supplier context) { + context.get().setPacketHandled(true); + context.get().enqueueWork(() -> context.get().getSender().getCapability(MatteryCapability.ANDROID).ifPresent(cap -> this.playServer((AndroidCapabilityPlayer) cap, (ServerPlayer) context.get().getSender()))); + } + + public void playServer(AndroidCapabilityPlayer cap, ServerPlayer ply) { + if (cap.hasFeature(feature)) + return; + + var node = feature.getResearchNode(); + + if (node == null) + return; + + node.research(ply, cap); + } + + public static AndroidResearchRequestPacket read(FriendlyByteBuf buffer) { + return new AndroidResearchRequestPacket(Objects.requireNonNull(Registry.ANDROID_FEATURES().getValue(buffer.readInt()))); + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java index 88ba6c857..8a2aef86f 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java @@ -1,11 +1,17 @@ package ru.dbotthepony.mc.otm.screen; +import com.mojang.blaze3d.vertex.PoseStack; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import ru.dbotthepony.mc.otm.Registry; +import ru.dbotthepony.mc.otm.capability.android.AndroidFeatureResearchNode; import ru.dbotthepony.mc.otm.menu.AndroidStationMenu; +import java.util.HashSet; +import java.util.Set; + public class AndroidStationScreen extends PoweredMachineScreen { private static final ResourceLocation CONTAINER_BACKGROUND = new ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/android_station.png"); @@ -14,7 +20,51 @@ public class AndroidStationScreen extends PoweredMachineScreen nodes = new HashSet<>(); + public AndroidStationScreen(AndroidStationMenu p_97741_, Inventory p_97742_, Component p_97743_) { super(p_97741_, p_97742_, p_97743_); + + for (var feature : Registry.ANDROID_FEATURES().getValues()) { + var node = feature.getResearchNode(); + + if (node != null) { + nodes.add(node); + } + } + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int p_97750_) { + int x = leftPos + 40; + int y = topPos + 10; + + for (var node : nodes) { + if (mouseX >= x && mouseX <= x + 16 && mouseY >= y && mouseY <= y + 16) { + node.researchClient(); + return true; + } + } + + return super.mouseClicked(mouseX, mouseY, p_97750_); + } + + @Override + protected void renderTooltip(PoseStack pose, int mouseX, int mouseY) { + super.renderTooltip(pose, mouseX, mouseY); + + int x = leftPos + 40; + int y = topPos + 10; + + for (var node : nodes) { + if (mouseX >= x && mouseX <= x + 16 && mouseY >= y && mouseY <= y + 16) { + renderComponentTooltip(pose, node.getTooltip(), mouseX, mouseY); + } + } + } + + @Override + protected void renderBg(PoseStack pose, float p_97788_, int mouseX, int mouseY) { + super.renderBg(pose, p_97788_, mouseX, mouseY); } }