Skip to content

Commit

Permalink
Various
Browse files Browse the repository at this point in the history
  • Loading branch information
TheCymaera committed May 15, 2024
1 parent 6d80680 commit 01d520d
Show file tree
Hide file tree
Showing 20 changed files with 2,517 additions and 963 deletions.
23 changes: 15 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,16 @@
</repositories>

<dependencies>
<!-- <dependency>-->
<!-- <groupId>io.papermc.paper</groupId>-->
<!-- <artifactId>paper-api</artifactId>-->
<!-- <version>1.20.4-R0.1-SNAPSHOT</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<!-- Spigot -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
Expand All @@ -93,11 +100,11 @@
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.jetbrains.kotlin</groupId>-->
<!-- <artifactId>kotlin-test</artifactId>-->
<!-- <version>${kotlin.version}</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
</dependencies>
</project>
195 changes: 195 additions & 0 deletions src/main/java/com/heledron/spideranimation/BodyPlan.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package com.heledron.spideranimation

import com.heledron.spideranimation.components.Leg
import org.bukkit.util.Vector

interface SpiderBodyPlan {
val scale: Double
val legs: List<LegPlan>
fun initialize(spider: Spider)
fun canMoveLeg(leg: Leg): Boolean
fun legsInPolygonalOrder(): List<Leg>
fun legsInUpdateOrder(): List<Leg>
}

class LegPlan(
val attachmentPosition: Vector,
val restPosition: Vector,
val segments: List<SegmentPlan>,
)

class SegmentPlan(
val length: Double,
val thickness: Double,
)

class SymmetricalBodyPlan(override val scale: Double, override val legs: List<LegPlan>): SpiderBodyPlan {
lateinit var spider: Spider

private var legsInPolygonalOrder = listOf<Leg>()
private var legsInUpdateOrder = listOf<Leg>()

override fun initialize(spider: Spider) {
this.spider = spider

val diagonals1 = arrayListOf<Leg>()
val diagonals2 = arrayListOf<Leg>()

val lefts = arrayListOf<Leg>()
val rights = arrayListOf<Leg>()
for (i in spider.body.legs.indices step 2) {
val left = spider.body.legs[i]
val right = spider.body.legs[i + 1]
lefts.add(left)
rights.add(right)

if (i % 4 == 0) {
diagonals1.add(left)
diagonals2.add(right)
} else {
diagonals2.add(left)
diagonals1.add(right)
}
}

legsInPolygonalOrder = lefts + rights.reversed()
legsInUpdateOrder = diagonals1 + diagonals2
}

override fun legsInPolygonalOrder(): List<Leg> {
return legsInPolygonalOrder
}

override fun legsInUpdateOrder(): List<Leg> {
return legsInUpdateOrder
}

override fun canMoveLeg(leg: Leg): Boolean {
if (leg.target.isGrounded) return true

val cooldownLegs: List<Leg>
if (spider.isGalloping) {
// always move if uncomfortable
if (leg.uncomfortable) return true

cooldownLegs = listOf(horizontal(leg))
} else {
// only move when the adjacent legs are grounded
for (adjacent in adjacent(leg)) {
if (adjacent.isMoving) return false
}

cooldownLegs = diagonal(leg)
}

// cooldown
for (opposite in cooldownLegs) {
if (opposite.isMoving && !opposite.target.isGrounded && opposite.moveTime < spider.gait.legMoveCooldown) {
return false
}
}

return true
}

// x .
// . x
// x .
private fun horizontal(leg: Leg): Leg {
val index = spider.body.legs.indexOf(leg)
val out = spider.body.legs.getOrNull(index + if (index % 2 == 0) 1 else -1)
return out ?: leg
}

private fun diagonal(leg: Leg): List<Leg> {
val index = spider.body.legs.indexOf(leg)
val (front, back) = if (index % 2 == 0) -1 to 3 else -3 to 1
return listOfNotNull(spider.body.legs.getOrNull(index + front), spider.body.legs.getOrNull(index + back))
}

private fun adjacent(leg: Leg): List<Leg> {
val pair = horizontal(leg)
return diagonal(pair) + pair
}
}

