Plasma weapons but better™️
This commit is contained in:
parent
15c4cfb488
commit
42c0c49782
@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -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()))
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user