KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/lua/bindings/MovementControllerBindings.kt

462 lines
17 KiB
Kotlin

package ru.dbotthepony.kstarbound.lua.bindings
import com.google.gson.JsonNull
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.ActorMovementParameters
import ru.dbotthepony.kstarbound.defs.actor.ActorMovementModifiers
import ru.dbotthepony.kstarbound.fromJsonFast
import ru.dbotthepony.kstarbound.lua.LuaThread
import ru.dbotthepony.kstarbound.lua.nextVector2d
import ru.dbotthepony.kstarbound.lua.push
import ru.dbotthepony.kstarbound.lua.setTableValue
import ru.dbotthepony.kstarbound.math.vector.Vector2d
import ru.dbotthepony.kstarbound.world.Direction
import ru.dbotthepony.kstarbound.world.entities.ActorMovementController
import ru.dbotthepony.kstarbound.world.entities.AnchorNetworkState
import ru.dbotthepony.kstarbound.world.physics.Poly
import kotlin.math.PI
class MovementControllerBindings(val self: ActorMovementController) {
private fun mass(args: LuaThread.ArgStack): Int {
args.lua.push(self.mass)
return 1
}
private fun localBoundBox(args: LuaThread.ArgStack): Int {
args.lua.push(self.computeLocalCollisionAABB())
return 1
}
// TODO
private fun boundBox(args: LuaThread.ArgStack): Int {
args.lua.push(self.computeLocalCollisionAABB())
return 1
}
private fun collisionBoundBox(args: LuaThread.ArgStack): Int {
args.lua.push(self.computeGlobalCollisionAABB())
return 1
}
private fun collisionPoly(args: LuaThread.ArgStack): Int {
args.lua.push(self.movementParameters.collisionPoly?.map({ it }, { it.firstOrNull() }) ?: Poly.EMPTY)
return 1
}
private fun collisionPolies(args: LuaThread.ArgStack): Int {
val result = self.movementParameters.collisionPoly?.map({ listOf(it) }, { it }) ?: listOf(Poly.EMPTY)
args.lua.pushTable(result.size)
for ((i, v) in result.withIndex())
args.lua.setTableValue(i + 1L, v)
return 1
}
private fun collisionBody(args: LuaThread.ArgStack): Int {
args.lua.push(self.computeGlobalHitboxes().firstOrNull() ?: Poly.EMPTY)
return 1
}
private fun collisionBodies(args: LuaThread.ArgStack): Int {
val result = self.computeGlobalHitboxes()
args.lua.pushTable(result.size)
for ((i, v) in result.withIndex())
args.lua.setTableValue(i + 1L, v)
return 1
}
private fun position(args: LuaThread.ArgStack): Int { args.lua.push(self.position); return 1 }
private fun xPosition(args: LuaThread.ArgStack): Int { args.lua.push(self.xPosition); return 1 }
private fun yPosition(args: LuaThread.ArgStack): Int { args.lua.push(self.yPosition); return 1 }
private fun velocity(args: LuaThread.ArgStack): Int { args.lua.push(self.velocity); return 1 }
private fun xVelocity(args: LuaThread.ArgStack): Int { args.lua.push(self.xVelocity); return 1 }
private fun yVelocity(args: LuaThread.ArgStack): Int { args.lua.push(self.yVelocity); return 1 }
private fun rotation(args: LuaThread.ArgStack): Int { args.lua.push(self.rotation); return 1 }
private fun isColliding(args: LuaThread.ArgStack): Int { args.lua.push(self.isColliding); return 1 }
private fun isNullColliding(args: LuaThread.ArgStack): Int { args.lua.push(self.isCollidingWithNull); return 1 }
private fun isCollisionStuck(args: LuaThread.ArgStack): Int { args.lua.push(self.isCollisionStuck); return 1 }
private fun stickingDirection(args: LuaThread.ArgStack): Int { args.lua.push(self.stickingDirection); return 1 }
private fun liquidPercentage(args: LuaThread.ArgStack): Int { args.lua.push(self.liquidPercentage); return 1 }
private fun liquidId(args: LuaThread.ArgStack): Int { args.lua.push(self.liquid?.id?.toLong() ?: 0L); return 1 }
private fun liquidName(args: LuaThread.ArgStack): Int { args.lua.push(self.liquid?.key); return 1 }
private fun onGround(args: LuaThread.ArgStack): Int { args.lua.push(self.isOnGround); return 1 }
private fun zeroG(args: LuaThread.ArgStack): Int { args.lua.push(self.isZeroGravity); return 1 }
private fun atWorldLimit(args: LuaThread.ArgStack): Int {
args.lua.push(self.isAtWorldLimit(args.nextBoolean()))
return 1
}
private fun setAnchorState(args: LuaThread.ArgStack): Int {
self.anchorNetworkState = AnchorNetworkState(args.nextInt(), args.nextInt())
return 0
}
private fun resetAnchorState(args: LuaThread.ArgStack): Int {
self.anchorNetworkState = null
return 0
}
private fun anchorState(args: LuaThread.ArgStack): Int {
val anchorState = self.anchorNetworkState
if (anchorState != null) {
args.lua.push(anchorState.entityID.toLong())
args.lua.push(anchorState.positionIndex.toLong())
return 2
} else {
return 0
}
}
private fun setPosition(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.position = args.nextVector2d()
return 0
}
private fun translate(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.position += args.nextVector2d()
return 0
}
private fun setXPosition(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.xPosition = args.nextDouble()
return 0
}
private fun setYPosition(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.yPosition = args.nextDouble()
return 0
}
private fun setVelocity(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.velocity = args.nextVector2d()
return 0
}
private fun setXVelocity(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.xVelocity = args.nextDouble()
return 0
}
private fun setYVelocity(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.yVelocity = args.nextDouble()
return 0
}
private fun addMomentum(args: LuaThread.ArgStack): Int {
resetPathMove = true
if (self.mass != 0.0) // let's not collapse into black hole
self.velocity += args.nextVector2d() / self.mass
return 0
}
private fun setRotation(args: LuaThread.ArgStack): Int {
resetPathMove = true
self.rotation = args.nextDouble()
return 0
}
private fun baseParameters(args: LuaThread.ArgStack): Int { args.lua.push(Starbound.gson.toJsonTree(self.actorMovementParameters)); return 1 }
private fun walking(args: LuaThread.ArgStack): Int { args.lua.push(self.isWalking); return 1 }
private fun running(args: LuaThread.ArgStack): Int { args.lua.push(self.isRunning); return 1 }
private fun movingDirection(args: LuaThread.ArgStack): Int { args.lua.push(self.movingDirection.numericalValue); return 1 }
private fun facingDirection(args: LuaThread.ArgStack): Int { args.lua.push(self.facingDirection.numericalValue); return 1 }
private fun crouching(args: LuaThread.ArgStack): Int { args.lua.push(self.isCrouching); return 1 }
private fun flying(args: LuaThread.ArgStack): Int { args.lua.push(self.isFlying); return 1 }
private fun falling(args: LuaThread.ArgStack): Int { args.lua.push(self.isFalling); return 1 }
private fun canJump(args: LuaThread.ArgStack): Int { args.lua.push(self.canJump); return 1 }
private fun jumping(args: LuaThread.ArgStack): Int { args.lua.push(self.isJumping); return 1 }
private fun groundMovement(args: LuaThread.ArgStack): Int { args.lua.push(self.isGroundMovement); return 1 }
private fun liquidMovement(args: LuaThread.ArgStack): Int { args.lua.push(self.isLiquidMovement); return 1 }
// controls, stored locally, reset automatically or are persistent
private fun controlRotation(args: LuaThread.ArgStack): Int {
controlRotationRate += args.nextDouble()
return 0
}
private fun controlAcceleration(args: LuaThread.ArgStack): Int {
controlAcceleration += args.nextVector2d()
return 0
}
private fun controlForce(args: LuaThread.ArgStack): Int {
controlForce += args.nextVector2d()
return 0
}
private fun controlApproachVelocity(args: LuaThread.ArgStack): Int {
controlApproachVelocity = ActorMovementController.ApproachVelocityCommand(args.nextVector2d(), args.nextDouble())
return 0
}
private fun controlApproachVelocityAlongAngle(args: LuaThread.ArgStack): Int {
controlApproachVelocityAlongAngle = ActorMovementController.ApproachVelocityAngleCommand(args.nextDouble(), args.nextDouble(), args.nextDouble(), args.nextBoolean())
return 0
}
private fun controlApproachXVelocity(args: LuaThread.ArgStack): Int {
controlApproachVelocityAlongAngle = ActorMovementController.ApproachVelocityAngleCommand(0.0, args.nextDouble(), args.nextDouble(), false)
return 0
}
private fun controlApproachYVelocity(args: LuaThread.ArgStack): Int {
controlApproachVelocityAlongAngle = ActorMovementController.ApproachVelocityAngleCommand(PI / 2.0, args.nextDouble(), args.nextDouble(), false)
return 0
}
private fun controlParameters(args: LuaThread.ArgStack): Int {
controlParameters = controlParameters.merge(Starbound.gson.fromJsonFast(args.nextJson(), ActorMovementParameters::class.java))
return 0
}
private fun controlModifiers(args: LuaThread.ArgStack): Int {
controlModifiers = controlModifiers.merge(Starbound.gson.fromJsonFast(args.nextJson(), ActorMovementModifiers::class.java))
return 0
}
private fun controlMove(args: LuaThread.ArgStack): Int {
// why?
val new = Direction.valueOf(args.nextDouble())
val shouldRun = args.nextOptionalBoolean()
if (new != null) {
controlMove = new
controlShouldRun = shouldRun ?: false
}
return 0
}
private fun controlFace(args: LuaThread.ArgStack): Int {
// why?
val new = Direction.valueOf(args.nextDouble())
if (new != null)
controlFace = new
return 0
}
private fun controlDown(args: LuaThread.ArgStack): Int { controlDown = true; return 0 }
private fun controlCrouch(args: LuaThread.ArgStack): Int { controlCrouch = true; return 0 }
private fun controlHoldJump(args: LuaThread.ArgStack): Int { controlHoldJump = true; return 0 }
private fun controlJump(args: LuaThread.ArgStack): Int { controlJump = args.nextBoolean(); return 0 }
private fun controlFly(args: LuaThread.ArgStack): Int { controlFly = args.nextVector2d(); return 0 }
private fun controlPathMove(args: LuaThread.ArgStack): Int {
val position = args.nextVector2d()
if (pathMoveResult?.first == position) {
val pathMoveResult = this.pathMoveResult!!
this.pathMoveResult = null
args.lua.push(pathMoveResult.second)
} else {
pathMoveResult = null
val run = args.nextOptionalBoolean() == true
val parameters = args.nextOptionalJson()
val result = self.pathMove(position, run, Starbound.gson.fromJsonFast(parameters ?: JsonNull.INSTANCE))
if (result == null) {
controlPathMove = position to false
}
args.lua.push(result?.second)
}
return 1
}
private fun pathfinding(args: LuaThread.ArgStack): Int {
args.lua.push(self.pathController.isPathfinding)
return 1
}
private fun autoClearControls(args: LuaThread.ArgStack): Int {
args.lua.push(autoClearControls)
return 1
}
private fun setAutoClearControls(args: LuaThread.ArgStack): Int {
autoClearControls = args.nextBoolean()
return 0
}
private fun clearControls(args: LuaThread.ArgStack): Int {
clearControls()
return 0
}
fun init(lua: LuaThread) {
lua.pushTable()
lua.dup()
lua.storeGlobal("mcontroller")
lua.setTableValue("mass", ::mass)
lua.setTableValue("localBoundBox", ::localBoundBox)
lua.setTableValue("boundBox", ::boundBox)
lua.setTableValue("collisionBoundBox", ::collisionBoundBox)
lua.setTableValue("collisionPoly", ::collisionPoly)
lua.setTableValue("collisionPolies", ::collisionPolies)
lua.setTableValue("collisionBody", ::collisionBody)
lua.setTableValue("collisionBodies", ::collisionBodies)
lua.setTableValue("position", ::position)
lua.setTableValue("xPosition", ::xPosition)
lua.setTableValue("yPosition", ::yPosition)
lua.setTableValue("velocity", ::velocity)
lua.setTableValue("xVelocity", ::xVelocity)
lua.setTableValue("yVelocity", ::yVelocity)
lua.setTableValue("rotation", ::rotation)
lua.setTableValue("isColliding", ::isColliding)
lua.setTableValue("isNullColliding", ::isNullColliding)
lua.setTableValue("isCollisionStuck", ::isCollisionStuck)
lua.setTableValue("stickingDirection", ::stickingDirection)
lua.setTableValue("liquidPercentage", ::liquidPercentage)
lua.setTableValue("liquidId", ::liquidId)
lua.setTableValue("liquidName", ::liquidName)
lua.setTableValue("onGround", ::onGround)
lua.setTableValue("zeroG", ::zeroG)
lua.setTableValue("atWorldLimit", ::atWorldLimit)
lua.setTableValue("setAnchorState", ::setAnchorState)
lua.setTableValue("resetAnchorState", ::resetAnchorState)
lua.setTableValue("anchorState", ::anchorState)
lua.setTableValue("setPosition", ::setPosition)
lua.setTableValue("setXPosition", ::setXPosition)
lua.setTableValue("setYPosition", ::setYPosition)
lua.setTableValue("translate", ::translate)
lua.setTableValue("setVelocity", ::setVelocity)
lua.setTableValue("setXVelocity", ::setXVelocity)
lua.setTableValue("setYVelocity", ::setYVelocity)
lua.setTableValue("addMomentum", ::addMomentum)
lua.setTableValue("setRotation", ::setRotation)
lua.setTableValue("baseParameters", ::baseParameters)
lua.setTableValue("walking", ::walking)
lua.setTableValue("running", ::running)
lua.setTableValue("movingDirection", ::movingDirection)
lua.setTableValue("facingDirection", ::facingDirection)
lua.setTableValue("crouching", ::crouching)
lua.setTableValue("flying", ::flying)
lua.setTableValue("falling", ::falling)
lua.setTableValue("canJump", ::canJump)
lua.setTableValue("jumping", ::jumping)
lua.setTableValue("groundMovement", ::groundMovement)
lua.setTableValue("liquidMovement", ::liquidMovement)
lua.setTableValue("controlRotation", ::controlRotation)
lua.setTableValue("controlAcceleration", ::controlAcceleration)
lua.setTableValue("controlForce", ::controlForce)
lua.setTableValue("controlApproachVelocity", ::controlApproachVelocity)
lua.setTableValue("controlApproachVelocityAlongAngle", ::controlApproachVelocityAlongAngle)
lua.setTableValue("controlApproachXVelocity", ::controlApproachXVelocity)
lua.setTableValue("controlApproachYVelocity", ::controlApproachYVelocity)
lua.setTableValue("controlParameters", ::controlParameters)
lua.setTableValue("controlModifiers", ::controlModifiers)
lua.setTableValue("controlMove", ::controlMove)
lua.setTableValue("controlFace", ::controlFace)
lua.setTableValue("controlDown", ::controlDown)
lua.setTableValue("controlCrouch", ::controlCrouch)
lua.setTableValue("controlHoldJump", ::controlHoldJump)
lua.setTableValue("controlJump", ::controlJump)
lua.setTableValue("controlFly", ::controlFly)
lua.setTableValue("controlPathMove", ::controlPathMove)
lua.setTableValue("pathfinding", ::pathfinding)
lua.setTableValue("autoClearControls", ::autoClearControls)
lua.setTableValue("setAutoClearControls", ::setAutoClearControls)
lua.setTableValue("clearControls", ::clearControls)
lua.pop()
}
private var autoClearControls = true
private var controlRotationRate = 0.0
private var controlAcceleration = Vector2d.ZERO
private var controlForce = Vector2d.ZERO
private var controlApproachVelocity: ActorMovementController.ApproachVelocityCommand? = null
private var controlApproachVelocityAlongAngle: ActorMovementController.ApproachVelocityAngleCommand? = null
private var controlParameters = ActorMovementParameters.EMPTY
private var controlModifiers = ActorMovementModifiers.EMPTY
private var controlMove: Direction? = null
private var controlFace: Direction? = null
private var controlShouldRun: Boolean? = null
private var controlDown = false
private var controlCrouch = false
private var controlJump = false
private var controlHoldJump = false
private var controlFly: Vector2d? = null
private var resetPathMove = false
private var pathMoveResult: Pair<Vector2d, Boolean>? = null
private var controlPathMove: Pair<Vector2d, Boolean>? = null
fun apply() {
self.controlRotationRate += controlRotationRate
self.controlAcceleration += controlAcceleration
self.controlForce += controlForce
if (controlApproachVelocity != null) self.approachVelocities.add(controlApproachVelocity!!)
if (controlApproachVelocityAlongAngle != null) self.approachVelocityAngles.add(controlApproachVelocityAlongAngle!!)
self.controlActorMovementParameters = self.controlActorMovementParameters.merge(controlParameters)
self.controlMovementModifiers = self.controlMovementModifiers.merge(controlModifiers)
if (controlMove != null) self.controlMove = controlMove
if (controlShouldRun != null) self.controlRun = controlShouldRun!!
if (controlFace != null) self.controlFace = controlFace
if (controlDown) self.controlDown = true
if (controlCrouch) self.controlCrouch = true
if (controlJump) self.controlJump = true
if (controlHoldJump && !self.isOnGround) self.controlJump = true
if (controlFly != null) self.controlFly = controlFly
// some action was taken that has priority over pathing, setting position or velocity
if (resetPathMove)
controlPathMove = null
if (controlPathMove != null && pathMoveResult == null)
pathMoveResult = self.controlPathMove(controlPathMove!!.first, controlPathMove!!.second)
}
fun clearControlsIfNeeded() {
if (autoClearControls)
clearControls()
}
private fun clearControls() {
controlRotationRate = 0.0
controlAcceleration = Vector2d.ZERO
controlForce = Vector2d.ZERO
controlApproachVelocity = null
controlApproachVelocityAlongAngle = null
controlParameters = ActorMovementParameters.EMPTY
controlModifiers = ActorMovementModifiers.EMPTY
controlMove = null
controlFace = null
controlShouldRun = null
controlDown = false
controlCrouch = false
controlJump = false
controlHoldJump = false
controlFly = null
pathMoveResult = null
controlPathMove = null
resetPathMove = false
}
}