Remove kbox2d from deps and remove leftover code from previous testing stages
This commit is contained in:
parent
b9975657d4
commit
30b168766d
build.gradle.kts
src/main/kotlin/ru/dbotthepony/kstarbound
Constants.ktMain.ktStarbound.kt
client
defs
math
world
@ -82,8 +82,7 @@ dependencies {
|
||||
implementation("net.java.dev.jna:jna:5.13.0")
|
||||
implementation("com.github.jnr:jnr-ffi:2.2.13")
|
||||
|
||||
implementation("ru.dbotthepony:kbox2d:2.4.1-1.0.2")
|
||||
implementation("ru.dbotthepony:kvector:2.10.2")
|
||||
implementation("ru.dbotthepony:kvector:2.11.0")
|
||||
|
||||
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound
|
||||
|
||||
const val METRES_IN_STARBOUND_UNIT = 0.5
|
||||
const val METRES_IN_STARBOUND_UNITf = 0.5f
|
||||
|
||||
const val PIXELS_IN_STARBOUND_UNITi = 8
|
||||
const val PIXELS_IN_STARBOUND_UNIT = PIXELS_IN_STARBOUND_UNITi.toDouble()
|
||||
const val PIXELS_IN_STARBOUND_UNITf = PIXELS_IN_STARBOUND_UNITi.toFloat()
|
@ -20,6 +20,7 @@ import ru.dbotthepony.kstarbound.io.readVarInt
|
||||
import ru.dbotthepony.kstarbound.util.AssetPathStack
|
||||
import ru.dbotthepony.kstarbound.world.entities.WorldObject
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.ByteArrayInputStream
|
||||
@ -122,12 +123,12 @@ fun main() {
|
||||
val item = Registries.items.values.random()
|
||||
val rand = Random()
|
||||
|
||||
for (i in 0 .. 0) {
|
||||
for (i in 0 .. 128) {
|
||||
val item = ItemEntity(client.world!!, item.value)
|
||||
|
||||
item.position = Vector2d(225.0 + i, 685.0)
|
||||
item.position = Vector2d(225.0 - i, 685.0)
|
||||
item.spawn()
|
||||
item.velocity = Vector2d(0.01, -0.08)
|
||||
item.velocity = Vector2d(rand.nextDouble() * 32.0 - 16.0, rand.nextDouble() * 32.0 - 16.0)
|
||||
//item.movement.applyVelocity(Vector2d(rand.nextDouble() * 1000.0 - 500.0, rand.nextDouble() * 1000.0 - 500.0))
|
||||
}
|
||||
|
||||
@ -164,53 +165,6 @@ fun main() {
|
||||
client.font.render("World chunk: ${client.world!!.chunkFromCell(client.camera.pos)}", y = 180f, scale = 0.25f)
|
||||
}
|
||||
|
||||
var p = Poly(Starbound.gson.fromJson<List<Vector2d>>("""[ [1.75, 2.55], [2.25, 2.05], [2.75, -3.55], [2.25, -3.95], [-2.25, -3.95], [-2.75, -3.55], [-2.25, 2.05], [-1.75, 2.55] ]""", TypeToken.getParameterized(ImmutableList::class.java, Vector2d::class.java).type))
|
||||
val polies = ArrayList<Poly>()
|
||||
|
||||
val box = Poly(listOf(Vector2d(-0.5, -0.5), Vector2d(-0.5, 0.5), Vector2d(0.5, 0.5), Vector2d(0.5, -0.5)))
|
||||
p = box
|
||||
val triangle = Poly(listOf(Vector2d(-0.5, -0.5), Vector2d(0.5, 0.5), Vector2d(0.5, -0.5)))
|
||||
|
||||
//polies.add(triangle + Vector2d(0.0, -1.5))
|
||||
polies.add(box)
|
||||
polies.add(box + Vector2d(1.0))
|
||||
//polies.add(box + Vector2d(1.0, -1.0))
|
||||
//polies.add(box + Vector2d(1.0, -2.0))
|
||||
//polies.add(box + Vector2d(1.0, -3.0))
|
||||
|
||||
//client.foregroundExecutor.scheduleAtFixedRate({ p.intersect(p2)?.let { p += it; println(it) } }, 1, 1, TimeUnit.SECONDS)
|
||||
|
||||
p += client.camera.pos
|
||||
|
||||
for (i in polies.indices)
|
||||
polies[i] = polies[i] + client.camera.pos
|
||||
|
||||
client.onPostDrawWorld {
|
||||
//client.camera.pos.x = ent.pos.x.toFloat()
|
||||
//client.camera.pos.y = ent.pos.y.toFloat()
|
||||
|
||||
p += client.screenToWorld(client.mouseCoordinates) - p.aabb.centre
|
||||
|
||||
for (i in 0 until 10) {
|
||||
val intersects = ArrayList<Poly.Penetration>()
|
||||
|
||||
polies.forEach { p.intersect(it)?.let { intersects.add(it) } }
|
||||
|
||||
if (intersects.isEmpty())
|
||||
break
|
||||
else
|
||||
p += intersects.max()
|
||||
}
|
||||
|
||||
p.render()
|
||||
polies.forEach { it.render() }
|
||||
}
|
||||
|
||||
client.box2dRenderer.drawShapes = false
|
||||
client.box2dRenderer.drawPairs = false
|
||||
client.box2dRenderer.drawAABB = false
|
||||
client.box2dRenderer.drawJoints = false
|
||||
|
||||
//ent.spawn()
|
||||
|
||||
client.input.addScrollCallback { _, x, y ->
|
||||
|
@ -60,6 +60,7 @@ import ru.dbotthepony.kstarbound.util.WriteOnce
|
||||
import ru.dbotthepony.kstarbound.util.filterNotNull
|
||||
import ru.dbotthepony.kstarbound.util.set
|
||||
import ru.dbotthepony.kstarbound.util.traverseJsonPath
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
import java.io.*
|
||||
import java.lang.ref.Cleaner
|
||||
import java.text.DateFormat
|
||||
@ -163,7 +164,6 @@ object Starbound : ISBFileLocator {
|
||||
registerTypeAdapter(Vector2iTypeAdapter)
|
||||
registerTypeAdapter(Vector4iTypeAdapter)
|
||||
registerTypeAdapter(Vector4dTypeAdapter)
|
||||
registerTypeAdapter(PolyTypeAdapter)
|
||||
registerTypeAdapter(LineF::Adapter)
|
||||
|
||||
// Функции
|
||||
@ -192,6 +192,8 @@ object Starbound : ISBFileLocator {
|
||||
|
||||
registerTypeAdapter(Image.Companion)
|
||||
|
||||
registerTypeAdapterFactory(Poly.Companion)
|
||||
|
||||
registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
|
||||
add(Registries.tiles)
|
||||
add(Registries.tileModifiers)
|
||||
|
@ -15,8 +15,8 @@ import org.lwjgl.system.MemoryStack
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import ru.dbotthepony.kstarbound.LoadingLog
|
||||
import ru.dbotthepony.kstarbound.util.ManualExecutorService
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.freetype.FreeType
|
||||
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException
|
||||
@ -41,7 +41,6 @@ import ru.dbotthepony.kstarbound.client.gl.shader.UberShader
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.input.UserInput
|
||||
import ru.dbotthepony.kstarbound.client.render.Box2DRenderer
|
||||
import ru.dbotthepony.kstarbound.client.render.Camera
|
||||
import ru.dbotthepony.kstarbound.client.render.Font
|
||||
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
|
||||
@ -382,7 +381,6 @@ class StarboundClient : Closeable {
|
||||
|
||||
val freeType = FreeType()
|
||||
val font = Font()
|
||||
val box2dRenderer = Box2DRenderer()
|
||||
val programs = GLPrograms()
|
||||
|
||||
init {
|
||||
@ -683,7 +681,8 @@ class StarboundClient : Closeable {
|
||||
viewportRectangle = AABB.rectangle(
|
||||
camera.pos,
|
||||
viewportWidth / settings.zoom / PIXELS_IN_STARBOUND_UNIT,
|
||||
viewportHeight / settings.zoom / PIXELS_IN_STARBOUND_UNIT)
|
||||
viewportHeight / settings.zoom / PIXELS_IN_STARBOUND_UNIT
|
||||
)
|
||||
|
||||
viewportCellX = roundTowardsNegativeInfinity(viewportRectangle.mins.x) - 16
|
||||
viewportCellY = roundTowardsNegativeInfinity(viewportRectangle.mins.y) - 16
|
||||
@ -855,10 +854,6 @@ class StarboundClient : Closeable {
|
||||
|
||||
layers.render()
|
||||
|
||||
box2dRenderer.begin()
|
||||
world.physics.debugDraw()
|
||||
box2dRenderer.render()
|
||||
|
||||
for (lambda in onPostDrawWorld) {
|
||||
lambda.invoke()
|
||||
}
|
||||
|
@ -1,137 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound.client.render
|
||||
|
||||
import org.lwjgl.opengl.GL45.*
|
||||
import ru.dbotthepony.kbox2d.api.IDebugDraw
|
||||
import ru.dbotthepony.kbox2d.api.Transform
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexAttributes
|
||||
import ru.dbotthepony.kvector.arrays.Matrix3f
|
||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class Box2DRenderer : IDebugDraw {
|
||||
val state = StarboundClient.current()
|
||||
|
||||
override var drawShapes: Boolean = false
|
||||
override var drawJoints: Boolean = false
|
||||
override var drawAABB: Boolean = false
|
||||
override var drawTreeAABB: Boolean = false
|
||||
override var drawPairs: Boolean = false
|
||||
override var drawCenterOfMess: Boolean = false
|
||||
|
||||
private val identity = Matrix3f.identity()
|
||||
|
||||
private val lines = StreamVertexBuilder(VertexAttributes.POSITION_COLOR, GeometryType.LINES)
|
||||
private val triangles = StreamVertexBuilder(VertexAttributes.POSITION_COLOR, GeometryType.TRIANGLES)
|
||||
|
||||
fun begin() {
|
||||
lines.builder.begin()
|
||||
triangles.builder.begin()
|
||||
}
|
||||
|
||||
fun render() {
|
||||
if (lines.builder.isEmpty() && triangles.builder.isEmpty()) return
|
||||
|
||||
lines.upload(GL_STREAM_DRAW)
|
||||
triangles.upload(GL_STREAM_DRAW)
|
||||
|
||||
state.programs.positionColor.use()
|
||||
state.programs.positionColor.colorMultiplier = RGBAColor.WHITE
|
||||
state.programs.positionColor.modelMatrix = identity
|
||||
|
||||
lines.draw(GL_LINES)
|
||||
triangles.draw(GL_TRIANGLES)
|
||||
}
|
||||
|
||||
override fun drawPolygon(vertices: List<Vector2d>, color: RGBAColor) {
|
||||
require(vertices.size > 1) { "Vertex list had only ${vertices.size} namings in it" }
|
||||
|
||||
if (!vertices.any { state.viewportRectangle.isInside(it) }) return
|
||||
|
||||
for (i in vertices.indices) {
|
||||
val current = vertices[i]
|
||||
val next = vertices[(i + 1) % vertices.size]
|
||||
lines.builder.vertex(state.stack.last(), current).color(color)
|
||||
lines.builder.vertex(state.stack.last(), next).color(color)
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawSolid(vertices: List<Vector2d>, color: RGBAColor) {
|
||||
require(vertices.size >= 3) { "Vertex list had only ${vertices.size} namings in it" }
|
||||
|
||||
if (!vertices.any { state.viewportRectangle.isInside(it) }) return
|
||||
|
||||
val zero = vertices[0]
|
||||
|
||||
for (i in 1 until vertices.size) {
|
||||
val current = vertices[i]
|
||||
val next = vertices[(i + 1) % vertices.size]
|
||||
triangles.builder.vertex(state.stack.last(), zero.x.toFloat(), zero.y.toFloat()).color(color)
|
||||
triangles.builder.vertex(state.stack.last(), current.x.toFloat(), current.y.toFloat()).color(color)
|
||||
triangles.builder.vertex(state.stack.last(), next.x.toFloat(), next.y.toFloat()).color(color)
|
||||
}
|
||||
}
|
||||
|
||||
override fun drawSolidPolygon(vertices: List<Vector2d>, color: RGBAColor) {
|
||||
drawSolid(vertices, color.copy(alpha = 0.5f))
|
||||
drawPolygon(vertices, color)
|
||||
}
|
||||
|
||||
override fun drawCircle(center: Vector2d, radius: Double, color: RGBAColor) {
|
||||
val vertexList = ArrayList<Vector2d>()
|
||||
|
||||
for (i in 0 until 360 step 15) {
|
||||
val rad = Math.toRadians(i.toDouble())
|
||||
val c = cos(rad)
|
||||
val s = sin(rad)
|
||||
|
||||
vertexList.add(Vector2d(
|
||||
center.x + c * radius,
|
||||
center.y + s * radius
|
||||
))
|
||||
}
|
||||
|
||||
drawPolygon(vertexList, color)
|
||||
}
|
||||
|
||||
override fun drawSolidCircle(center: Vector2d, radius: Double, axis: Vector2d, color: RGBAColor) {
|
||||
val vertexList = ArrayList<Vector2d>()
|
||||
|
||||
for (i in 0 until 360 step 15) {
|
||||
val rad = Math.toRadians(i.toDouble())
|
||||
val c = cos(rad)
|
||||
val s = sin(rad)
|
||||
|
||||
vertexList.add(Vector2d(
|
||||
center.x + c * radius,
|
||||
center.y + s * radius
|
||||
))
|
||||
}
|
||||
|
||||
drawSolidPolygon(vertexList, color.copy(alpha = 0.5f))
|
||||
drawPolygon(vertexList, color)
|
||||
drawPolygon(listOf(center, center + axis * radius), color)
|
||||
}
|
||||
|
||||
override fun drawSegment(p1: Vector2d, p2: Vector2d, color: RGBAColor) {
|
||||
drawPolygon(listOf(p1, p2), color)
|
||||
}
|
||||
|
||||
override fun drawTransform(xf: Transform) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun drawPoint(p: Vector2d, size: Double, color: RGBAColor) {
|
||||
drawSolid(listOf(
|
||||
Vector2d(x = p.x - size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y - size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),
|
||||
Vector2d(x = p.x + size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y - size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),
|
||||
Vector2d(x = p.x + size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y + size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),
|
||||
Vector2d(x = p.x - size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y + size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),
|
||||
), color)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.github.benmanes.caffeine.cache.Scheduler
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL45.*
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.Registries
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.*
|
||||
|
@ -5,12 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.longs.LongArraySet
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
|
||||
import ru.dbotthepony.kbox2d.api.BodyDef
|
||||
import ru.dbotthepony.kbox2d.api.BodyType
|
||||
import ru.dbotthepony.kbox2d.api.FixtureDef
|
||||
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
|
||||
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
|
||||
@ -21,27 +16,18 @@ import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
|
||||
import ru.dbotthepony.kstarbound.math.roundTowardsPositiveInfinity
|
||||
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE
|
||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||
import ru.dbotthepony.kstarbound.world.NeverFilter
|
||||
import ru.dbotthepony.kstarbound.world.NonEmptyFilter
|
||||
import ru.dbotthepony.kstarbound.world.RayCastResult
|
||||
import ru.dbotthepony.kstarbound.world.World
|
||||
import ru.dbotthepony.kstarbound.world.api.ITileAccess
|
||||
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
|
||||
import ru.dbotthepony.kstarbound.world.api.TileView
|
||||
import ru.dbotthepony.kstarbound.world.castRay
|
||||
import ru.dbotthepony.kstarbound.world.positiveModulo
|
||||
import ru.dbotthepony.kvector.api.IStruct2i
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.RGBAColor
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
import ru.dbotthepony.kvector.vector.Vector2f
|
||||
import ru.dbotthepony.kvector.vector.Vector2i
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.ForkJoinPool
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class ClientWorld(
|
||||
val client: StarboundClient,
|
||||
@ -50,10 +36,6 @@ class ClientWorld(
|
||||
loopX: Boolean = false,
|
||||
loopY: Boolean = false
|
||||
) : World<ClientWorld, ClientChunk>(seed, size, loopX, loopY) {
|
||||
init {
|
||||
physics.debugDraw = client.box2dRenderer
|
||||
}
|
||||
|
||||
private fun determineChunkSize(cells: Int): Int {
|
||||
for (i in 32 downTo 1) {
|
||||
if (cells % i == 0) {
|
||||
|
@ -7,11 +7,11 @@ import ru.dbotthepony.kstarbound.util.KOptional
|
||||
|
||||
@JsonImplementation(BaseMovementParameters.Impl::class)
|
||||
interface BaseMovementParameters {
|
||||
val mass: KOptional<Float>
|
||||
val gravityMultiplier: KOptional<Float>
|
||||
val liquidBuoyancy: KOptional<Float>
|
||||
val airBuoyancy: KOptional<Float>
|
||||
val bounceFactor: KOptional<Float>
|
||||
val mass: KOptional<Double>
|
||||
val gravityMultiplier: KOptional<Double>
|
||||
val liquidBuoyancy: KOptional<Double>
|
||||
val airBuoyancy: KOptional<Double>
|
||||
val bounceFactor: KOptional<Double>
|
||||
|
||||
// If set to true, during an update that has more than one internal movement
|
||||
// step, the movement will stop on the first bounce.
|
||||
@ -21,50 +21,50 @@ interface BaseMovementParameters {
|
||||
// other directions (within a set limit). Allows smooth sliding along
|
||||
// horizontal ground without losing horizontal speed.
|
||||
val enableSurfaceSlopeCorrection: KOptional<Boolean>
|
||||
val slopeSlidingFactor: KOptional<Float>
|
||||
val maxMovementPerStep: KOptional<Float>
|
||||
val maximumCorrection: KOptional<Float>
|
||||
val speedLimit: KOptional<Float>
|
||||
val slopeSlidingFactor: KOptional<Double>
|
||||
val maxMovementPerStep: KOptional<Double>
|
||||
val maximumCorrection: KOptional<Double>
|
||||
val speedLimit: KOptional<Double>
|
||||
|
||||
val stickyCollision: KOptional<Boolean>
|
||||
val stickyForce: KOptional<Float>
|
||||
val stickyForce: KOptional<Double>
|
||||
|
||||
val airFriction: KOptional<Float>
|
||||
val liquidFriction: KOptional<Float>
|
||||
val groundFriction: KOptional<Float>
|
||||
val airFriction: KOptional<Double>
|
||||
val liquidFriction: KOptional<Double>
|
||||
val groundFriction: KOptional<Double>
|
||||
|
||||
val collisionEnabled: KOptional<Boolean>
|
||||
val frictionEnabled: KOptional<Boolean>
|
||||
val gravityEnabled: KOptional<Boolean>
|
||||
|
||||
val maximumPlatformCorrection: KOptional<Float>
|
||||
val maximumPlatformCorrectionVelocityFactor: KOptional<Float>
|
||||
val maximumPlatformCorrection: KOptional<Double>
|
||||
val maximumPlatformCorrectionVelocityFactor: KOptional<Double>
|
||||
|
||||
val physicsEffectCategories: KOptional<ImmutableSet<String>>
|
||||
|
||||
@JsonFactory
|
||||
data class Impl(
|
||||
override val mass: KOptional<Float> = KOptional.empty(),
|
||||
override val gravityMultiplier: KOptional<Float> = KOptional.empty(),
|
||||
override val liquidBuoyancy: KOptional<Float> = KOptional.empty(),
|
||||
override val airBuoyancy: KOptional<Float> = KOptional.empty(),
|
||||
override val bounceFactor: KOptional<Float> = KOptional.empty(),
|
||||
override val mass: KOptional<Double> = KOptional.empty(),
|
||||
override val gravityMultiplier: KOptional<Double> = KOptional.empty(),
|
||||
override val liquidBuoyancy: KOptional<Double> = KOptional.empty(),
|
||||
override val airBuoyancy: KOptional<Double> = KOptional.empty(),
|
||||
override val bounceFactor: KOptional<Double> = KOptional.empty(),
|
||||
override val stopOnFirstBounce: KOptional<Boolean> = KOptional.empty(),
|
||||
override val enableSurfaceSlopeCorrection: KOptional<Boolean> = KOptional.empty(),
|
||||
override val slopeSlidingFactor: KOptional<Float> = KOptional.empty(),
|
||||
override val maxMovementPerStep: KOptional<Float> = KOptional.empty(),
|
||||
override val maximumCorrection: KOptional<Float> = KOptional.empty(),
|
||||
override val speedLimit: KOptional<Float> = KOptional.empty(),
|
||||
override val slopeSlidingFactor: KOptional<Double> = KOptional.empty(),
|
||||
override val maxMovementPerStep: KOptional<Double> = KOptional.empty(),
|
||||
override val maximumCorrection: KOptional<Double> = KOptional.empty(),
|
||||
override val speedLimit: KOptional<Double> = KOptional.empty(),
|
||||
override val stickyCollision: KOptional<Boolean> = KOptional.empty(),
|
||||
override val stickyForce: KOptional<Float> = KOptional.empty(),
|
||||
override val airFriction: KOptional<Float> = KOptional.empty(),
|
||||
override val liquidFriction: KOptional<Float> = KOptional.empty(),
|
||||
override val groundFriction: KOptional<Float> = KOptional.empty(),
|
||||
override val stickyForce: KOptional<Double> = KOptional.empty(),
|
||||
override val airFriction: KOptional<Double> = KOptional.empty(),
|
||||
override val liquidFriction: KOptional<Double> = KOptional.empty(),
|
||||
override val groundFriction: KOptional<Double> = KOptional.empty(),
|
||||
override val collisionEnabled: KOptional<Boolean> = KOptional.empty(),
|
||||
override val frictionEnabled: KOptional<Boolean> = KOptional.empty(),
|
||||
override val gravityEnabled: KOptional<Boolean> = KOptional.empty(),
|
||||
override val maximumPlatformCorrection: KOptional<Float> = KOptional.empty(),
|
||||
override val maximumPlatformCorrectionVelocityFactor: KOptional<Float> = KOptional.empty(),
|
||||
override val maximumPlatformCorrection: KOptional<Double> = KOptional.empty(),
|
||||
override val maximumPlatformCorrectionVelocityFactor: KOptional<Double> = KOptional.empty(),
|
||||
override val physicsEffectCategories: KOptional<ImmutableSet<String>> = KOptional.empty(),
|
||||
) : BaseMovementParameters {
|
||||
fun merge(other: Impl): Impl {
|
||||
|
@ -8,7 +8,7 @@ import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.client.render.IGeometryLayer
|
||||
|
@ -1,10 +1,9 @@
|
||||
package ru.dbotthepony.kstarbound.defs
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
|
||||
import ru.dbotthepony.kstarbound.util.KOptional
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
|
||||
@JsonFactory
|
||||
data class MovementParameters(
|
||||
@ -12,7 +11,7 @@ data class MovementParameters(
|
||||
val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(),
|
||||
|
||||
val discontinuityThreshold: KOptional<Float> = KOptional.empty(),
|
||||
val collisionPoly: KOptional<ImmutableList<Vector2d>> = KOptional.empty(),
|
||||
val collisionPoly: KOptional<Poly> = KOptional.empty(),
|
||||
val ignorePlatformCollision: KOptional<Boolean> = KOptional.empty(),
|
||||
val restDuration: KOptional<Int> = KOptional.empty(),
|
||||
) : BaseMovementParameters by base {
|
||||
|
@ -20,8 +20,8 @@ import org.apache.logging.log4j.LogManager
|
||||
import org.lwjgl.opengl.GL45
|
||||
import org.lwjgl.stb.STBImage
|
||||
import org.lwjgl.system.MemoryUtil
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITi
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
|
@ -10,7 +10,7 @@ import com.google.gson.TypeAdapter
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.render.RenderLayer
|
||||
import ru.dbotthepony.kstarbound.defs.Drawable
|
||||
import ru.dbotthepony.kstarbound.defs.JsonReference
|
||||
|
@ -1,14 +1,12 @@
|
||||
package ru.dbotthepony.kstarbound.defs.player
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import ru.dbotthepony.kstarbound.defs.BaseMovementParameters
|
||||
import ru.dbotthepony.kstarbound.defs.JumpProfile
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonAlias
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
|
||||
import ru.dbotthepony.kstarbound.util.KOptional
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
|
||||
@JsonFactory
|
||||
data class PlayerMovementParameters(
|
||||
@ -16,9 +14,9 @@ data class PlayerMovementParameters(
|
||||
val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(),
|
||||
|
||||
@JsonAlias("collisionPoly")
|
||||
val standingPoly: KOptional<ImmutableList<Vector2d>> = KOptional.empty(),
|
||||
val standingPoly: KOptional<Poly> = KOptional.empty(),
|
||||
@JsonAlias("collisionPoly")
|
||||
val crouchingPoly: KOptional<ImmutableList<Vector2d>> = KOptional.empty(),
|
||||
val crouchingPoly: KOptional<Poly> = KOptional.empty(),
|
||||
|
||||
val walkSpeed: KOptional<Double> = KOptional.empty(),
|
||||
val runSpeed: KOptional<Double> = KOptional.empty(),
|
||||
|
@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.CollisionType
|
||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||
|
||||
object BuiltinMetaMaterials {
|
||||
|
@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import ru.dbotthepony.kstarbound.defs.AssetReference
|
||||
import ru.dbotthepony.kstarbound.defs.CollisionType
|
||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||
import ru.dbotthepony.kstarbound.defs.IThingWithDescription
|
||||
import ru.dbotthepony.kstarbound.defs.ThingDescription
|
||||
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
|
||||
|
@ -1,43 +0,0 @@
|
||||
package ru.dbotthepony.kstarbound.math
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonToken
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
|
||||
class Poly(vararg points: Vector2d) {
|
||||
val points: List<Vector2d> = ImmutableList.copyOf(points)
|
||||
|
||||
override fun toString(): String {
|
||||
return "Poly($points)"
|
||||
}
|
||||
}
|
||||
|
||||
object PolyTypeAdapter : TypeAdapter<Poly>() {
|
||||
override fun write(out: JsonWriter, value: Poly) {
|
||||
`out`.beginArray()
|
||||
|
||||
for (point in value.points) {
|
||||
Vector2dTypeAdapter.write(out, point)
|
||||
}
|
||||
|
||||
`out`.endArray()
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Poly {
|
||||
`in`.beginArray()
|
||||
|
||||
val points = mutableListOf<Vector2d>()
|
||||
|
||||
while (`in`.peek() == JsonToken.BEGIN_ARRAY) {
|
||||
points.add(Vector2dTypeAdapter.read(`in`))
|
||||
}
|
||||
|
||||
`in`.endArray()
|
||||
|
||||
return Poly(*points.toTypedArray())
|
||||
}
|
||||
}
|
@ -1,10 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
||||
import ru.dbotthepony.kbox2d.api.BodyDef
|
||||
import ru.dbotthepony.kbox2d.api.FixtureDef
|
||||
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
|
||||
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
|
||||
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
|
||||
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
|
||||
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
|
||||
@ -49,8 +45,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
||||
private set
|
||||
var cellChangeset = 0
|
||||
private set
|
||||
var collisionChangeset = 0
|
||||
private set
|
||||
|
||||
var foregroundChangeset = 0
|
||||
private set
|
||||
@ -101,28 +95,15 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
||||
private val collisionCache = ArrayList<AABB>()
|
||||
private val collisionCacheView = Collections.unmodifiableCollection(collisionCache)
|
||||
|
||||
private val body by lazy {
|
||||
world.physics.createBody(BodyDef(
|
||||
position = pos.tile.toDoubleVector(),
|
||||
userData = this
|
||||
))
|
||||
}
|
||||
|
||||
private val collisionChains = ArrayList<B2Fixture>()
|
||||
|
||||
protected open fun foregroundChanges(cell: Cell) {
|
||||
cellChanges(cell)
|
||||
tileChangeset++
|
||||
|
||||
collisionChangeset++
|
||||
foregroundChangeset++
|
||||
markPhysicsDirty()
|
||||
}
|
||||
|
||||
protected open fun backgroundChanges(cell: Cell) {
|
||||
cellChanges(cell)
|
||||
tileChangeset++
|
||||
|
||||
backgroundChangeset++
|
||||
}
|
||||
|
||||
@ -147,14 +128,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
||||
world.chunkMap[pos.bottomRight]?.let(block)
|
||||
}
|
||||
|
||||
fun markPhysicsDirty() {
|
||||
if (isPhysicsDirty)
|
||||
return
|
||||
|
||||
isPhysicsDirty = true
|
||||
world.dirtyPhysicsChunks.add(this as This)
|
||||
}
|
||||
|
||||
inner class Cell(x: Int, y: Int) : IChunkCell {
|
||||
override val x: Int = x + pos.x * CHUNK_SIZE
|
||||
override val y: Int = y + pos.y * CHUNK_SIZE
|
||||
@ -279,45 +252,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
|
||||
}
|
||||
}
|
||||
|
||||
fun bakeCollisions() {
|
||||
if (collisionChangeset == changeset)
|
||||
return
|
||||
|
||||
collisionChangeset = changeset
|
||||
collisionCache.clear()
|
||||
|
||||
for (box in collisionChains) {
|
||||
body.destroyFixture(box)
|
||||
}
|
||||
|
||||
collisionChains.clear()
|
||||
|
||||
for (y in 0 .. CHUNK_SIZE_FF) {
|
||||
for (x in 0..CHUNK_SIZE_FF) {
|
||||
val cell = getCell(x, y)
|
||||
|
||||
/*if (!cell.foreground.material.collisionKind.isEmpty) {
|
||||
collisionChains.add(body.createFixture(FixtureDef(
|
||||
shape = PolygonShape().also { it.setAsBox(0.5, 0.5, Vector2d(x + 0.5, y + 0.5), 0.0) },
|
||||
friction = 0.4,
|
||||
userData = cell,
|
||||
)))
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает список AABB тайлов этого слоя
|
||||
*
|
||||
* Данный список напрямую указывает на внутреннее состояние и будет изменён при перестройке
|
||||
* коллизии чанка, поэтому если необходим стабильный список, его необходимо скопировать
|
||||
*/
|
||||
fun collisionLayers(): Collection<AABB> {
|
||||
bakeCollisions()
|
||||
return collisionCacheView
|
||||
}
|
||||
|
||||
override fun randomLongFor(x: Int, y: Int): Long {
|
||||
return world.randomLongFor(x or pos.x shl CHUNK_SIZE_BITS, y or pos.y shl CHUNK_SIZE_BITS)
|
||||
}
|
||||
|
15
src/main/kotlin/ru/dbotthepony/kstarbound/world/Constants.kt
Normal file
15
src/main/kotlin/ru/dbotthepony/kstarbound/world/Constants.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
const val METRES_IN_STARBOUND_UNIT = 0.5
|
||||
const val METRES_IN_STARBOUND_UNITf = 0.5f
|
||||
const val PIXELS_IN_STARBOUND_UNITi = 8
|
||||
const val PIXELS_IN_STARBOUND_UNIT = PIXELS_IN_STARBOUND_UNITi.toDouble()
|
||||
const val PIXELS_IN_STARBOUND_UNITf = PIXELS_IN_STARBOUND_UNITi.toFloat()
|
||||
|
||||
const val CHUNK_SIZE_BITS = 5
|
||||
const val CHUNK_SIZE_MASK = 1 or 2 or 4 or 8 or 16
|
||||
const val CHUNK_SIZE = 1 shl CHUNK_SIZE_BITS // 32
|
||||
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
|
||||
const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
|
||||
|
||||
const val EARTH_FREEFALL_ACCELERATION = 9.8312 / METRES_IN_STARBOUND_UNIT
|
@ -1,6 +1,6 @@
|
||||
package ru.dbotthepony.kstarbound.world
|
||||
|
||||
import ru.dbotthepony.kstarbound.METRES_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.world.METRES_IN_STARBOUND_UNIT
|
||||
import ru.dbotthepony.kstarbound.math.roundTowardsNegativeInfinity
|
||||
import ru.dbotthepony.kstarbound.world.api.ICellAccess
|
||||
import ru.dbotthepony.kstarbound.world.api.IChunkCell
|
||||
@ -10,8 +10,6 @@ import kotlin.collections.ArrayList
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
|
||||
const val EARTH_FREEFALL_ACCELERATION = 9.8312 / METRES_IN_STARBOUND_UNIT
|
||||
|
||||
data class RayCastResult(
|
||||
val traversedTiles: List<HitCell>,
|
||||
val hitTile: HitCell?,
|
||||
|
@ -5,14 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
|
||||
import ru.dbotthepony.kbox2d.api.ContactImpulse
|
||||
import ru.dbotthepony.kbox2d.api.IContactFilter
|
||||
import ru.dbotthepony.kbox2d.api.IContactListener
|
||||
import ru.dbotthepony.kbox2d.api.Manifold
|
||||
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
|
||||
import ru.dbotthepony.kbox2d.dynamics.B2World
|
||||
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.world.ClientWorld
|
||||
import ru.dbotthepony.kstarbound.math.*
|
||||
import ru.dbotthepony.kstarbound.util.ManualExecutorService
|
||||
import ru.dbotthepony.kstarbound.world.api.ICellAccess
|
||||
@ -20,6 +13,9 @@ import ru.dbotthepony.kstarbound.world.api.IChunkCell
|
||||
import ru.dbotthepony.kstarbound.world.api.TileView
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kstarbound.world.entities.WorldObject
|
||||
import ru.dbotthepony.kstarbound.world.physics.CollisionPoly
|
||||
import ru.dbotthepony.kstarbound.world.physics.CollisionType
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
import ru.dbotthepony.kvector.api.IStruct2d
|
||||
import ru.dbotthepony.kvector.api.IStruct2i
|
||||
import ru.dbotthepony.kvector.arrays.Object2DArray
|
||||
@ -30,12 +26,6 @@ import java.lang.ref.ReferenceQueue
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.random.RandomGenerator
|
||||
|
||||
const val CHUNK_SIZE_BITS = 5
|
||||
const val CHUNK_SIZE_MASK = 1 or 2 or 4 or 8 or 16
|
||||
const val CHUNK_SIZE = 1 shl CHUNK_SIZE_BITS // 32
|
||||
const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
|
||||
const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(
|
||||
val seed: Long,
|
||||
@ -244,81 +234,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
val random: RandomGenerator = RandomGenerator.of("Xoroshiro128PlusPlus")
|
||||
|
||||
/**
|
||||
* Chunks, which have their collision mesh changed
|
||||
*/
|
||||
val dirtyPhysicsChunks = ObjectOpenHashSet<ChunkType>()
|
||||
|
||||
val physics = B2World(Vector2d(0.0, -EARTH_FREEFALL_ACCELERATION))
|
||||
|
||||
init {
|
||||
physics.contactFilter = object : IContactFilter {
|
||||
override fun shouldCollide(fixtureA: B2Fixture, fixtureB: B2Fixture): Boolean {
|
||||
val dataA = fixtureA.body!!.userData
|
||||
val dataB = fixtureB.body!!.userData
|
||||
|
||||
//if (dataA is AbstractProjectileMovementController && dataB is AbstractProjectileMovementController) {
|
||||
// return false
|
||||
//}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
physics.contactListener = object : IContactListener {
|
||||
override fun beginContact(contact: AbstractContact) {
|
||||
val dataA = contact.fixtureA.body!!.userData
|
||||
val dataB = contact.fixtureB.body!!.userData
|
||||
|
||||
if (dataA is IContactListener) {
|
||||
dataA.beginContact(contact)
|
||||
}
|
||||
|
||||
if (dataB is IContactListener) {
|
||||
dataB.beginContact(contact)
|
||||
}
|
||||
}
|
||||
|
||||
override fun endContact(contact: AbstractContact) {
|
||||
val dataA = contact.fixtureA.body!!.userData
|
||||
val dataB = contact.fixtureB.body!!.userData
|
||||
|
||||
if (dataA is IContactListener) {
|
||||
dataA.endContact(contact)
|
||||
}
|
||||
|
||||
if (dataB is IContactListener) {
|
||||
dataB.endContact(contact)
|
||||
}
|
||||
}
|
||||
|
||||
override fun preSolve(contact: AbstractContact, oldManifold: Manifold) {
|
||||
val dataA = contact.fixtureA.body!!.userData
|
||||
val dataB = contact.fixtureB.body!!.userData
|
||||
|
||||
if (dataA is IContactListener) {
|
||||
dataA.preSolve(contact, oldManifold)
|
||||
}
|
||||
|
||||
if (dataB is IContactListener) {
|
||||
dataB.preSolve(contact, oldManifold)
|
||||
}
|
||||
}
|
||||
|
||||
override fun postSolve(contact: AbstractContact, impulse: ContactImpulse) {
|
||||
val dataA = contact.fixtureA.body!!.userData
|
||||
val dataB = contact.fixtureB.body!!.userData
|
||||
|
||||
if (dataA is IContactListener) {
|
||||
dataA.postSolve(contact, impulse)
|
||||
}
|
||||
|
||||
if (dataB is IContactListener) {
|
||||
dataB.postSolve(contact, impulse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var gravity = Vector2d(0.0, -EARTH_FREEFALL_ACCELERATION)
|
||||
|
||||
var ticks = 0
|
||||
private set
|
||||
@ -326,12 +242,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
fun think() {
|
||||
try {
|
||||
executor.executeQueuedTasks()
|
||||
|
||||
for (chunk in dirtyPhysicsChunks)
|
||||
chunk.bakeCollisions()
|
||||
|
||||
dirtyPhysicsChunks.clear()
|
||||
physics.step(Starbound.TICK_TIME_ADVANCE, 6, 4)
|
||||
thinkInner()
|
||||
ticks++
|
||||
} catch(err: Throwable) {
|
||||
@ -353,16 +263,9 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
val objects = ReferenceLinkedOpenHashSet<WorldObject>()
|
||||
|
||||
/**
|
||||
* Стандартное ускорение свободного падения в Starbound Units/секунда^2
|
||||
*
|
||||
* При Vector2d.ZERO = невесомость
|
||||
*/
|
||||
var gravity by physics::gravity
|
||||
|
||||
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType
|
||||
|
||||
fun testSpace(aabb: AABB, predicate: Predicate<IChunkCell> = Predicate { it.foreground.material != null }): Boolean {
|
||||
fun testSpace(aabb: AABB, predicate: Predicate<IChunkCell> = Predicate { !it.foreground.material.collisionKind.isEmpty }): Boolean {
|
||||
val tiles = aabb.encasingIntAABB()
|
||||
|
||||
for (x in tiles.mins.x .. tiles.maxs.x) {
|
||||
@ -375,4 +278,21 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun queryCollisions(aabb: AABB): MutableList<CollisionPoly> {
|
||||
val result = ArrayList<CollisionPoly>()
|
||||
val tiles = aabb.encasingIntAABB()
|
||||
|
||||
for (x in tiles.mins.x .. tiles.maxs.x) {
|
||||
for (y in tiles.mins.y .. tiles.maxs.y) {
|
||||
val cell = getCell(x, y) ?: continue
|
||||
|
||||
for (poly in cell.polies) {
|
||||
result.add(CollisionPoly(poly, cell.foreground.material.collisionKind, Vector2d(EARTH_FREEFALL_ACCELERATION, 0.0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,6 @@ interface IChunkCell : IStruct2i {
|
||||
}
|
||||
|
||||
val polies: Collection<Poly> get() {
|
||||
if (foreground.material.isMeta)
|
||||
return emptyList()
|
||||
|
||||
return listOf(rect + Vector2d(this.x.toDouble(), this.y.toDouble()))
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import ru.dbotthepony.kstarbound.GlobalDefaults
|
||||
import ru.dbotthepony.kstarbound.Starbound
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.defs.BaseMovementParameters
|
||||
import ru.dbotthepony.kstarbound.world.Chunk
|
||||
import ru.dbotthepony.kstarbound.world.World
|
||||
import ru.dbotthepony.kstarbound.world.physics.CollisionPoly
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
|
||||
abstract class Entity(val world: World<*, *>) {
|
||||
/**
|
||||
* The chunk this entity currently in, it is automatically updated on each change of [position]
|
||||
*/
|
||||
var chunk: Chunk<*, *>? = null
|
||||
set(value) {
|
||||
if (!isSpawned) {
|
||||
@ -40,16 +42,6 @@ abstract class Entity(val world: World<*, *>) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Current entity position. If entity is logical, this can only be changed
|
||||
* by external means, otherwise it always stands where it is.
|
||||
*
|
||||
* If entity is physical, then movement controller will update this on each physics step
|
||||
* to match position of physical body.
|
||||
*
|
||||
* Setting this value will update [chunk] immediately, if [isSpawned] is true and [isRemoved] is false.
|
||||
*/
|
||||
var position = Vector2d()
|
||||
set(value) {
|
||||
if (field == value)
|
||||
@ -68,27 +60,9 @@ abstract class Entity(val world: World<*, *>) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This entity's angle in radians.
|
||||
*
|
||||
* Logical entities never rotate.
|
||||
*
|
||||
* Alive entities usually don't rotate.
|
||||
*
|
||||
* If entity is physical, this value is updated by movement controller on
|
||||
* each physics step to match angle of physical body.
|
||||
*/
|
||||
var angle: Double = 0.0
|
||||
set(value) {
|
||||
if (field == value)
|
||||
return
|
||||
|
||||
field = value
|
||||
}
|
||||
|
||||
var velocity = Vector2d.ZERO
|
||||
val hitboxes = ArrayList<Poly>()
|
||||
open var movementParameters: BaseMovementParameters = GlobalDefaults.movementParameters
|
||||
|
||||
/**
|
||||
* Whenever is this entity spawned in world ([spawn] called).
|
||||
@ -128,9 +102,6 @@ abstract class Entity(val world: World<*, *>) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Заставляет сущность "думать".
|
||||
*/
|
||||
fun think() {
|
||||
if (!isSpawned) {
|
||||
throw IllegalStateException("Tried to think before spawning in world")
|
||||
@ -143,24 +114,20 @@ abstract class Entity(val world: World<*, *>) {
|
||||
protected abstract fun thinkInner()
|
||||
|
||||
protected open fun move() {
|
||||
position += velocity
|
||||
velocity += world.gravity * Starbound.TICK_TIME_ADVANCE
|
||||
position += velocity * Starbound.TICK_TIME_ADVANCE
|
||||
|
||||
val polies = ArrayList<Poly>()
|
||||
|
||||
for (x in -1 .. 1) {
|
||||
for (y in -1 .. 1) {
|
||||
world.chunkMap.getCell(position.x.toInt() + x, position.y.toInt() + y)?.let {
|
||||
polies.addAll(it.polies)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hitboxes.isEmpty()) return
|
||||
|
||||
for (i in 0 until 10) {
|
||||
val intersects = ArrayList<Poly.Penetration>()
|
||||
val localHitboxes = hitboxes.map { it + position }
|
||||
val polies = world.queryCollisions(localHitboxes.stream().map { it.aabb }.reduce(AABB::combine).get().enlarge(1.0, 1.0)).filter { !it.type.isEmpty }
|
||||
if (polies.isEmpty()) break
|
||||
|
||||
this.hitboxes.forEach { hitbox0 ->
|
||||
val hitbox = hitbox0 + position
|
||||
polies.forEach { poly -> hitbox.intersect(poly)?.let { intersects.add(it) } }
|
||||
val intersects = ArrayList<Poly.Penetration<CollisionPoly>>()
|
||||
|
||||
localHitboxes.forEach { hitbox ->
|
||||
polies.forEach { poly -> hitbox.intersect(poly.poly, poly)?.let { intersects.add(it) } }
|
||||
}
|
||||
|
||||
if (intersects.isEmpty())
|
||||
@ -170,7 +137,13 @@ abstract class Entity(val world: World<*, *>) {
|
||||
// resolve collision
|
||||
position += max.vector
|
||||
// collision response
|
||||
velocity -= max.axis * velocity.dot(max.axis * 1.1)
|
||||
velocity -= max.axis * velocity.dot(max.axis)
|
||||
|
||||
val gravityDot = world.gravity.unitVector.dot(max.axis)
|
||||
// impulse?
|
||||
velocity += max.data.velocity * gravityDot * Starbound.TICK_TIME_ADVANCE
|
||||
// friction
|
||||
velocity *= 1.0 - gravityDot * 0.08
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,5 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import ru.dbotthepony.kbox2d.api.ContactImpulse
|
||||
import ru.dbotthepony.kbox2d.api.FixtureDef
|
||||
import ru.dbotthepony.kbox2d.api.Manifold
|
||||
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
|
||||
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
|
||||
import ru.dbotthepony.kstarbound.world.World
|
||||
import ru.dbotthepony.kstarbound.world.physics.Poly
|
||||
|
@ -0,0 +1,9 @@
|
||||
package ru.dbotthepony.kstarbound.world.physics
|
||||
|
||||
import ru.dbotthepony.kvector.vector.Vector2d
|
||||
|
||||
data class CollisionPoly(
|
||||
val poly: Poly,
|
||||
val type: CollisionType,
|
||||
val velocity: Vector2d = Vector2d.ZERO
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package ru.dbotthepony.kstarbound.defs
|
||||
package ru.dbotthepony.kstarbound.world.physics
|
||||
|
||||
enum class CollisionType(val isEmpty: Boolean) {
|
||||
NULL(true),
|
@ -1,10 +1,18 @@
|
||||
package ru.dbotthepony.kstarbound.world.physics
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.TypeAdapter
|
||||
import com.google.gson.TypeAdapterFactory
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.google.gson.stream.JsonReader
|
||||
import com.google.gson.stream.JsonWriter
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
|
||||
import org.lwjgl.opengl.GL11.GL_LINES
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
|
||||
import ru.dbotthepony.kstarbound.io.json.consumeNull
|
||||
import ru.dbotthepony.kstarbound.io.json.listAdapter
|
||||
import ru.dbotthepony.kvector.api.IStruct2d
|
||||
import ru.dbotthepony.kvector.arrays.Matrix3f
|
||||
import ru.dbotthepony.kvector.util2d.AABB
|
||||
@ -63,15 +71,15 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
}
|
||||
}
|
||||
|
||||
data class Penetration(val axis: Vector2d, val penetration: Double) : Comparable<Penetration> {
|
||||
data class Penetration<T>(val axis: Vector2d, val penetration: Double, val data: T) : Comparable<Penetration<*>> {
|
||||
val vector = axis * penetration
|
||||
|
||||
override fun compareTo(other: Penetration): Int {
|
||||
override fun compareTo(other: Penetration<*>): Int {
|
||||
return penetration.absoluteValue.compareTo(other.penetration.absoluteValue)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun plus(value: Penetration): Poly {
|
||||
operator fun plus(value: Penetration<*>): Poly {
|
||||
val vertices = ImmutableList.Builder<Vector2d>()
|
||||
val edges = ImmutableList.Builder<Edge>()
|
||||
|
||||
@ -136,7 +144,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
return Vector2d(min, max)
|
||||
}
|
||||
|
||||
fun intersect(other: Poly): Penetration? {
|
||||
fun <T> intersect(other: Poly, data: T): Penetration<T>? {
|
||||
if (!aabb.intersectWeak(other.aabb))
|
||||
return null
|
||||
|
||||
@ -144,7 +152,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
edges.forEach { normals.add(it.normal) }
|
||||
other.edges.forEach { normals.add(it.normal) }
|
||||
|
||||
val intersections = ArrayList<Penetration>()
|
||||
val intersections = ArrayList<Penetration<T>>()
|
||||
|
||||
for (normal in normals) {
|
||||
val projectThis = project(normal)
|
||||
@ -165,10 +173,10 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
|
||||
if (minMin <= maxMax) {
|
||||
// push to left
|
||||
intersections.add(Penetration(normal, -minMin - width))
|
||||
intersections.add(Penetration(normal, -minMin - width, data))
|
||||
} else {
|
||||
// push to right
|
||||
intersections.add(Penetration(normal, maxMax + width))
|
||||
intersections.add(Penetration(normal, maxMax + width, data))
|
||||
}
|
||||
} else if (
|
||||
projectThis.component1() in projectOther.component1() .. projectOther.component2() &&
|
||||
@ -180,20 +188,20 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
|
||||
if (minMin <= maxMax) {
|
||||
// push to left
|
||||
intersections.add(Penetration(normal, -minMin - width))
|
||||
intersections.add(Penetration(normal, -minMin - width, data))
|
||||
} else {
|
||||
// push to right
|
||||
intersections.add(Penetration(normal, maxMax + width))
|
||||
intersections.add(Penetration(normal, maxMax + width, data))
|
||||
}
|
||||
} else if (projectOther.component1() in projectThis.component1() .. projectThis.component2()) {
|
||||
// other's min point is within this
|
||||
intersections.add(Penetration(normal, projectOther.component1() - projectThis.component2()))
|
||||
intersections.add(Penetration(normal, projectOther.component1() - projectThis.component2(), data))
|
||||
} else {
|
||||
// other's max point in within this
|
||||
intersections.add(Penetration(normal, projectOther.component2() - projectThis.component1()))
|
||||
intersections.add(Penetration(normal, projectOther.component2() - projectThis.component1(), data))
|
||||
}
|
||||
|
||||
if (intersections.last().penetration == 0.0) {
|
||||
if (intersections.last().penetration.absoluteValue <= EPSILON) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -205,19 +213,23 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
return intersections.min()
|
||||
}
|
||||
|
||||
fun intersect(other: Poly) = intersect(other, Unit)
|
||||
|
||||
fun render(client: StarboundClient = StarboundClient.current(), color: RGBAColor = RGBAColor.LIGHT_GREEN) {
|
||||
val program = client.programs.position
|
||||
val lines = program.builder.builder
|
||||
program.use()
|
||||
lines.begin(GeometryType.LINES)
|
||||
|
||||
val normalSize = (aabb.width.coerceAtMost(aabb.height) / 3.0).coerceAtLeast(0.1)
|
||||
|
||||
for (edge in edges) {
|
||||
val current = edge.p0
|
||||
val next = edge.p1
|
||||
lines.vertex(client.stack.last(), current)
|
||||
lines.vertex(client.stack.last(), next)
|
||||
lines.vertex(client.stack.last(), (next + current) / 2.0)
|
||||
lines.vertex(client.stack.last(), (next + current) / 2.0 + edge.normal * 3.0)
|
||||
lines.vertex(client.stack.last(), (next + current) / 2.0 + edge.normal * normalSize)
|
||||
}
|
||||
|
||||
program.modelMatrix = identity
|
||||
@ -227,10 +239,40 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Poly[edges = $edges]"
|
||||
return "Poly[aabb = $aabb; edges = $edges]"
|
||||
}
|
||||
|
||||
companion object {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other === this || other is Poly && vertices == other.vertices
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return vertices.hashCode()
|
||||
}
|
||||
|
||||
companion object : TypeAdapterFactory {
|
||||
const val EPSILON = 0.01
|
||||
private val identity = Matrix3f.identity()
|
||||
|
||||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
||||
if (type.rawType === Poly::class.java) {
|
||||
return object : TypeAdapter<Poly>() {
|
||||
private val list = gson.listAdapter<Vector2d>()
|
||||
|
||||
override fun write(out: JsonWriter, value: Poly?) {
|
||||
list.write(out, value?.vertices)
|
||||
}
|
||||
|
||||
override fun read(`in`: JsonReader): Poly? {
|
||||
if (`in`.consumeNull())
|
||||
return null
|
||||
else
|
||||
return Poly(list.read(`in`))
|
||||
}
|
||||
} as TypeAdapter<T>
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user