Plasma weapons but better™️

This commit is contained in:
DBotThePony 2022-05-14 15:18:50 +07:00
parent 15c4cfb488
commit 42c0c49782
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 130 additions and 17 deletions

View File

@ -329,3 +329,24 @@ fun bezierCurve(t: Double, vararg values: Vector): Vector {
} }
} }
} }
fun bezierCurve(t: Double, values: DoubleArray): Double {
when (values.size) {
0, 1 -> throw IllegalArgumentException("Provided array has only ${values.size} entries in it")
else -> {
@Suppress("NAME_SHADOWING") val values = values.clone()
// construct prime - 1
for (length in values.size - 2 downTo 0) {
// search prime
for (j in 0 .. length) {
val point1 = values[j]
val point2 = values[j + 1]
values[j] = linearInterpolation(t, point1, point2)
}
}
return values[0]
}
}
}

View File

@ -43,8 +43,6 @@ class PlasmaProjectile(level: Level) : Projectile(MEntityTypes.PLASMA as EntityT
override fun onHitBlock(p_37258_: BlockHitResult) { override fun onHitBlock(p_37258_: BlockHitResult) {
super.onHitBlock(p_37258_) super.onHitBlock(p_37258_)
println("Play sound at ${position()}")
} }
override fun tick() { override fun tick() {

View File

@ -27,6 +27,7 @@ import ru.dbotthepony.mc.otm.network.MatteryNetworking
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.math.PI import kotlin.math.PI
import kotlin.math.abs
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.primaryConstructor import kotlin.reflect.full.primaryConstructor
@ -99,6 +100,29 @@ open class WeaponDataTable(val tag: CompoundTag) {
var nextPrimaryFire by tag.ints var nextPrimaryFire by tag.ints
var nextSecondaryFire by tag.ints var nextSecondaryFire by tag.ints
var uuid by tag.uuids var uuid by tag.uuids
var fireAnim = 0.0
var fireAnimDeviation = Angle.ZERO
fun doFireAnim(amount: Double = 1.0, deviation: Angle? = null) {
fireAnim = (fireAnim + amount).coerceAtLeast(0.0).coerceAtMost(1.0)
if (deviation != null) {
fireAnimDeviation = Angle(
deviation.pitch * RANDOM.nextGaussian(),
deviation.yaw * RANDOM.nextGaussian(),
deviation.roll * RANDOM.nextGaussian(),
)
} else {
fireAnimDeviation = Angle.ZERO
}
}
var deployTime = 0.0
companion object {
private val RANDOM = Random()
}
} }
abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, rarity: Rarity = Rarity.UNCOMMON) : Item( abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, rarity: Rarity = Rarity.UNCOMMON) : Item(
@ -144,10 +168,16 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
val roundsPerSecond get() = roundsPerMinute / 60 val roundsPerSecond get() = roundsPerMinute / 60
val fireCooldown get() = (1200 / roundsPerMinute).coerceAtLeast(1) val fireCooldown get() = (1200 / roundsPerMinute).coerceAtLeast(1)
open val positionHolstered get() = Vector(1.0, -2.5, -1.0)
open val positionIdle get() = Vector(1.0, -0.5, -1.0) open val positionIdle get() = Vector(1.0, -0.5, -1.0)
open val positionIronSights get() = Vector(0.0, -0.23, -1.0) open val positionIronSights get() = Vector(0.0, -0.23, -1.0)
open val rotIdle get() = Angle(PI / 36, PI / 18) open val rotIdle get() = Angle(PI / 36, PI / 18)
open val rotIronSights get() = Angle.ZERO open val rotIronSights get() = Angle.ZERO
open val rotFireAnim get() = Angle.deg(20.0, 0.0, 0.0)
open val rotFireAnimDeviation get() = Angle.deg(2.0, 1.0, 1.0)
open val fireAnimRecovery = 1.0
open val deployAnimSpeed = 1.0
open val primaryAutomatic = true open val primaryAutomatic = true
open val secondaryAutomatic = true open val secondaryAutomatic = true
@ -156,9 +186,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
fun ironSightsProgress(itemStack: ItemStack, partialTicks: Double = 0.0, dt: D = dataTable(itemStack)): Double { fun ironSightsProgress(itemStack: ItemStack, partialTicks: Double = 0.0, dt: D = dataTable(itemStack)): Double {
if (!dt.wantsToScope) if (!dt.wantsToScope)
return (dt.scopeTicks.toDouble() - partialTicks).coerceAtLeast(0.0) / scopingTime.toDouble() return (((dt.scopeTicks.toDouble() - partialTicks).coerceAtLeast(0.0) / scopingTime.toDouble()) * 1.4).coerceAtMost(1.0)
return (dt.scopeTicks.toDouble() + partialTicks) / scopingTime.toDouble() return (((dt.scopeTicks.toDouble() + partialTicks) / scopingTime.toDouble()) * 1.4).coerceAtMost(1.0)
} }
abstract val scopingTime: Int abstract val scopingTime: Int
@ -228,25 +258,39 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
// client only // client only
private var inRender = false private var inRender = false
var predictedData: WeaponDataTable? = null var predictedData: WeaponDataTable? = null
private var lastFov = 1.0
private var lastFovTime = 0L
@SubscribeEvent @SubscribeEvent
@Suppress("unused") @Suppress("unused")
fun fovHook(event: EntityViewRenderEvent.FieldOfView) { fun fovHook(event: EntityViewRenderEvent.FieldOfView) {
val player = event.camera.entity as? Player ?: return val player = event.camera.entity as? Player ?: return
(player.mainHandItem.item as? AbstractWeaponItem<*>)?.let { val it = (player.mainHandItem.item as? AbstractWeaponItem<*>)
if (it != null) {
@Suppress("unchecked_cast") @Suppress("unchecked_cast")
if (it.compatibleDataTable(predictedData)) if (it.compatibleDataTable(predictedData))
(it as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData (it as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
event.fov /= linearInterpolation( val interp = linearInterpolation(
it.ironSightsProgress( it.ironSightsProgress(
player.mainHandItem, player.mainHandItem,
event.partialTicks event.partialTicks
) * 1.7 - 0.6, 1.0, it.ironSightsFOV ) * 1.7 - 0.6, 1.0, it.ironSightsFOV
) )
val time = System.nanoTime()
val diff = abs(lastFovTime - time)
lastFov = linearInterpolation(diff.coerceAtLeast(0).coerceAtMost(10_000_000L).toDouble() / 10_000_000.0, lastFov, interp).coerceAtLeast(0.001)
lastFovTime = time
event.fov /= lastFov
it.dataTable = null it.dataTable = null
} else {
lastFov = 1.0
lastFovTime = 0L
} }
} }
@ -270,6 +314,29 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
} }
} }
private var lastClientRender = 0L
private val fireAnimInterp = doubleArrayOf(
0.0,
0.01,
0.03,
0.04,
0.05,
0.06,
0.07,
0.1,
0.15,
0.3,
0.45,
0.6,
0.8,
0.85,
0.9,
1.0,
0.9,
0.6,
)
@SubscribeEvent @SubscribeEvent
@Suppress("unused", "unchecked_cast") @Suppress("unused", "unchecked_cast")
fun renderViewModel(event: RenderHandEvent) { fun renderViewModel(event: RenderHandEvent) {
@ -277,6 +344,10 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
return return
} }
val time = System.nanoTime()
val diff = abs(lastClientRender - time)
lastClientRender = time
val stack = event.itemStack val stack = event.itemStack
val item = stack.item as? AbstractWeaponItem<*> ?: return val item = stack.item as? AbstractWeaponItem<*> ?: return
@ -285,6 +356,9 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
(item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData (item as AbstractWeaponItem<WeaponDataTable>).dataTable = predictedData
predictedData?.deployTime = (predictedData!!.deployTime + diff.toDouble() / (300_000_000.0 * item.deployAnimSpeed)).coerceAtMost(1.0).coerceAtLeast(0.0)
predictedData?.fireAnim = (predictedData!!.fireAnim - diff.toDouble() / (300_000_000.0 * item.fireAnimRecovery)).coerceAtMost(1.0).coerceAtLeast(0.0)
val player = Minecraft.getInstance().player!! val player = Minecraft.getInstance().player!!
val pose = event.poseStack val pose = event.poseStack
val itemInHandRenderer = Minecraft.getInstance().itemInHandRenderer val itemInHandRenderer = Minecraft.getInstance().itemInHandRenderer
@ -293,7 +367,11 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
val progress = item.ironSightsProgress(stack, event.partialTicks.toDouble()) val progress = item.ironSightsProgress(stack, event.partialTicks.toDouble())
val (x, y, z) = bezierCurve( val (x, y, z) = linearInterpolation(
// 1.0 - event.equipProgress.toDouble(),
item.dataTable?.deployTime ?: 0.0,
item.positionHolstered,
bezierCurve(
progress, progress,
item.positionIdle, item.positionIdle,
item.positionIdle, item.positionIdle,
@ -303,10 +381,11 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
item.positionIronSights, item.positionIronSights,
item.positionIronSights, item.positionIronSights,
) )
)
pose.translate(x, y, z) pose.translate(x, y, z)
val (pitch, yaw, roll) = bezierCurve( var (pitch, yaw, roll) = bezierCurve(
progress, progress,
item.rotIdle, item.rotIdle,
item.rotIdle, item.rotIdle,
@ -319,6 +398,16 @@ abstract class AbstractWeaponItem<D : WeaponDataTable>(val tables: KClass<D>, ra
item.rotIronSights, item.rotIronSights,
) )
val fireAnim = bezierCurve(
predictedData?.fireAnim ?: 0.0,
fireAnimInterp
)
val rotFire = item.rotFireAnim
pitch += (rotFire.pitch + (predictedData?.fireAnimDeviation?.pitch ?: 0.0)) * fireAnim
yaw += (rotFire.yaw + (predictedData?.fireAnimDeviation?.yaw ?: 0.0)) * fireAnim
roll += (rotFire.roll + (predictedData?.fireAnimDeviation?.roll ?: 0.0)) * fireAnim
pose.mulPose(Vector3f.ZP.rotation(roll.toFloat())) pose.mulPose(Vector3f.ZP.rotation(roll.toFloat()))
pose.mulPose(Vector3f.YP.rotation(yaw.toFloat())) pose.mulPose(Vector3f.YP.rotation(yaw.toFloat()))
pose.mulPose(Vector3f.XP.rotation(pitch.toFloat())) pose.mulPose(Vector3f.XP.rotation(pitch.toFloat()))

View File

@ -118,8 +118,9 @@ class VelocityCalculation(
} }
class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class, ImpreciseFraction(200_000)) { class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class, ImpreciseFraction(200_000)) {
override val roundsPerMinute: Int = 400 override val roundsPerMinute: Int = 200
override val scopingTime: Int = 7 override val scopingTime: Int = 7
override val positionIdle: Vector override val positionIdle: Vector
get() = Vector(0.2,-0.4,-0.6) get() = Vector(0.2,-0.4,-0.6)
override val positionIronSights: Vector override val positionIronSights: Vector
@ -137,7 +138,11 @@ class PlasmaRifleItem : PlasmaWeaponItem<WeaponDataTable>(WeaponDataTable::class
val calc = VelocityCalculation(player, force = 4.0, deviation = 0.3) val calc = VelocityCalculation(player, force = 4.0, deviation = 0.3)
calc.load(arrow) calc.load(arrow)
arrow.owner = player
player.level.addFreshEntity(arrow) player.level.addFreshEntity(arrow)
} else {
dt.doFireAnim(deviation = rotFireAnimDeviation)
} }
return true return true