Shockwave feature test, some refactoring
This commit is contained in:
parent
f8965e583c
commit
0713b7bb09
@ -40,3 +40,11 @@ fun ForgeConfigSpec.Builder.appendComment(vararg comments: String): ForgeConfigS
|
||||
builderContextField.set(context, reconstruct)
|
||||
return this
|
||||
}
|
||||
|
||||
fun ForgeConfigSpec.Builder.defineInRange(path: String, value: Int, minValue: Int): ForgeConfigSpec.IntValue {
|
||||
return defineInRange(path, value, minValue, Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
fun ForgeConfigSpec.Builder.defineInRange(path: String, value: Double, minValue: Double): ForgeConfigSpec.DoubleValue {
|
||||
return defineInRange(path, value, minValue, Double.MAX_VALUE)
|
||||
}
|
||||
|
@ -141,7 +141,28 @@ object ServerConfig {
|
||||
|
||||
val NIGHT_VISION_POWER_DRAW by specBuilder.defineImpreciseFraction("nightVisionPowerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO)
|
||||
|
||||
object Shockwave {
|
||||
init {
|
||||
specBuilder.comment("Shockwave ability").push("shockwave")
|
||||
}
|
||||
|
||||
val TERMINAL_VELOCITY: Double by specBuilder.comment("In meters per second vertically").defineInRange("terminalVelocity", 5.6, 0.0)
|
||||
val ACCELERATION: Double by specBuilder.comment("In meters per second vertically").defineInRange("acceleration", 4.0, 0.0)
|
||||
val COOLDOWN: Int by specBuilder.comment("In ticks").defineInRange("cooldown", 30, 1)
|
||||
val RADIUS_HORIZONTAL: Double by specBuilder.comment("In meters").defineInRange("radiusHorizontal", 4.0, 0.0)
|
||||
val RADIUS_VERTICAL: Double by specBuilder.comment("In meters").defineInRange("radiusVertical", 1.0, 0.0)
|
||||
val BREAK_BLOCKS: Boolean by specBuilder.comment("Break blocks without any blast resistance").define("breakBlocks", true)
|
||||
val DAMAGE: Double by specBuilder.comment("Max potential damage done by shockwave").defineInRange("damage", 12.0, 0.0, Float.MAX_VALUE.toDouble())
|
||||
|
||||
init {
|
||||
specBuilder.pop()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// access shockwave class so spec is built
|
||||
Shockwave
|
||||
|
||||
specBuilder.pop()
|
||||
|
||||
specBuilder.comment("Tweaking of exosuits").push("exosuitPlayer")
|
||||
|
@ -11,7 +11,7 @@ import java.io.DataInputStream
|
||||
import java.io.InputStream
|
||||
|
||||
abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: MatteryPlayerCapability) : INBTSerializable<CompoundTag> {
|
||||
val entity get() = android.ply
|
||||
val ply get() = android.ply
|
||||
val synchronizer = FieldSynchronizer()
|
||||
|
||||
open var level by synchronizer.int(setter = setter@{ value, field, setByRemote ->
|
||||
|
@ -22,6 +22,7 @@ abstract class AndroidSwitchableFeature(type: AndroidFeatureType<*>, android: Ma
|
||||
|
||||
open val allowToSwitchByPlayer: Boolean get() = true
|
||||
|
||||
// TODO: PoseStack is stripped from server dist
|
||||
abstract fun renderIcon(stack: PoseStack, x: Float, y: Float, width: Float, height: Float)
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
|
@ -9,7 +9,7 @@ import java.util.*
|
||||
|
||||
class AttackBoost(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.LIMB_OVERCLOCKING, android) {
|
||||
override fun applyModifiers() {
|
||||
val modifier = entity.getAttribute(Attributes.ATTACK_DAMAGE)
|
||||
val modifier = ply.getAttribute(Attributes.ATTACK_DAMAGE)
|
||||
|
||||
if (modifier != null) {
|
||||
modifier.removePermanentModifier(MODIFIER_ID)
|
||||
@ -18,7 +18,7 @@ class AttackBoost(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeat
|
||||
}
|
||||
|
||||
override fun removeModifiers() {
|
||||
entity.getAttribute(Attributes.ATTACK_DAMAGE)?.removePermanentModifier(MODIFIER_ID)
|
||||
ply.getAttribute(Attributes.ATTACK_DAMAGE)?.removePermanentModifier(MODIFIER_ID)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -12,7 +12,7 @@ class ExtendedReach(android: MatteryPlayerCapability) : AndroidFeature(AndroidFe
|
||||
if (!ForgeMod.REACH_DISTANCE.isPresent)
|
||||
return
|
||||
|
||||
val reach = entity.getAttribute(ForgeMod.REACH_DISTANCE.get()) ?: return
|
||||
val reach = ply.getAttribute(ForgeMod.REACH_DISTANCE.get()) ?: return
|
||||
|
||||
reach.removePermanentModifier(MODIFIER_ID)
|
||||
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), level + 1.0, AttributeModifier.Operation.ADDITION))
|
||||
@ -22,7 +22,7 @@ class ExtendedReach(android: MatteryPlayerCapability) : AndroidFeature(AndroidFe
|
||||
if (!ForgeMod.REACH_DISTANCE.isPresent)
|
||||
return
|
||||
|
||||
entity.getAttribute(ForgeMod.REACH_DISTANCE.get())?.removePermanentModifier(MODIFIER_ID)
|
||||
ply.getAttribute(ForgeMod.REACH_DISTANCE.get())?.removePermanentModifier(MODIFIER_ID)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -9,14 +9,14 @@ import java.util.*
|
||||
|
||||
class LimbOverclocking(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.LIMB_OVERCLOCKING, android) {
|
||||
override fun applyModifiers() {
|
||||
val speed = entity.getAttribute(Attributes.MOVEMENT_SPEED)
|
||||
val speed = ply.getAttribute(Attributes.MOVEMENT_SPEED)
|
||||
|
||||
if (speed != null) {
|
||||
speed.removePermanentModifier(MODIFIER_ID)
|
||||
speed.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.08, AttributeModifier.Operation.MULTIPLY_TOTAL))
|
||||
}
|
||||
|
||||
val attackSpeed = entity.getAttribute(Attributes.ATTACK_SPEED)
|
||||
val attackSpeed = ply.getAttribute(Attributes.ATTACK_SPEED)
|
||||
|
||||
if (attackSpeed != null) {
|
||||
attackSpeed.removePermanentModifier(MODIFIER_ID)
|
||||
@ -25,8 +25,8 @@ class LimbOverclocking(android: MatteryPlayerCapability) : AndroidFeature(Androi
|
||||
}
|
||||
|
||||
override fun removeModifiers() {
|
||||
entity.getAttribute(Attributes.MOVEMENT_SPEED)?.removePermanentModifier(MODIFIER_ID)
|
||||
entity.getAttribute(Attributes.ATTACK_SPEED)?.removePermanentModifier(MODIFIER_ID)
|
||||
ply.getAttribute(Attributes.MOVEMENT_SPEED)?.removePermanentModifier(MODIFIER_ID)
|
||||
ply.getAttribute(Attributes.ATTACK_SPEED)?.removePermanentModifier(MODIFIER_ID)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -9,7 +9,6 @@ import ru.dbotthepony.mc.otm.capability.extractEnergyInnerExact
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.StatNames
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -47,7 +46,7 @@ class NanobotsArmor(android: MatteryPlayerCapability) : AndroidFeature(AndroidFe
|
||||
val powerExtracted = android.androidEnergy.extractEnergyInner(powerRequired, false)
|
||||
val realAbsorbed = (powerExtracted / ENERGY_PER_HITPOINT).toFloat()
|
||||
event.amount = event.amount - realAbsorbed
|
||||
(entity as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt())
|
||||
(ply as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt())
|
||||
layers--
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.StatNames
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -17,21 +16,21 @@ class NanobotsRegeneration(android: MatteryPlayerCapability) : AndroidFeature(An
|
||||
private var healTicks = 0
|
||||
|
||||
override fun tickServer() {
|
||||
if (entity.health > 0f && entity.health < entity.maxHealth) {
|
||||
if (ply.health > 0f && ply.health < ply.maxHealth) {
|
||||
ticksPassed++
|
||||
|
||||
val waitTime = TICKS_BETWEEN_HEAL.getOrElse(healTicks) { TICKS_BETWEEN_HEAL.last() }
|
||||
|
||||
if (ticksPassed > waitTime) {
|
||||
val missingHealth = entity.maxHealth - entity.health
|
||||
val missingHealth = ply.maxHealth - ply.health
|
||||
val power = ENERGY_PER_HITPOINT * missingHealth
|
||||
val extracted = android.androidEnergy.extractEnergyInner(power, false)
|
||||
|
||||
if (extracted.isPositive) {
|
||||
healTicks = (healTicks + 1).coerceAtMost(level)
|
||||
val healed = (extracted / ENERGY_PER_HITPOINT).toFloat()
|
||||
entity.heal(healed)
|
||||
(entity as ServerPlayer?)?.awardStat(StatNames.HEALTH_REGENERATED, (healed * 10f).roundToInt())
|
||||
ply.heal(healed)
|
||||
(ply as ServerPlayer?)?.awardStat(StatNames.HEALTH_REGENERATED, (healed * 10f).roundToInt())
|
||||
ticksPassed = 0
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.android.feature
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraftforge.api.distmarker.Dist
|
||||
import net.minecraftforge.api.distmarker.OnlyIn
|
||||
import ru.dbotthepony.mc.otm.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
|
@ -0,0 +1,153 @@
|
||||
package ru.dbotthepony.mc.otm.android.feature
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.phys.AABB
|
||||
import ru.dbotthepony.mc.otm.ServerConfig
|
||||
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
import ru.dbotthepony.mc.otm.core.Vector
|
||||
import ru.dbotthepony.mc.otm.core.getEllipsoidBlockPositions
|
||||
import ru.dbotthepony.mc.otm.core.getExplosionResistance
|
||||
import ru.dbotthepony.mc.otm.core.minus
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
import ru.dbotthepony.mc.otm.core.position
|
||||
import ru.dbotthepony.mc.otm.core.roundToIntVector
|
||||
import ru.dbotthepony.mc.otm.core.times
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.network.TriggerShockwavePacket
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||
import ru.dbotthepony.mc.otm.registry.AndroidResearch
|
||||
import ru.dbotthepony.mc.otm.registry.ShockwaveDamageSource
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.SHOCKWAVE, capability) {
|
||||
var cooldown by synchronizer.int()
|
||||
|
||||
private var wasMidair = false
|
||||
private var highestSpeed = 0.0
|
||||
var airTicks = 0
|
||||
private set
|
||||
|
||||
override fun tickClient() {
|
||||
if (isActive && ply.isSteppingCarefully && cooldown <= 0) {
|
||||
ply.deltaMovement += Vector(0.0, -ServerConfig.Shockwave.ACCELERATION / 20.0, 0.0)
|
||||
}
|
||||
|
||||
ticker(true)
|
||||
}
|
||||
|
||||
fun shockwave() {
|
||||
// TODO: raycasting
|
||||
val entities = ply.level.getEntities(ply, AABB(
|
||||
ply.position.x - ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
ply.position.y - ServerConfig.Shockwave.RADIUS_VERTICAL,
|
||||
ply.position.z - ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
|
||||
ply.position.x + ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
ply.position.y + ServerConfig.Shockwave.RADIUS_VERTICAL,
|
||||
ply.position.z + ServerConfig.Shockwave.RADIUS_HORIZONTAL,
|
||||
)) { (it !is LivingEntity || !it.isSpectator && it.isAlive) && ((it.position - ply.position).let { vec ->
|
||||
vec.x.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
vec.y.pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
vec.z.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) <= 1.0
|
||||
}) || it.boundingBox.center.let { vec ->
|
||||
(vec.x - ply.position.x).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
(vec.y - ply.position.y).pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
(vec.z - ply.position.z).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) <= 1.0
|
||||
} }
|
||||
|
||||
for (entity in entities) {
|
||||
val diff = entity.position - ply.position
|
||||
|
||||
val distanceMultiplier = diff.let {
|
||||
it.x.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
it.y.pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
it.z.pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0)
|
||||
}.coerceAtMost(entity.boundingBox.center.let { vec ->
|
||||
(vec.x - ply.position.x).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0) +
|
||||
(vec.y - ply.position.y).pow(2.0) / ServerConfig.Shockwave.RADIUS_VERTICAL.pow(2.0) +
|
||||
(vec.z - ply.position.z).pow(2.0) / ServerConfig.Shockwave.RADIUS_HORIZONTAL.pow(2.0)
|
||||
})
|
||||
|
||||
val multiplier = (1.0 - distanceMultiplier).pow(1.25)
|
||||
|
||||
// don't hurt items, arrows, etc etc
|
||||
if (entity is LivingEntity) {
|
||||
entity.hurt(ShockwaveDamageSource(ply), multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat())
|
||||
entity.deltaMovement += diff.normalize() * (multiplier * 3.0)
|
||||
} else {
|
||||
entity.deltaMovement += diff.normalize() * (multiplier * 6.0)
|
||||
}
|
||||
}
|
||||
|
||||
if (ServerConfig.Shockwave.BREAK_BLOCKS) {
|
||||
val rounded = ply.position.roundToIntVector()
|
||||
|
||||
for (blockPos in getEllipsoidBlockPositions(ServerConfig.Shockwave.RADIUS_HORIZONTAL.roundToInt(), ServerConfig.Shockwave.RADIUS_VERTICAL.roundToInt(), ServerConfig.Shockwave.RADIUS_HORIZONTAL.roundToInt())) {
|
||||
val newBlockPos = blockPos + rounded
|
||||
|
||||
val blockState = ply.level.getBlockState(newBlockPos)
|
||||
|
||||
if (!blockState.isAir && blockState.getExplosionResistance(ply.level, newBlockPos) <= 0f && ply.level.getBlockEntity(newBlockPos) == null) {
|
||||
// Block.dropResources(blockState, ply.level, newBlockPos)
|
||||
// blockState.block.destroy(ply.level, newBlockPos, blockState)
|
||||
// ply.level.setBlock(newBlockPos, blockState.fluidState.createLegacyBlock(), Block.UPDATE_ALL)
|
||||
|
||||
ply.level.destroyBlock(newBlockPos, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ticker(isClient: Boolean) {
|
||||
if (!ply.isOnGround) {
|
||||
airTicks = (airTicks + 1).coerceAtMost(3)
|
||||
} else {
|
||||
airTicks = (airTicks - 1).coerceAtLeast(0)
|
||||
}
|
||||
|
||||
if (isActive && cooldown <= 0) {
|
||||
val old = wasMidair
|
||||
wasMidair = !ply.isOnGround
|
||||
|
||||
if (wasMidair) {
|
||||
highestSpeed = (-ply.deltaMovement.y).coerceAtLeast(highestSpeed)
|
||||
}
|
||||
|
||||
if (old != wasMidair && !wasMidair && ServerConfig.Shockwave.TERMINAL_VELOCITY <= (highestSpeed * 20.0) && ply.isSteppingCarefully) {
|
||||
cooldown = ServerConfig.Shockwave.COOLDOWN
|
||||
|
||||
if (isClient) {
|
||||
// I HATE SELF-UPDATING PLAYERS
|
||||
// I HATE SELF-UPDATING PLAYERS
|
||||
// fix "bug" where shockwave doesn't trigger even when player is falling faster than orbiting satellite
|
||||
MatteryPlayerNetworkChannel.sendToServer(TriggerShockwavePacket)
|
||||
} else {
|
||||
shockwave()
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasMidair) {
|
||||
highestSpeed = 0.0
|
||||
}
|
||||
} else if (!isActive) {
|
||||
highestSpeed = 0.0
|
||||
wasMidair = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun tickServer() {
|
||||
if (cooldown > 0) {
|
||||
cooldown--
|
||||
}
|
||||
|
||||
ticker(false)
|
||||
}
|
||||
|
||||
override fun renderIcon(stack: PoseStack, x: Float, y: Float, width: Float, height: Float) {
|
||||
AndroidResearch.ICON_SHOCKWAVE.render(stack, x, y, width, height)
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ class StepAssistFeature(android: MatteryPlayerCapability) : AndroidFeature(Andro
|
||||
if (!ForgeMod.STEP_HEIGHT_ADDITION.isPresent)
|
||||
return
|
||||
|
||||
val reach = entity.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()) ?: return
|
||||
val reach = ply.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()) ?: return
|
||||
|
||||
reach.removePermanentModifier(MODIFIER_ID)
|
||||
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), level + 1.0, AttributeModifier.Operation.ADDITION))
|
||||
@ -22,7 +22,7 @@ class StepAssistFeature(android: MatteryPlayerCapability) : AndroidFeature(Andro
|
||||
if (!ForgeMod.STEP_HEIGHT_ADDITION.isPresent)
|
||||
return
|
||||
|
||||
entity.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get())?.removePermanentModifier(MODIFIER_ID)
|
||||
ply.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get())?.removePermanentModifier(MODIFIER_ID)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.matter.getMatterValue
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.MItems
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import ru.dbotthepony.mc.otm.container.set
|
||||
import ru.dbotthepony.mc.otm.core.getSphericalBlockPositions
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
@ -302,7 +302,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn
|
||||
}
|
||||
|
||||
if (gravitationStrength > 0.4) {
|
||||
val sphere = getSphericalShape((gravitationStrength * 6.0).roundToInt())
|
||||
val sphere = getSphericalBlockPositions((gravitationStrength * 6.0).roundToInt())
|
||||
|
||||
if (sphere.size != lastSphereSizeOuter) {
|
||||
lastSphereSizeOuter = sphere.size
|
||||
@ -327,12 +327,14 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn
|
||||
|
||||
val eResist = try {
|
||||
getBlock.getExplosionResistance(level, pos, null)
|
||||
} catch (err: Throwable) {
|
||||
getBlock.block.getExplosionResistance()
|
||||
} catch (err: NullPointerException) {
|
||||
getBlock.block.explosionResistance
|
||||
// Потому что возможно какой-либо мод не ожидает что Explosion == null
|
||||
// особенно учитывая что интерфейс IForgeBlock не имеет @ParamsAreNonnullByDefault
|
||||
// и аргумент не помечен как @Nullable
|
||||
// тем самым имеет тип Explosion! который указывается как Explosion? .. Explosion!!
|
||||
} catch (err: IllegalArgumentException) {
|
||||
getBlock.block.explosionResistance
|
||||
}
|
||||
|
||||
var strengthLinear = sqrt(blockPos.distSqr(pos))
|
||||
@ -362,49 +364,5 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn
|
||||
const val ITERATIONS = 30_000
|
||||
val BASELINE_MASS = ImpreciseFraction(1_000)
|
||||
val HAWKING_MASS_LOSE_STEP = ImpreciseFraction("-0.1")
|
||||
|
||||
private val blockShapeCache = HashMap<Int, Array<BlockPos>>()
|
||||
|
||||
private fun getSphericalShape(size: Int): Array<BlockPos> {
|
||||
return blockShapeCache.computeIfAbsent(size) {
|
||||
val result = ArrayList<BlockPos>((it * it * it * Math.PI * (4.0 / 3.0)).toInt() + 16)
|
||||
|
||||
for (x in -it .. it) {
|
||||
for (y in -it .. it) {
|
||||
for (z in -it .. it) {
|
||||
val dist = sqrt(x * x.toDouble() + y * y.toDouble() + z * z.toDouble())
|
||||
|
||||
if (dist <= size && dist != 0.0) {
|
||||
result.add(BlockPos(x, y, z))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val arr = result.toTypedArray()
|
||||
|
||||
arr.sortWith { a, b ->
|
||||
val xa = a.x
|
||||
val ya = a.y
|
||||
val za = a.z
|
||||
val distA = sqrt(xa * xa.toDouble() + ya * ya.toDouble() + za * za.toDouble())
|
||||
|
||||
val xb = b.x
|
||||
val yb = b.y
|
||||
val zb = b.z
|
||||
val distB = sqrt(xb * xb.toDouble() + yb * yb.toDouble() + zb * zb.toDouble())
|
||||
|
||||
if (distA == distB) {
|
||||
return@sortWith 0
|
||||
} else if (distA > distB) {
|
||||
return@sortWith 1
|
||||
} else {
|
||||
return@sortWith -1
|
||||
}
|
||||
}
|
||||
|
||||
return@computeIfAbsent arr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,14 @@ package ru.dbotthepony.mc.otm.core
|
||||
|
||||
import com.mojang.math.Quaternion
|
||||
import com.mojang.math.Vector3f
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.lang.ref.SoftReference
|
||||
import kotlin.math.*
|
||||
|
||||
typealias Vector = Vec3
|
||||
@ -376,6 +380,9 @@ operator fun Vec3i.times(int: Int): Vec3i = this.multiply(int)
|
||||
operator fun Direction.times(int: Int): Vec3i = this.normal.multiply(int)
|
||||
operator fun Vec3i.times(double: Double): Vector = Vector(x * double, y * double, z * double)
|
||||
|
||||
fun Vec3.toIntVector() = Vec3i(x.toInt(), y.toInt(), z.toInt())
|
||||
fun Vec3.roundToIntVector() = Vec3i(x.roundToInt(), y.roundToInt(), z.roundToInt())
|
||||
|
||||
fun BlockPos.asVector(): Vector {
|
||||
return Vector(x + 0.5, y + 0.5, z + 0.5)
|
||||
}
|
||||
@ -383,3 +390,61 @@ fun BlockPos.asVector(): Vector {
|
||||
operator fun Direction.unaryMinus(): Direction = this.opposite
|
||||
operator fun Vec3i.unaryMinus(): Vec3i = Vec3i(-x, -y, -z)
|
||||
operator fun BlockPos.unaryMinus(): BlockPos = BlockPos(-x, -y, -z)
|
||||
|
||||
private data class EllipsoidShapeCacheKey(val x: Int, val y: Int, val z: Int) : Comparable<EllipsoidShapeCacheKey> {
|
||||
override fun compareTo(other: EllipsoidShapeCacheKey): Int {
|
||||
return x.compareTo(other.x).let { if (it != 0) it else y.compareTo(other.y).let { if (it != 0) it else z.compareTo(other.z) } }
|
||||
}
|
||||
}
|
||||
|
||||
private val blockShapeCache = Object2ObjectAVLTreeMap<EllipsoidShapeCacheKey, SoftReference<List<BlockPos>>>(EllipsoidShapeCacheKey::compareTo)
|
||||
|
||||
fun getSphericalBlockPositions(size: Int): List<BlockPos> {
|
||||
return getEllipsoidBlockPositions(size, size, size)
|
||||
}
|
||||
|
||||
fun getEllipsoidBlockPositions(x: Int, y: Int, z: Int): List<BlockPos> {
|
||||
val getResult = blockShapeCache[EllipsoidShapeCacheKey(x, y, z)]?.get()
|
||||
|
||||
if (getResult != null) {
|
||||
return getResult
|
||||
}
|
||||
|
||||
val result = ArrayList<BlockPos>((x * y * z * Math.PI * (4.0 / 3.0)).toInt() + 16)
|
||||
|
||||
val xPow = x.toDouble().pow(2.0)
|
||||
val yPow = y.toDouble().pow(2.0)
|
||||
val zPow = z.toDouble().pow(2.0)
|
||||
|
||||
for (ellipsoidX in -x..x) {
|
||||
for (ellipsoidY in -y..y) {
|
||||
for (ellipsoidZ in -z..z) {
|
||||
if (
|
||||
ellipsoidX.toDouble().pow(2.0) / xPow +
|
||||
ellipsoidY.toDouble().pow(2.0) / yPow +
|
||||
ellipsoidZ.toDouble().pow(2.0) / zPow <= 1.0
|
||||
) {
|
||||
result.add(BlockPos(ellipsoidX, ellipsoidY, ellipsoidZ))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.sortWith { a, b ->
|
||||
val xa = a.x
|
||||
val ya = a.y
|
||||
val za = a.z
|
||||
val distA = sqrt(xa * xa.toDouble() + ya * ya.toDouble() + za * za.toDouble())
|
||||
|
||||
val xb = b.x
|
||||
val yb = b.y
|
||||
val zb = b.z
|
||||
val distB = sqrt(xb * xb.toDouble() + yb * yb.toDouble() + zb * zb.toDouble())
|
||||
|
||||
return@sortWith distA.compareTo(distB)
|
||||
}
|
||||
|
||||
val immutableList = com.google.common.collect.ImmutableList.copyOf(result)
|
||||
blockShapeCache[EllipsoidShapeCacheKey(x, y, z)] = SoftReference(immutableList)
|
||||
return immutableList
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package ru.dbotthepony.mc.otm.core
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.ByteArrayTag
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
@ -14,6 +15,8 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateHolder
|
||||
import net.minecraft.world.level.block.state.properties.Property
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@ -344,3 +347,17 @@ fun <T> List<T>.toImmutableList(): ImmutableList<T> {
|
||||
operator fun <R> (() -> R).getValue(thisRef: Any, property: KProperty<*>): R {
|
||||
return invoke()
|
||||
}
|
||||
|
||||
fun BlockState.getExplosionResistance(level: BlockGetter, pos: BlockPos): Float {
|
||||
return try {
|
||||
getExplosionResistance(level, pos, null)
|
||||
} catch (err: NullPointerException) {
|
||||
block.explosionResistance
|
||||
// Потому что возможно какой-либо мод не ожидает что Explosion == null
|
||||
// особенно учитывая что интерфейс IForgeBlock не имеет @ParamsAreNonnullByDefault
|
||||
// и аргумент не помечен как @Nullable
|
||||
// тем самым имеет тип Explosion! который указывается как Explosion? .. Explosion!!
|
||||
} catch (err: IllegalArgumentException) {
|
||||
block.explosionResistance
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.android.AndroidFeatureType
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearch
|
||||
import ru.dbotthepony.mc.otm.android.AndroidResearchType
|
||||
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
|
||||
import ru.dbotthepony.mc.otm.android.feature.ShockwaveFeature
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.client.MatteryGUI
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
@ -353,6 +354,23 @@ class SwitchAndroidFeaturePacket(val type: AndroidFeatureType<*>, val newState:
|
||||
}
|
||||
}
|
||||
|
||||
object TriggerShockwavePacket : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
// no op
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.packetHandled = true
|
||||
context.enqueueWork {
|
||||
val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) as ShockwaveFeature? ?: return@enqueueWork
|
||||
|
||||
if (shockwave.cooldown <= 0 && shockwave.isActive && shockwave.airTicks > 0) {
|
||||
shockwave.shockwave()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
||||
version = "1",
|
||||
name = "player"
|
||||
@ -375,5 +393,6 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
||||
add(ExoSuitMenuClose::class, { ExoSuitMenuClose }, PLAY_TO_SERVER)
|
||||
|
||||
add(SwitchAndroidFeaturePacket::class, SwitchAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER)
|
||||
add(TriggerShockwavePacket::class, { TriggerShockwavePacket }, PLAY_TO_SERVER)
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ object AndroidFeatures {
|
||||
val NANOBOTS_ARMOR: AndroidFeatureType<*> by registry.register(MNames.NANOBOTS_ARMOR) { AndroidFeatureType(::NanobotsArmor) }
|
||||
val EXTENDED_REACH: AndroidFeatureType<*> by registry.register(MNames.EXTENDED_REACH) { AndroidFeatureType(::ExtendedReach) }
|
||||
val NIGHT_VISION: AndroidFeatureType<*> by registry.register(MNames.NIGHT_VISION) { AndroidFeatureType(::NightVisionFeature) }
|
||||
val SHOCKWAVE: AndroidFeatureType<*> by registry.register(MNames.SHOCKWAVE) { AndroidFeatureType(::ShockwaveFeature) }
|
||||
|
||||
internal fun register(bus: IEventBus) {
|
||||
registry.register(bus)
|
||||
|
@ -260,7 +260,7 @@ object AndroidResearch {
|
||||
|
||||
armorSpeedList.add(registry.register(MNames.NANOBOTS_ARMOR_SPEED_LIST[i]) {
|
||||
AndroidResearchBuilder()
|
||||
.withExperience(20 + i * 8)
|
||||
.withExperience(18 + i * 6)
|
||||
.withIconText(TextComponent((i + 1).toString()))
|
||||
.withIcon(ICON_ARMOR)
|
||||
.addPrerequisite(OverdriveThatMatters.loc(if (i > 0) MNames.NANOBOTS_ARMOR_SPEED_LIST[i - 1] else MNames.NANOBOTS_ARMOR))
|
||||
@ -290,4 +290,14 @@ object AndroidResearch {
|
||||
NANOBOTS_ARMOR_STRENGTH = RegistryObjectList(armorStrengthList)
|
||||
ATTACK_BOOST = RegistryObjectList(attackBoostList)
|
||||
}
|
||||
|
||||
val SHOCKWAVE: AndroidResearchType<*> by registry.register(MNames.SHOCKWAVE) {
|
||||
AndroidResearchBuilder()
|
||||
.withExperience(40)
|
||||
.withDescription()
|
||||
.withIcon(ICON_SHOCKWAVE)
|
||||
.addFeatureResult(AndroidFeatures.SHOCKWAVE)
|
||||
.addPrerequisite(ATTACK_BOOST[2])
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
@ -169,6 +169,16 @@ class EMPDamageSource(entity: Entity? = null, inflictor: ItemStack? = null) : Ma
|
||||
}
|
||||
}
|
||||
|
||||
class ShockwaveDamageSource(entity: Entity? = null, inflictor: ItemStack? = null) : MatteryDamageSource(MRegistry.DAMAGE_SHOCKWAVE_NAME, entity, inflictor) {
|
||||
init {
|
||||
bypassArmor()
|
||||
}
|
||||
|
||||
override fun scalesWithDifficulty(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class PlasmaDamageSource(entity: Entity? = null, inflictor: ItemStack? = null) : MatteryDamageSource(MRegistry.DAMAGE_PLASMA_NAME, entity, inflictor) {
|
||||
override fun scalesWithDifficulty(): Boolean {
|
||||
return false
|
||||
|
@ -208,6 +208,7 @@ object MNames {
|
||||
|
||||
const val EXTENDED_REACH = "extended_reach"
|
||||
const val NIGHT_VISION = "night_vision"
|
||||
const val SHOCKWAVE = "shockwave"
|
||||
const val IMPROVED_LIMBS = "improved_limbs"
|
||||
|
||||
// stats
|
||||
|
@ -211,6 +211,7 @@ object MRegistry {
|
||||
val DAMAGE_EVENT_HORIZON = ImmutableDamageSource(DamageSource(DAMAGE_EVENT_HORIZON_ID).bypassMagic().bypassArmor())
|
||||
val DAMAGE_HAWKING_RADIATION = ImmutableDamageSource(DamageSource(DAMAGE_HAWKING_RADIATION_ID))
|
||||
const val DAMAGE_EMP_NAME = "otm_emp"
|
||||
const val DAMAGE_SHOCKWAVE_NAME = "otm_shockwave"
|
||||
const val DAMAGE_PLASMA_NAME = "otm_plasma"
|
||||
val DAMAGE_EMP: DamageSource = ImmutableDamageSource(EMPDamageSource())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user