Skip to content

Commit

Permalink
Merge pull request #17 from pupnewfster/feat_api
Browse files Browse the repository at this point in the history
Add an API to allow mods to adjust breast behavior when armor is worn
  • Loading branch information
WildfireRomeo committed Mar 17, 2022
2 parents eecced7 + 34a005e commit c7ccd58
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 74 deletions.
71 changes: 71 additions & 0 deletions src/main/java/com/wildfire/api/IGenderArmor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Wildfire's Female Gender Mod is a female gender mod created for Minecraft.
Copyright (C) 2022 WildfireRomeo
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.wildfire.api;

/**
* Expose this as a capability on your chestplates or items that go in the chest slot to configure how it interacts with breast rendering.
*/
public interface IGenderArmor {

/**
* Determines whether this {@link IGenderArmor} "covers" the breasts or if it has an open front ({@code false}) like the elytra.
*
* @return {@code true} if the breasts are covered.
*
* @implNote Defaults to {@code true}.
*/
default boolean coversBreasts() {
return true;
}

/**
* Determines if this {@link IGenderArmor} should always hide the wearer's breasts when worn even if they have {@code showBreastsInArmor} set to {@code true}. This is
* useful for armors that may have custom rendering that is not compatible with how the breasts render and would just lead to clipping.
*
* @return {@code true} to hide the breasts regardless of what {@code showBreastsInArmor} is set to.
*
* @implNote Defaults to {@code false}.
*/
default boolean alwaysHidesBreasts() {
return false;
}

/**
* The percent of physical resistance this {@link IGenderArmor} provides to the wearer's breasts when calculating the corresponding physics.
*
* @return Value between {@code 0} (no resistance, full physics) and {@code 1} (total resistance, no physics).
*
* @implNote Defaults to {@code 0} (no resistance, full physics).
*/
default float physicsResistance() {
return 0;
}

/**
* Value representing how "tight" this {@link IGenderArmor} is. Tightness "compresses" the breasts against the wearer causing the breasts to appear up to {@code 15%}
* smaller.
*
* @return Value between {@code 0} (no tightness, no size reduction) and {@code 1} (full tightness, {@code 15%} size reduction).
*
* @implNote Defaults to {@code 0} (no tightness, no size reduction).
*/
default float tightness() {
return 0;
}
}
7 changes: 5 additions & 2 deletions src/main/java/com/wildfire/main/WildfireEventHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.wildfire.main;

import com.wildfire.api.IGenderArmor;
import com.wildfire.gui.screen.WildfirePlayerListScreen;
import com.wildfire.main.networking.PacketSendGenderInfo;
import com.wildfire.render.GenderLayer;
Expand All @@ -30,6 +31,7 @@
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ClientRegistry;
Expand Down Expand Up @@ -108,8 +110,9 @@ public void onPlayerTick(PlayerTickEvent evt) {
if(evt.phase == TickEvent.Phase.END && evt.side.isClient()) {
GenderPlayer aPlr = WildfireGender.getPlayerById(evt.player.getUUID());
if(aPlr == null) return;
aPlr.getLeftBreastPhysics().update(evt.player);
aPlr.getRightBreastPhysics().update(evt.player);
IGenderArmor armor = WildfireHelper.getArmorConfig(evt.player.getItemBySlot(EquipmentSlot.CHEST));
aPlr.getLeftBreastPhysics().update(evt.player, armor);
aPlr.getRightBreastPhysics().update(evt.player, armor);
}
}
@SubscribeEvent
Expand Down
61 changes: 49 additions & 12 deletions src/main/java/com/wildfire/main/WildfireHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,61 @@

package com.wildfire.main;

import com.wildfire.api.IGenderArmor;
import com.wildfire.render.armor.SimpleGenderArmor;
import com.wildfire.render.armor.EmptyGenderArmor;
import java.util.concurrent.ThreadLocalRandom;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.ArmorMaterial;
import net.minecraft.world.item.ArmorMaterials;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;