class SymmetricalBodyPlanBuilder(var scale: Double = 1.0, var legs: MutableList<LegPlan> = arrayListOf()) {
fun addPair(rootX: Double, rootZ: Double, restX: Double, restZ: Double, segmentLength: Double, segmentCount: Int) {
val segmentPlan = SegmentPlan(segmentLength, .1)
legs.add(LegPlan(Vector(rootX, 0.0, rootZ), Vector(restX, 0.0, restZ), List(segmentCount) { segmentPlan }))
legs.add(LegPlan(Vector(-rootX, 0.0, rootZ), Vector(-restX, 0.0, restZ), List(segmentCount) { segmentPlan }))
}

fun autoAssignThickness() {
val maxThickness = 1.5/16 * 4
val minThickness = 1.5/16 * 1

legs = legs.map { legPlan ->
val segmentCount = legs.first().segments.size
val segments = legPlan.segments.mapIndexed { i, segmentPlan ->
val thickness = (segmentCount - i - 1) * (maxThickness - minThickness) / segmentCount + minThickness
SegmentPlan(segmentPlan.length, thickness)
}
LegPlan(legPlan.attachmentPosition, legPlan.restPosition, segments)
}.toMutableList()
}

fun scale(scale: Double) {
this.scale *= scale
legs = legs.map { legPlan ->
val attachmentPosition = legPlan.attachmentPosition.clone().multiply(scale)
val restPosition = legPlan.restPosition.clone().multiply(scale)
val segments = legPlan.segments.map { SegmentPlan(it.length * scale, it.thickness * scale) }
LegPlan(attachmentPosition, restPosition, segments)
}.toMutableList()
}

// fun addSpace(left: Double, right: Double, forward: Double, backward: Double) {
// legs.forEach { legPlan ->
// val z = .5 * if (legPlan.restPosition.z > 0) forward else -backward
// val x = .5 * if (legPlan.restPosition.x > 0) left else -right
// legPlan.attachmentPosition.add(Vector(x, 0.0, z))
// legPlan.restPosition.add(Vector(x, 0.0, z))
// }
// }
//
// fun liftAttachment(front: Double, back: Double) {
// legs.forEach { legPlan ->
// val y = .5 * if (legPlan.restPosition.z > 0) front else back
// legPlan.attachmentPosition.y += y
// }
// }

fun create(): SpiderBodyPlan {
return SymmetricalBodyPlan(scale, legs)
}
}

fun quadripedBodyPlan(segmentLength: Double, segmentCount: Int): SymmetricalBodyPlanBuilder {
return SymmetricalBodyPlanBuilder().apply {
addPair(.0, .0, 0.9, 0.9, 0.9 * segmentLength, segmentCount)
addPair(.0, .0, 1.0, -1.1, 1.2 * segmentLength, segmentCount)
autoAssignThickness()
// addSpace(.5, .5, 1.0, 1.0)
// liftAttachment(-.1, .3)
}
}

fun hexapodBodyPlan(segmentLength: Double, segmentCount: Int): SymmetricalBodyPlanBuilder {
return SymmetricalBodyPlanBuilder().apply {
addPair(.0, 0.1, 1.0, 1.1, 1.1 * segmentLength, segmentCount)
addPair(.0, 0.0, 1.3, -0.3, 1.1 * segmentLength, segmentCount)
addPair(.0, -.1, 1.2, -2.0, 1.6 * segmentLength, segmentCount)
autoAssignThickness()
}
}

fun octopodBodyPlan(segmentLength: Double, segmentCount: Int): SymmetricalBodyPlanBuilder {
return SymmetricalBodyPlanBuilder().apply {
addPair(.0, 0.1, 1.0, 1.6, 1.1 * segmentLength, segmentCount)
addPair(.0, 0.0, 1.3, 0.4, 1.0 * segmentLength, segmentCount)
addPair(.0, -.1, 1.3, -0.9, 1.1 * segmentLength, segmentCount)
addPair(.0, -.2, 1.1, -2.5, 1.6 * segmentLength, segmentCount)
autoAssignThickness()
}
}
151 changes: 151 additions & 0 deletions src/main/java/com/heledron/spideranimation/EntityRenderer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.heledron.spideranimation

