Skip to content

Commit

Permalink
Re-implement walking speed bonus (#2251)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tictim authored Dec 7, 2023
1 parent cbadcbb commit 09a4e64
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 103 deletions.
8 changes: 8 additions & 0 deletions src/main/java/gregtech/api/block/IWalkingSpeedBonus.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;

import org.jetbrains.annotations.ApiStatus;

/**
* @deprecated use {@link gregtech.api.util.BlockUtility#setWalkingSpeedBonus(IBlockState, double)}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
@ApiStatus.ScheduledForRemoval(inVersion = "2.9")
public interface IWalkingSpeedBonus {

default double getWalkingSpeedBonus() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/gregtech/api/block/VariantActiveBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public int getMetaFromState(IBlockState state) {
@NotNull
@Override
protected BlockStateContainer createBlockState() {
Class<T> enumClass = getActualTypeParameter(getClass(), VariantActiveBlock.class, 0);
Class<T> enumClass = getActualTypeParameter(getClass(), VariantActiveBlock.class);
this.VARIANT = PropertyEnum.create("variant", enumClass);
this.VALUES = enumClass.getEnumConstants();
return new ExtendedBlockState(this, new IProperty[] { VARIANT, ACTIVE_DEPRECATED },
Expand Down
30 changes: 6 additions & 24 deletions src/main/java/gregtech/api/block/VariantBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@
import net.minecraft.client.resources.I18n;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
Expand All @@ -28,11 +26,13 @@
import java.util.Collections;
import java.util.List;

@SuppressWarnings("deprecation")
public class VariantBlock<T extends Enum<T> & IStringSerializable> extends Block implements IWalkingSpeedBonus {

protected PropertyEnum<T> VARIANT;
protected T[] VALUES;

@SuppressWarnings("DataFlowIssue")
public VariantBlock(Material materialIn) {
super(materialIn);
if (VALUES.length > 0 && VALUES[0] instanceof IStateHarvestLevel) {
Expand Down Expand Up @@ -77,15 +77,15 @@ public ItemStack getItemVariant(T variant, int amount) {
@NotNull
@Override
protected BlockStateContainer createBlockState() {
Class<T> enumClass = getActualTypeParameter(getClass(), VariantBlock.class, 0);
Class<T> enumClass = getActualTypeParameter(getClass(), VariantBlock.class);
this.VARIANT = PropertyEnum.create("variant", enumClass);
this.VALUES = enumClass.getEnumConstants();
return new BlockStateContainer(this, VARIANT);
}

@Override
@SideOnly(Side.CLIENT)
public void addInformation(@NotNull ItemStack stack, @Nullable World player, List<String> tooltip,
public void addInformation(@NotNull ItemStack stack, @Nullable World player, @NotNull List<String> tooltip,
@NotNull ITooltipFlag advanced) {
// tier less tooltip like: tile.turbine_casing.tooltip
String unlocalizedVariantTooltip = getTranslationKey() + ".tooltip";
Expand Down Expand Up @@ -114,27 +114,9 @@ public int getMetaFromState(IBlockState state) {
return state.getValue(VARIANT).ordinal();
}

@Override
public void onEntityWalk(@NotNull World worldIn, @NotNull BlockPos pos, @NotNull Entity entityIn) {
// Short circuit if there is no bonus speed
if (getWalkingSpeedBonus() == 1.0D) {
return;
}

IBlockState below = entityIn.getEntityWorld()
.getBlockState(new BlockPos(entityIn.posX, entityIn.posY - (1 / 16D), entityIn.posZ));
if (checkApplicableBlocks(below)) {
if (bonusSpeedCondition(entityIn)) {
entityIn.motionX *= getWalkingSpeedBonus();
entityIn.motionZ *= getWalkingSpeedBonus();
}
}
}

// magic is here
@SuppressWarnings("unchecked")
protected static <T, R> Class<T> getActualTypeParameter(Class<? extends R> thisClass, Class<R> declaringClass,
int index) {
protected static <T, R> Class<T> getActualTypeParameter(Class<? extends R> thisClass, Class<R> declaringClass) {
Type type = thisClass.getGenericSuperclass();

while (!(type instanceof ParameterizedType) || ((ParameterizedType) type).getRawType() != declaringClass) {
Expand All @@ -144,6 +126,6 @@ protected static <T, R> Class<T> getActualTypeParameter(Class<? extends R> thisC
type = ((Class<?>) type).getGenericSuperclass();
}
}
return (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[index];
return (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
}
}
49 changes: 49 additions & 0 deletions src/main/java/gregtech/api/util/BlockUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,45 @@

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;

import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import it.unimi.dsi.fastutil.objects.Object2DoubleMaps;
import it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap;
import org.jetbrains.annotations.NotNull;

import java.util.Objects;
import java.util.UUID;

public class BlockUtility {

private static final BlockWrapper WRAPPER = new BlockWrapper();

private static final Object2DoubleMap<IBlockState> walkingSpeedBonusInternal = new Object2DoubleOpenHashMap<>();
/**
* View-only collection of block states that give speed bonus when walking over it. The bonus value is a percentage
* value that gets added to the player speed; for example, a bonus value of {@link 0.25} will add 25% of extra speed
* to the player.
*/
public static final Object2DoubleMap<IBlockState> WALKING_SPEED_BONUS = Object2DoubleMaps.unmodifiable(
walkingSpeedBonusInternal);

/**
* UUID of the walking speed bonus attribute applied to players.
*/
public static final UUID WALKING_SPEED_UUID = UUID.fromString("415ac431-8339-4150-965c-e673a8a328be");

/**
* Walking speed bonus applied to asphalt and concrete blocks.
*/
public static final double ASPHALT_WALKING_SPEED_BONUS = 0.6;
/**
* Walking speed bonus applied to studs.
*/
public static final double STUDS_WALKING_SPEED_BONUS = 0.25;

private static class BlockWrapper extends Block {

public BlockWrapper() {
Expand All @@ -31,4 +61,23 @@ public static void startCaptureDrops() {
public static NonNullList<ItemStack> stopCaptureDrops() {
return WRAPPER.captureDrops(false);
}

/**
* Set walking speed bonus for the block state. The bonus value is a percentage value that gets added to the player
* speed; for example, a bonus value of {@link 0.25} will add 25% of extra speed to the player.
*
* @param state block state
* @param amount amount of walking speed bonus
*/
public static void setWalkingSpeedBonus(@NotNull IBlockState state, double amount) {
Objects.requireNonNull(state, "state == null");
if (!Double.isFinite(amount)) {
throw new IllegalArgumentException("Haha funny i put NaN and Infinity in your API method haha no");
}
if (amount == 0) {
walkingSpeedBonusInternal.remove(state);
} else {
walkingSpeedBonusInternal.put(state, amount);
}
}
}
98 changes: 95 additions & 3 deletions src/main/java/gregtech/common/EventHandlers.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package gregtech.common;

import gregtech.api.GTValues;
import gregtech.api.block.IWalkingSpeedBonus;
import gregtech.api.items.armor.ArmorMetaItem;
import gregtech.api.items.toolitem.ToolClasses;
import gregtech.api.items.toolitem.ToolHelper;
import gregtech.api.metatileentity.interfaces.IGregTechTileEntity;
import gregtech.api.pipenet.longdist.LongDistanceNetwork;
import gregtech.api.pipenet.tile.IPipeTile;
import gregtech.api.unification.material.Materials;
import gregtech.api.util.BlockUtility;
import gregtech.api.util.CapesRegistry;
import gregtech.api.util.GTUtility;
import gregtech.api.util.VirtualTankRegistry;
Expand All @@ -18,8 +20,12 @@
import gregtech.common.items.behaviors.ToggleEnergyConsumerBehavior;
import gregtech.common.metatileentities.multi.electric.centralmonitor.MetaTileEntityCentralMonitor;

import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityOtherPlayerMP;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.player.EntityPlayer;
Expand All @@ -31,7 +37,9 @@
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.EnumDifficulty;
import net.minecraftforge.client.event.FOVUpdateEvent;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.event.entity.living.EnderTeleportEvent;
import net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent;
Expand Down Expand Up @@ -148,8 +156,7 @@ public static void onDestroySpeed(net.minecraftforge.event.entity.player.PlayerE

@SubscribeEvent(priority = EventPriority.LOW)
public static void onEntityLivingFallEvent(LivingFallEvent event) {
if (event.getEntity() instanceof EntityPlayerMP) {
EntityPlayerMP player = (EntityPlayerMP) event.getEntity();
if (event.getEntity() instanceof EntityPlayerMP player) {
ItemStack armor = player.getItemStackFromSlot(EntityEquipmentSlot.FEET);
ItemStack jet = player.getItemStackFromSlot(EntityEquipmentSlot.CHEST);

Expand Down Expand Up @@ -206,9 +213,94 @@ public static void onLivingEquipmentChangeEvent(LivingEquipmentChangeEvent event
}
}

@SuppressWarnings({ "ConstantValue", "deprecation" })
@SubscribeEvent
@SideOnly(Side.CLIENT)
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
EntityPlayer player = event.player;
if (event.phase == TickEvent.Phase.START && !player.world.isRemote) {
IAttributeInstance movementSpeed = player.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED);
if (movementSpeed == null) return;
AttributeModifier modifier = movementSpeed.getModifier(BlockUtility.WALKING_SPEED_UUID);

double speedBonus;
if (!player.onGround || player.isInWater() || player.isSneaking()) {
speedBonus = 0;
} else {
IBlockState state = player.world.getBlockState(new BlockPos(
player.posX, player.getEntityBoundingBox().minY - 1, player.posZ));
speedBonus = BlockUtility.WALKING_SPEED_BONUS.getDouble(state);
// { remove this bit while removing IWalkingSpeedBonus
if (speedBonus == 0 &&
state.getBlock() instanceof IWalkingSpeedBonus walkingSpeedBonus &&
walkingSpeedBonus.getWalkingSpeedBonus() != 1 &&
walkingSpeedBonus.bonusSpeedCondition(player) &&
walkingSpeedBonus.checkApplicableBlocks(state)) {
speedBonus = walkingSpeedBonus.getWalkingSpeedBonus() - 1;
}
// }
}
if (modifier != null) {
if (speedBonus == modifier.getAmount()) return;
else movementSpeed.removeModifier(BlockUtility.WALKING_SPEED_UUID);
} else {
if (speedBonus == 0) return;
}
if (speedBonus != 0) {
movementSpeed.applyModifier(new AttributeModifier(BlockUtility.WALKING_SPEED_UUID,
"Walking Speed Bonus", speedBonus, 2));
}
}
}

@SuppressWarnings({ "lossy-conversions", "ConstantValue" })
@SubscribeEvent
@SideOnly(Side.CLIENT)
public static void onFOVUpdate(FOVUpdateEvent event) { // this event SUCKS
EntityPlayer player = event.getEntity();
IAttributeInstance movementSpeed = player.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED);
if (movementSpeed == null || movementSpeed.getModifier(BlockUtility.WALKING_SPEED_UUID) == null) return;

float originalFov = player.capabilities.isFlying ? 1.1f : 1.0f;
originalFov *= (movementSpeed.getAttributeValue() / player.capabilities.getWalkSpeed() + 1) / 2;

if (player.capabilities.getWalkSpeed() == 0 || Float.isNaN(originalFov) || Float.isInfinite(originalFov)) {
return;
}

float newFov = player.capabilities.isFlying ? 1.1f : 1.0f;
newFov *= (computeValueWithoutWalkingSpeed(movementSpeed) / player.capabilities.getWalkSpeed() + 1) / 2;

event.setNewfov(newFov / originalFov * event.getNewfov());
}

/**
* Computes walking speed without boost from {@link BlockUtility#WALKING_SPEED_BONUS}. Skipping parent check stuff
* because movement speed attribute does not have any parent modifier.
*/
private static double computeValueWithoutWalkingSpeed(IAttributeInstance attrib) {
double base = attrib.getBaseValue();

for (AttributeModifier m : attrib.getModifiersByOperation(0)) {
base += m.getAmount();
}

double applied = base;

for (AttributeModifier m : attrib.getModifiersByOperation(1)) {
applied += base * m.getAmount();
}

for (AttributeModifier m : attrib.getModifiersByOperation(2)) {
if (m.getID() == BlockUtility.WALKING_SPEED_UUID) continue;
applied *= 1 + m.getAmount();
}

return attrib.getAttribute().clampValue(applied);
}

@SubscribeEvent
@SideOnly(Side.CLIENT)
public static void onPlayerTickClient(TickEvent.PlayerTickEvent event) {
if (event.phase == TickEvent.Phase.START && !event.player.isSpectator() &&
!(event.player instanceof EntityOtherPlayerMP) && !(event.player instanceof FakePlayer)) {
ItemStack feetEquip = event.player.getItemStackFromSlot(EntityEquipmentSlot.FEET);
Expand Down
10 changes: 0 additions & 10 deletions src/main/java/gregtech/common/blocks/BlockAsphalt.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,6 @@ public boolean canCreatureSpawn(@NotNull IBlockState state, @NotNull IBlockAcces
return false;
}

@Override
public double getWalkingSpeedBonus() {
return 1.6D;
}

@Override
public boolean checkApplicableBlocks(IBlockState state) {
return state == getState(BlockType.ASPHALT);
}

public enum BlockType implements IStringSerializable, IStateHarvestLevel {

ASPHALT("asphalt", 0);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/gregtech/common/blocks/BlockBatteryPart.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public boolean canCreatureSpawn(@NotNull IBlockState state, @NotNull IBlockAcces
}

@Override
public void addInformation(@NotNull ItemStack stack, @Nullable World world, List<String> tooltip,
public void addInformation(@NotNull ItemStack stack, @Nullable World world, @NotNull List<String> tooltip,
@NotNull ITooltipFlag advanced) {
super.addInformation(stack, world, tooltip, advanced);

Expand Down
24 changes: 6 additions & 18 deletions src/main/java/gregtech/common/blocks/BlockColored.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;

public class BlockColored extends VariantBlock<EnumDyeColor> {
import org.jetbrains.annotations.NotNull;

public BlockColored() {
this(net.minecraft.block.material.Material.IRON, "block_colored", 2.0f, 5.0f, SoundType.METAL,
EnumDyeColor.WHITE);
}
public class BlockColored extends VariantBlock<EnumDyeColor> {

public BlockColored(Material material, String translationKey, float hardness, float resistance, SoundType soundType,
EnumDyeColor defaultColor) {
Expand All @@ -30,23 +27,14 @@ public BlockColored(Material material, String translationKey, float hardness, fl
}

@Override
public boolean canCreatureSpawn(IBlockState state, IBlockAccess world, BlockPos pos,
EntityLiving.SpawnPlacementType type) {
public boolean canCreatureSpawn(@NotNull IBlockState state, @NotNull IBlockAccess world, @NotNull BlockPos pos,
@NotNull EntityLiving.SpawnPlacementType type) {
return false;
}

@Override
public double getWalkingSpeedBonus() {
return 1.25;
}

@Override
public boolean checkApplicableBlocks(IBlockState state) {
return this == MetaBlocks.STUDS;
}

@Override
public boolean recolorBlock(World world, BlockPos pos, EnumFacing side, EnumDyeColor color) {
public boolean recolorBlock(World world, @NotNull BlockPos pos, @NotNull EnumFacing side,
@NotNull EnumDyeColor color) {
if (world.getBlockState(pos) != getState(color)) {
world.setBlockState(pos, getState(color));
return true;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/gregtech/common/blocks/BlockSteamCasing.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public boolean canCreatureSpawn(@NotNull IBlockState state, @NotNull IBlockAcces
}

@Override
public void addInformation(@NotNull ItemStack stack, @Nullable World player, List<String> tooltip,
public void addInformation(@NotNull ItemStack stack, @Nullable World player, @NotNull List<String> tooltip,
@NotNull ITooltipFlag advanced) {
int ordinal = getState(stack).ordinal();
if (ordinal < 2) {
Expand Down
Loading

0 comments on commit 09a4e64

Please sign in to comment.