public class WildfireHelper {

public static final String SYNC_URL = "https://wildfiremod.tk";
public static final Capability<IGenderArmor> GENDER_ARMOR_CAPABILITY = CapabilityManager.get(new CapabilityToken<>() {});

public static class Obfuscation {

//NetworkPlayerInfo.java
public static final String NETWORK_PLAYER_INFO = "field_175157_a";
public static final String PLAYER_TEXTURES = "field_187107_a";
public static final String LAYER_RENDERERS = "field_177097_h";
}

public static int randInt(int min, int max) {
return ThreadLocalRandom.current().nextInt(min, max + 1);
}
public static float randFloat(float min, float max) {
return (float) ThreadLocalRandom.current().nextDouble(min, (double) max + 1);
}

public static IGenderArmor getArmorConfig(ItemStack stack) {
if (stack.isEmpty()) {
return EmptyGenderArmor.INSTANCE;
}
return stack.getCapability(WildfireHelper.GENDER_ARMOR_CAPABILITY).orElseGet(() -> {
//While these defaults could be attached to the item stack via the AttachCapabilitiesEvent there is not
// really a great reason to do so as we would then need to ensure we handle all the lazy optionals properly,
// so we just include them as part of this fallback
if (stack.getItem() instanceof ArmorItem armorItem && armorItem.getSlot() == EquipmentSlot.CHEST) {
//Start by checking if it is a vanilla chestplate as we have custom configurations for those we check against
// the armor material instead of the item instance in case any mods define custom armor items using vanilla
// materials as then we can make a better guess at what we want the default implementation to be
ArmorMaterial material = armorItem.getMaterial();
if (material == ArmorMaterials.LEATHER) {
return SimpleGenderArmor.LEATHER;
} else if (material == ArmorMaterials.CHAIN) {
return SimpleGenderArmor.CHAIN_MAIL;
} else if (material == ArmorMaterials.GOLD) {
return SimpleGenderArmor.GOLD;
} else if (material == ArmorMaterials.IRON) {
return SimpleGenderArmor.IRON;
} else if (material == ArmorMaterials.DIAMOND) {
return SimpleGenderArmor.DIAMOND;
} else if (material == ArmorMaterials.NETHERITE) {
return SimpleGenderArmor.NETHERITE;
}
//Otherwise just fallback to our default armor implementation
return SimpleGenderArmor.FALLBACK;
}
//If it is not an armor item default as if "nothing is being worn that covers the breast area"
// this might not be fully accurate and may need some tweaks but in general is likely relatively
// close to the truth of if it should render or not. This covers cases such as the elytra and
// other wearables
return EmptyGenderArmor.INSTANCE;
});
}
}
19 changes: 13 additions & 6 deletions src/main/java/com/wildfire/physics/BreastPhysics.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package com.wildfire.physics;

import com.wildfire.api.IGenderArmor;
import com.wildfire.main.GenderPlayer;
import com.wildfire.main.WildfireHelper;
import net.minecraft.util.Mth;
Expand Down Expand Up @@ -49,23 +50,26 @@ public BreastPhysics(GenderPlayer genderPlayer) {

private int randomB = 1;
private boolean alreadyFalling = false;
public void update(Player plr) {
public void update(Player plr, IGenderArmor armor) {
this.wfg_preBounce = this.wfg_femaleBreast;
this.wfg_preBounceX = this.wfg_femaleBreastX;
this.wfg_preBounceRotation = this.wfg_bounceRotation;
this.preBreastSize = this.breastSize;

float breastWeight = genderPlayer.getBustSize() * 1.25f;

if(this.prePos == null) {
this.prePos = plr.position();
return;
}

float breastWeight = genderPlayer.getBustSize() * 1.25f;
float targetBreastSize = genderPlayer.getBustSize();

if(!genderPlayer.gender.canHaveBreasts()) {
if (!genderPlayer.gender.canHaveBreasts()) {
targetBreastSize = 0;
} else {
float tightness = Mth.clamp(armor.tightness(), 0, 1);
//Scale breast size by how tight the armor is, clamping at a max adjustment of shrinking by 0.15
targetBreastSize *= 1 - 0.15F * tightness;
}

if(breastSize < targetBreastSize) {
Expand All @@ -79,13 +83,16 @@ public void update(Player plr) {
this.prePos = plr.position();
//System.out.println(motion);

float bounceIntensity = (genderPlayer.getBustSize() * 3f) * genderPlayer.getBounceMultiplier();
float bounceIntensity = (targetBreastSize * 3f) * genderPlayer.getBounceMultiplier();
float resistance = Mth.clamp(armor.physicsResistance(), 0, 1);
//Adjust bounce intensity by physics resistance of the worn armor
bounceIntensity *= 1 - resistance;

if(!genderPlayer.getBreasts().isUniboob) {
bounceIntensity = bounceIntensity * WildfireHelper.randFloat(0.5f, 1.5f);
}
if(plr.fallDistance > 0 && !alreadyFalling) {
randomB = WildfireHelper.randInt(0, 1) == 1 ? -1 : 1;
randomB = plr.level.random.nextBoolean() ? -1 : 1;
alreadyFalling = true;
}
if(plr.fallDistance == 0) alreadyFalling = false;
Expand Down

0 comments on commit c7ccd58

Please sign in to comment.