Android features registry and impl, better android networking

This commit is contained in:
DBotThePony 2021-08-19 17:02:18 +07:00
parent 4f00113836
commit 45932e5e4b
Signed by: DBot
GPG Key ID: DCC23B5715498507
22 changed files with 587 additions and 270 deletions

View File

@ -53,11 +53,14 @@ public class OverdriveThatMatters {
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Blocks.class);
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.BlockEntities.class);
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Menus.class);
FMLJavaModLoadingContext.get().getModEventBus().register(Registry.AndroidFeatures.class);
FMLJavaModLoadingContext.get().getModEventBus().addListener(AndroidCapability::registerEffects);
// LOGGER.info("Registered event handlers");
Registry.createRegistry();
CREATIVE_TAB = new CreativeModeTab("otm") {
@Override
public ItemStack makeIcon() {

View File

@ -5,15 +5,19 @@ 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;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.IForgeRegistry;
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.AndroidFeatureType;
import ru.dbotthepony.mc.otm.item.ItemBattery;
import ru.dbotthepony.mc.otm.item.ItemMatterCapacitor;
import ru.dbotthepony.mc.otm.item.ItemPatternStorage;
@ -32,7 +36,28 @@ public class Registry {
DAMAGE_BECOME_HUMANE.bypassArmor().bypassInvul().bypassMagic();
}
private static ForgeRegistry<AndroidFeatureType<?>> ANDROID_FEATURES;
public static ForgeRegistry<AndroidFeatureType<?>> ANDROID_FEATURES() {
return ANDROID_FEATURES;
}
public static void createRegistry() {
if (ANDROID_FEATURES != null)
throw new IllegalStateException("Already has registry");
var builder = new RegistryBuilder<AndroidFeatureType<?>>();
builder.setName(new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_features"));
// make it shut up
builder.setType(c(AndroidFeatureType.class));
ANDROID_FEATURES = (ForgeRegistry<AndroidFeatureType<?>>) builder.create();
}
private static <T> Class<T> c(Class<?> cls) { return (Class<T>) cls; }
public static class Names {
// blocks
public static final ResourceLocation ANDROID_STATION = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_station");
public static final ResourceLocation BATTERY_BANK = new ResourceLocation(OverdriveThatMatters.MOD_ID, "battery_bank");
public static final ResourceLocation MATTER_DECOMPOSER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_decomposer");
@ -43,8 +68,10 @@ public class Registry {
public static final ResourceLocation MATTER_PANEL = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_panel");
public static final ResourceLocation MATTER_REPLICATOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_replicator");
// capabilities
public static final ResourceLocation ANDROID_CAPABILITY = new ResourceLocation(OverdriveThatMatters.MOD_ID, "android_capability");
// items
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");
@ -60,6 +87,9 @@ public class Registry {
public static final ResourceLocation PATTERN_DRIVE_NORMAL = new ResourceLocation(OverdriveThatMatters.MOD_ID, "pattern_drive_normal");
public static final ResourceLocation PATTERN_DRIVE_CREATIVE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "pattern_drive_creative");
// android features
public static final ResourceLocation AIR_BAGS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "air_bags");
}
public static class Blocks {
@ -225,6 +255,19 @@ public class Registry {
}
}
public static class AndroidFeatures {
public static final AndroidFeatureType<AndroidAirBags> AIR_BAGS = new AndroidFeatureType<>(AndroidAirBags::new);
static {
AIR_BAGS.setRegistryName(Names.AIR_BAGS);
}
@SubscribeEvent
public static void register(final RegistryEvent.Register<AndroidFeatureType<?>> event) {
event.getRegistry().register(AIR_BAGS);
}
}
public static class Menus {
public static final MenuType<AndroidStationMenu> ANDROID_STATION = new MenuType<>(AndroidStationMenu::new);
public static final MenuType<BatteryBankMenu> BATTERY_BANK = new MenuType<>(BatteryBankMenu::new);

View File

@ -13,12 +13,11 @@ 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.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.shapes.BlockShapes;

View File

@ -13,7 +13,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage;
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu;

View File

@ -1,30 +0,0 @@
package ru.dbotthepony.mc.otm.capability;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.INBTSerializable;
import ru.dbotthepony.mc.otm.network.AndroidCapabilityChangePacket;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
void tick();
void tickClient();
LivingEntity getEntity();
default boolean isAndroid() {
return true;
}
@Nonnull
ItemStack getBatteryItemStack();
void setBatteryItemStack(@Nonnull ItemStack stack);
// networking
void invalidateNetworkState(); // tell capability that player forgot everything
AndroidCapabilityChangePacket writeChanges(); // write changes to network
void readChanges(AndroidCapabilityChangePacket packet); // read changes from network
}

View File

@ -4,6 +4,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.energy.IEnergyStorage;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import java.math.BigDecimal;
import java.math.MathContext;

View File

@ -0,0 +1,7 @@
package ru.dbotthepony.mc.otm.capability.android;
public class AndroidAirBags extends AndroidFeature {
public AndroidAirBags(AndroidFeatureType<?> type, IAndroidCapability capability) {
super(type, capability);
}
}

View File

@ -1,13 +1,14 @@
package ru.dbotthepony.mc.otm.capability.android;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.food.FoodData;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
@ -18,19 +19,21 @@ import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fmllegacy.network.PacketDistributor;
import org.apache.logging.log4j.core.jmx.Server;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.AndroidCapabilityChangePacket;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.*;
public class AndroidCapability implements ICapabilityProvider, IAndroidCapability, INBTSerializable<CompoundTag> {
protected final LivingEntity ent;
@ -42,6 +45,64 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
private BigDecimal network_energy_max = new BigDecimal(-1);
private ItemStack network_battery = ItemStack.EMPTY;
protected final Map<AndroidFeatureType<?>, AndroidFeature> features = new HashMap<>();
protected final ArrayList<Object> network_queue = new ArrayList<>();
protected boolean network_first = false;
protected boolean addFeature(@Nonnull AndroidFeature feature) {
if (features.containsKey(feature.type))
return false;
features.put(feature.type, feature);
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(true, feature));
}
return true;
}
@Override
public boolean addFeature(@Nonnull AndroidFeatureType<?> feature) {
if (features.containsKey(feature))
return false;
var factory = feature.factory(this);
features.put(feature, factory);
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(true, factory));
}
return true;
}
@Override
public boolean removeFeature(@Nonnull AndroidFeatureType<?> feature) {
var removed = features.remove(feature);
if (removed != null) {
if (ent instanceof ServerPlayer ply) {
sendNetwork(new AndroidFeaturePacket(false, removed));
}
return true;
}
return false;
}
@Override
public boolean hasFeature(@Nullable AndroidFeatureType<?> feature) {
return features.containsKey(feature);
}
@Nullable
public AndroidFeature getFeature(AndroidFeatureType<?> feature) {
return features.get(feature);
}
public static final Set<MobEffect> UNAFFECTED_EFFECTS = new HashSet<>();
public static void registerEffects(final FMLCommonSetupEvent event) {
@ -64,6 +125,23 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
network_energy = new BigDecimal(-1);
network_energy_max = new BigDecimal(-1);
network_battery = ItemStack.EMPTY;
if (ent instanceof ServerPlayer ply) {
for (var feature : features.values()) {
sendNetwork(new AndroidFeaturePacket(true, feature));
feature.invalidateNetwork();
}
}
}
@Override
public void setEnergy(BigDecimal value) {
energy_stored = value;
}
@Override
public void setMaxEnergy(BigDecimal value) {
energy_stored_max = value;
}
public AndroidCapability(LivingEntity ent) {
@ -83,6 +161,22 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
tag.putString("energy_stored", energy_stored.toString());
tag.putString("energy_stored_max", energy_stored_max.toString());
tag.put("battery", battery.serializeNBT());
var features_nbt = new ListTag();
for (var feature : features.values()) {
var compound = new CompoundTag();
compound.putString("id", Objects.requireNonNull(feature.type.getRegistryName()).toString());
if (feature instanceof INBTSerializable serializable) {
compound.put("data", serializable.serializeNBT());
}
features_nbt.add(compound);
}
tag.put("features", features_nbt);
return tag;
}
@ -96,6 +190,27 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
if (compound.contains("battery"))
battery = ItemStack.of(compound.getCompound("battery"));
features.clear();
var features_nbt = compound.getList("features", Tag.TAG_COMPOUND);
for (var _tag : features_nbt) {
if (_tag instanceof CompoundTag tag) {
var get_feature = Registry.ANDROID_FEATURES().getValue(new ResourceLocation(tag.getString("id")));
if (get_feature != null) {
var feature = get_feature.factory(this);
if (feature instanceof INBTSerializable serializable) {
serializable.deserializeNBT(tag.getCompound("data"));
}
addFeature(feature);
feature.attachFinish();
}
}
}
}
public void dropBattery() {
@ -106,49 +221,43 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
battery = ItemStack.EMPTY;
}
protected void sendNetwork(Object packet) {
if (ent instanceof ServerPlayer ply) {
if (network_first) {
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> ply), packet);
} else {
network_queue.add(packet);
}
}
}
protected void tickNetwork() {
network_first = true;
}
if (ent instanceof ServerPlayer ply) {
if (!energy_stored.equals(network_energy)) {
network_energy = energy_stored;
sendNetwork(new AndroidEnergyPacket(false, energy_stored));
}
@Override
@Nullable
public AndroidCapabilityChangePacket writeChanges() {
if (!isAndroid())
return null;
if (!energy_stored_max.equals(network_energy_max)) {
network_energy_max = energy_stored_max;
sendNetwork(new AndroidEnergyPacket(true, energy_stored_max));
}
AndroidCapabilityChangePacket packet = null;
if (!network_battery.equals(battery, false)) {
network_battery = battery.copy();
sendNetwork(new AndroidBatteryPacket(battery));
}
if (!energy_stored.equals(network_energy)) {
network_energy = energy_stored;
packet = new AndroidCapabilityChangePacket();
packet.energyChanged(network_energy);
if (network_queue.size() != 0) {
for (var packet : network_queue) {
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> ply), packet);
}
network_queue.clear();
}
}
if (!energy_stored_max.equals(network_energy_max)) {
network_energy_max = energy_stored_max;
if (packet == null) packet = new AndroidCapabilityChangePacket();
packet.maxEnergyChanged(energy_stored_max);
}
if (!network_battery.equals(battery, false)) {
network_battery = battery.copy();
if (packet == null) packet = new AndroidCapabilityChangePacket();
packet.batteryStackChanged(battery);
}
return packet;
}
@Override
public void readChanges(AndroidCapabilityChangePacket packet) {
if (packet.energy != null)
energy_stored = packet.energy;
if (packet.max_energy != null)
energy_stored_max = packet.max_energy;
if (packet.battery != null)
battery = packet.battery;
}
protected void tickInnerClient() {
@ -157,19 +266,29 @@ public class AndroidCapability implements ICapabilityProvider, IAndroidCapabilit
@Override
public void tickClient() {
if (isAndroid())
if (isAndroid()) {
tickInnerClient();
for (var feature : features.values()) {
feature.tickClient();
}
}
}
@Override
public void tick() {
if (isAndroid())
tickInner();
if (isAndroid()) {
tickServer();
for (var feature : features.values()) {
feature.tickServer();
}
}
tickNetwork();
}
protected void tickInner() {
protected void tickServer() {
if (ent.getAirSupply() < ent.getMaxAirSupply())
ent.setAirSupply(ent.getMaxAirSupply());

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.mc.otm.capability.android;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.client.event.InputUpdateEvent;
@ -9,19 +8,15 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fmllegacy.network.PacketDistributor;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.AndroidCapabilityChangePacket;
import ru.dbotthepony.mc.otm.network.MatteryNetworking;
import ru.dbotthepony.mc.otm.network.android.AndroidStatusPacket;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
public class AndroidCapabilityPlayer extends AndroidCapability {
private boolean is_android = false;
public boolean is_android = false;
private boolean network_is_android = false;
@Override
@ -30,29 +25,6 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
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;
@ -70,6 +42,21 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
ply.die(Registry.DAMAGE_BECOME_ANDROID);
}
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);
}
@Override
public void deserializeNBT(CompoundTag compound) {
super.deserializeNBT(compound);
@ -86,21 +73,6 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
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<Entity> event) {
if (event.getObject() instanceof Player ply) {
@ -134,7 +106,7 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
});
}
private int last_jump_ticks = 10;
private int last_jump_ticks = 14;
@SubscribeEvent
public static void inputEvent(InputUpdateEvent event) {
@ -145,12 +117,15 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
if (!(_cap instanceof AndroidCapabilityPlayer cap))
return;
if (cap.hasFeature(Registry.AndroidFeatures.AIR_BAGS))
return;
if (ply.getAbilities().mayfly) {
cap.last_jump_ticks = 10;
cap.last_jump_ticks = 14;
} else {
if (ply.isInWater()) {
if (ply.isOnGround()) {
cap.last_jump_ticks = 10;
cap.last_jump_ticks = 14;
}
if (ply.isSwimming()) {
@ -177,22 +152,24 @@ public class AndroidCapabilityPlayer extends AndroidCapability {
@Override
protected void tickNetwork() {
AndroidCapabilityChangePacket packet = writeChanges();
super.tickNetwork();
if (packet != null)
MatteryNetworking.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) ent), packet);
if (is_android != network_is_android) {
network_is_android = is_android;
sendNetwork(new AndroidStatusPacket(is_android));
}
}
public static final BigDecimal ENERGY_FOR_HUNGER_POINT = new BigDecimal(1000);
@Override
public void tickInner() {
super.tickInner();
public void tickServer() {
super.tickServer();
// TODO: Maybe passive drain?
// extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false);
if (ply.isSwimming()) {
if (ply.isSwimming() && !hasFeature(Registry.AndroidFeatures.AIR_BAGS)) {
ply.setSwimming(false);
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.mc.otm.capability.android;
public class AndroidFeature {
public final AndroidFeatureType<? extends AndroidFeature> type;
public final IAndroidCapability capability;
public AndroidFeature(AndroidFeatureType<?> type, IAndroidCapability capability) {
this.type = type;
this.capability = capability;
}
@Override
public boolean equals(Object obj) {
if (super.equals(obj))
return true;
if (obj instanceof AndroidFeature feature)
return feature.type.equals(type);
return false;
}
public void invalidateNetwork() {
// when player forgets everything
}
public void attachFinish() {
// override
}
@Override
public int hashCode() {
return type.hashCode();
}
public void tickClient() {
}
public void tickServer() {
}
}

View File

@ -0,0 +1,24 @@
package ru.dbotthepony.mc.otm.capability.android;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.registries.*;
public class AndroidFeatureType<T extends AndroidFeature> extends ForgeRegistryEntry<AndroidFeatureType<?>> {
public interface AndroidFeatureFactory<T extends AndroidFeature> {
T factory(AndroidFeatureType<T> entry, IAndroidCapability capability);
}
protected final AndroidFeatureFactory<T> factory;
public AndroidFeatureType(AndroidFeatureFactory<T> factory) {
this.factory = factory;
}
public T factory(IAndroidCapability capability) {
return factory.factory(this, capability);
}
public boolean isApplicable(IAndroidCapability capability) {
return true;
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.mc.otm.capability.android;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.INBTSerializable;
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.util.Optional;
public interface IAndroidCapability extends IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
void tick();
void tickClient();
LivingEntity getEntity();
boolean addFeature(@Nonnull AndroidFeatureType<?> feature);
boolean removeFeature(@Nonnull AndroidFeatureType<?> feature);
boolean hasFeature(@Nullable AndroidFeatureType<?> feature);
AndroidFeature getFeature(AndroidFeatureType<?> feature);
@Nonnull
default Optional<AndroidFeature> getFeatureO(AndroidFeatureType<?> feature) {
var get = getFeature(feature);
return get != null ? Optional.of(get) : Optional.empty();
}
default boolean isAndroid() {
return true;
}
@Nonnull
ItemStack getBatteryItemStack();
void setBatteryItemStack(@Nonnull ItemStack stack);
void invalidateNetworkState(); // tell capability that player forgot everything, and everything needs to be re-networked
void setEnergy(BigDecimal value);
void setMaxEnergy(BigDecimal value);
}

View File

@ -3,9 +3,7 @@ package ru.dbotthepony.mc.otm.client;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.DeathScreen;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.effect.MobEffects;
@ -16,7 +14,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.gui.ForgeIngameGui;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import java.math.BigDecimal;

View File

@ -13,7 +13,7 @@ import net.minecraft.world.level.Level;
import net.minecraftforge.common.util.FakePlayer;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
import ru.dbotthepony.mc.otm.capability.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import javax.annotation.Nullable;

View File

@ -7,7 +7,7 @@ import net.minecraft.world.item.ItemStack;
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.android.IAndroidCapability;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.menu.slot.BatterySlot;

View File

@ -1,105 +0,0 @@
package ru.dbotthepony.mc.otm.network;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fmllegacy.network.NetworkEvent;
import net.minecraftforge.fmllegacy.network.PacketDistributor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.function.Supplier;
public class AndroidCapabilityChangePacket {
public enum ChangeType {
TERMINATION,
ENERGY_CHANGED,
MAX_ENERGY_CHANGED,
BATTERY_STACK_CHANGED,
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;
}
// build state
public void energyChanged(BigDecimal energy) {
this.energy = energy;
}
public void maxEnergyChanged(BigDecimal energy) {
this.max_energy = energy;
}
public void isAndroid(boolean is_android) {
this.is_android = is_android;
}
public void batteryStackChanged(ItemStack stack) {
this.battery = stack;
}
// encode state
public void encodeNetwork(FriendlyByteBuf buffer) {
if (energy != null) {
buffer.writeByte(ChangeType.ENERGY_CHANGED.ordinal());
NetworkHelper.writeDecimal(buffer, energy);
}
if (max_energy != null) {
buffer.writeByte(ChangeType.MAX_ENERGY_CHANGED.ordinal());
NetworkHelper.writeDecimal(buffer, max_energy);
}
if (battery != null) {
buffer.writeByte(ChangeType.BATTERY_STACK_CHANGED.ordinal());
buffer.writeItem(battery);
}
if (is_android != null) {
buffer.writeByte(ChangeType.IS_ANDROID.ordinal());
buffer.writeByte(is_android ? 1 : 0);
}
buffer.writeByte(ChangeType.TERMINATION.ordinal());
}
// handle state
public void handleMessage(Supplier<NetworkEvent.Context> context) {
context.get().setPacketHandled(true);
context.get().enqueueWork(() -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientAndroidCapabilityChangePacketHandler.handlePacket(this, context));
});
}
// decode state
public static AndroidCapabilityChangePacket decodeNetwork(FriendlyByteBuf buffer) {
AndroidCapabilityChangePacket packet = new AndroidCapabilityChangePacket();
ChangeType read = ChangeType.values()[buffer.readByte()];
while (read != ChangeType.TERMINATION) {
switch (read) {
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 = ChangeType.values()[buffer.readByte()];
}
return packet;
}
}

View File

@ -1,18 +0,0 @@
package ru.dbotthepony.mc.otm.network;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import java.util.function.Supplier;
public class ClientAndroidCapabilityChangePacketHandler {
public static void handlePacket(AndroidCapabilityChangePacket packet, Supplier<NetworkEvent.Context> ctx) {
if (Minecraft.getInstance().player != null) {
Minecraft.getInstance().player.getCapability(MatteryCapability.ANDROID)
.orElseThrow(() -> new IllegalStateException("Local player has no android capability yet"))
.readChanges(packet);
}
}
}

View File

@ -5,11 +5,15 @@ 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 java.util.Optional;
public class MatteryNetworking {
private static final String PROTOCOL_VERSION = "1";
private static final String PROTOCOL_VERSION = "2";
private static int next_network_id = 0;
@ -23,10 +27,37 @@ public class MatteryNetworking {
public static void register() {
CHANNEL.registerMessage(
next_network_id++,
AndroidCapabilityChangePacket.class,
AndroidCapabilityChangePacket::encodeNetwork,
AndroidCapabilityChangePacket::decodeNetwork,
AndroidCapabilityChangePacket::handleMessage,
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)
);

View File

@ -0,0 +1,38 @@
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.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.NetworkHelper;
import java.math.BigDecimal;
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

@ -0,0 +1,45 @@
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.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.NetworkHelper;
import java.math.BigDecimal;
import java.util.function.Supplier;
public record AndroidEnergyPacket(boolean is_maximal, BigDecimal energy) {
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(is_maximal);
NetworkHelper.writeDecimal(buffer, energy);
}
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(), NetworkHelper.readDecimal(buffer));
}
}

View File

@ -0,0 +1,58 @@
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.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 java.util.Objects;
import java.util.function.Supplier;
public record AndroidFeaturePacket(boolean is_added, AndroidFeatureType<?> feature) {
public AndroidFeaturePacket(boolean is_added, AndroidFeatureType<?> feature) {
this.is_added = is_added;
this.feature = feature;
}
public AndroidFeaturePacket(boolean is_added, AndroidFeature feature) {
this(is_added, feature.type);
}
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(is_added);
buffer.writeInt(Registry.ANDROID_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(Registry.ANDROID_FEATURES().getValue(buffer.readInt()));
return new AndroidFeaturePacket(is_added, feature);
}
}

View File

@ -0,0 +1,41 @@
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.fmllegacy.network.NetworkEvent;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
import java.util.function.Supplier;
public record AndroidStatusPacket(boolean status) {
public void write(FriendlyByteBuf buffer) {
buffer.writeBoolean(status);
}
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.is_android = status;
}
});
}
}
public static AndroidStatusPacket read(FriendlyByteBuf buffer) {
return new AndroidStatusPacket(buffer.readBoolean());
}
}