import org.bukkit.Location
import org.bukkit.entity.BlockDisplay
import org.bukkit.entity.Entity
import org.bukkit.util.Vector
import org.joml.Matrix4f
import java.io.Closeable

class EntityRendererTemplate <T : Entity> (
val clazz : Class<T>,
val location : Location,
val init : (T) -> Unit = {},
val update : (T) -> Unit = {}
)

fun blockTemplate(
location: Location,
init: (BlockDisplay) -> Unit = {},
update: (BlockDisplay) -> Unit = {}
) = EntityRendererTemplate(
clazz = BlockDisplay::class.java,
location = location,
init = init,
update = update
)

fun targetTemplate(
location: Location
) = blockTemplate(
location = location,
init = {
it.block = org.bukkit.Material.REDSTONE_BLOCK.createBlockData()
it.teleportDuration = 1
it.brightness = org.bukkit.entity.Display.Brightness(15, 15)
it.transformation = centredTransform(.25f, .25f, .25f)
}
)

fun lineTemplate(
location: Location,
vector: Vector,
upVector: Vector = if (vector.x + vector.z != 0.0) UP_VECTOR else Vector(0, 0, 1),
thickness: Float = .1f,
interpolation: Int = 1,
init: (BlockDisplay) -> Unit = {},
update: (BlockDisplay) -> Unit = {}
) = blockTemplate(
location = location,
init = {
it.teleportDuration = interpolation
it.interpolationDuration = interpolation
init(it)
},
update = {
val matrix = Matrix4f().rotateTowards(vector.toVector3f(), upVector.toVector3f())
.translate(-thickness / 2, -thickness / 2, 0f)
.scale(thickness, thickness, vector.length().toFloat())

applyTransformationWithInterpolation(it, matrix)
update(it)
}
)

class EntityRenderer<T : Entity>: Closeable {
var entity: T? = null

fun render(template: EntityRendererTemplate<T>) {
entity = (entity ?: spawnEntity(template.location, template.clazz) {
template.init(it)
}).apply {
this.teleport(template.location)
template.update(this)
}
}

fun renderIf(predicate: Boolean, template: EntityRendererTemplate<T>) {
if (predicate) render(template) else close()
}

override fun close() {
entity?.remove()
entity = null
}
}

class MultiEntityRenderer: Closeable {
val rendered = mutableMapOf<Any, Entity>()

val used = mutableSetOf<Any>()

override fun close() {
for (entity in rendered.values) {
entity.remove()
}
rendered.clear()
used.clear()
}

fun beginRender() {
if (used.isNotEmpty()) {
throw IllegalStateException("beginRender called without finishRender")
}
}

fun keepAlive(id: Any) {
used.add(id)
}

fun finishRender() {
val toRemove = rendered.keys - used
for (key in toRemove) {
val entity = rendered[key]!!
entity.remove()
rendered.remove(key)
}
used.clear()
}

fun <T: Entity>render(id: Any, template: EntityRendererTemplate<T>) {
used.add(id)

val oldEntity = rendered[id]
if (oldEntity != null) {
// check if the entity is of the same type
if (oldEntity.type.entityClass == template.clazz) {
oldEntity.teleport(template.location)
@Suppress("UNCHECKED_CAST")
template.update(oldEntity as T)
return
}

oldEntity.remove()
rendered.remove(id)
}

val entity = spawnEntity(template.location, template.clazz) {
template.init(it)
template.update(it)
}
rendered[id] = entity
}

fun renderList(id: Any, list: List<EntityRendererTemplate<*>>) {
for ((i, template) in list.withIndex()) {
render(id to i, template)
}
}
}


6 changes: 2 additions & 4 deletions src/main/java/com/heledron/spideranimation/KinematicChain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@ class KinematicChain(
}
}

fun straighten(target: Vector, height: Double) {
val direction = target.clone().subtract(root).normalize()
direction.y += height
fun straightenDirection(direction: Vector) {
direction.normalize()

// val direction = target.clone().subtract(root).normalize()
val position = root.clone()
for (segment in segments) {
position.add(direction.clone().multiply(segment.length))
Expand Down
Loading

0 comments on commit 01d520d

Please sign in to comment.