Remove kbox2d from deps and remove leftover code from previous testing stages

This commit is contained in:
DBotThePony 2023-10-14 19:26:28 +07:00
parent b9975657d4
commit 30b168766d
Signed by: DBot
GPG Key ID: DCC23B5715498507
27 changed files with 184 additions and 561 deletions

View File

@ -82,8 +82,7 @@ dependencies {
implementation("net.java.dev.jna:jna:5.13.0") implementation("net.java.dev.jna:jna:5.13.0")
implementation("com.github.jnr:jnr-ffi:2.2.13") implementation("com.github.jnr:jnr-ffi:2.2.13")
implementation("ru.dbotthepony:kbox2d:2.4.1-1.0.2") implementation("ru.dbotthepony:kvector:2.11.0")
implementation("ru.dbotthepony:kvector:2.10.2")
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5") implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
} }

View File

@ -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()

View File

@ -20,6 +20,7 @@ import ru.dbotthepony.kstarbound.io.readVarInt
import ru.dbotthepony.kstarbound.util.AssetPathStack import ru.dbotthepony.kstarbound.util.AssetPathStack
import ru.dbotthepony.kstarbound.world.entities.WorldObject import ru.dbotthepony.kstarbound.world.entities.WorldObject
import ru.dbotthepony.kstarbound.world.physics.Poly import ru.dbotthepony.kstarbound.world.physics.Poly
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Vector2d import ru.dbotthepony.kvector.vector.Vector2d
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -122,12 +123,12 @@ fun main() {
val item = Registries.items.values.random() val item = Registries.items.values.random()
val rand = Random() val rand = Random()
for (i in 0 .. 0) { for (i in 0 .. 128) {
val item = ItemEntity(client.world!!, item.value) 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.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)) //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) 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() //ent.spawn()
client.input.addScrollCallback { _, x, y -> client.input.addScrollCallback { _, x, y ->

View File

@ -60,6 +60,7 @@ import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kstarbound.util.filterNotNull import ru.dbotthepony.kstarbound.util.filterNotNull
import ru.dbotthepony.kstarbound.util.set import ru.dbotthepony.kstarbound.util.set
import ru.dbotthepony.kstarbound.util.traverseJsonPath import ru.dbotthepony.kstarbound.util.traverseJsonPath
import ru.dbotthepony.kstarbound.world.physics.Poly
import java.io.* import java.io.*
import java.lang.ref.Cleaner import java.lang.ref.Cleaner
import java.text.DateFormat import java.text.DateFormat
@ -163,7 +164,6 @@ object Starbound : ISBFileLocator {
registerTypeAdapter(Vector2iTypeAdapter) registerTypeAdapter(Vector2iTypeAdapter)
registerTypeAdapter(Vector4iTypeAdapter) registerTypeAdapter(Vector4iTypeAdapter)
registerTypeAdapter(Vector4dTypeAdapter) registerTypeAdapter(Vector4dTypeAdapter)
registerTypeAdapter(PolyTypeAdapter)
registerTypeAdapter(LineF::Adapter) registerTypeAdapter(LineF::Adapter)
// Функции // Функции
@ -192,6 +192,8 @@ object Starbound : ISBFileLocator {
registerTypeAdapter(Image.Companion) registerTypeAdapter(Image.Companion)
registerTypeAdapterFactory(Poly.Companion)
registerTypeAdapterFactory(with(RegistryReferenceFactory()) { registerTypeAdapterFactory(with(RegistryReferenceFactory()) {
add(Registries.tiles) add(Registries.tiles)
add(Registries.tileModifiers) add(Registries.tileModifiers)

View File

@ -15,8 +15,8 @@ import org.lwjgl.system.MemoryStack
import org.lwjgl.system.MemoryUtil import org.lwjgl.system.MemoryUtil
import ru.dbotthepony.kstarbound.LoadingLog import ru.dbotthepony.kstarbound.LoadingLog
import ru.dbotthepony.kstarbound.util.ManualExecutorService import ru.dbotthepony.kstarbound.util.ManualExecutorService
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.client.freetype.FreeType import ru.dbotthepony.kstarbound.client.freetype.FreeType
import ru.dbotthepony.kstarbound.client.freetype.InvalidArgumentException 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.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kstarbound.client.input.UserInput 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.Camera
import ru.dbotthepony.kstarbound.client.render.Font import ru.dbotthepony.kstarbound.client.render.Font
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer import ru.dbotthepony.kstarbound.client.render.LayeredRenderer
@ -382,7 +381,6 @@ class StarboundClient : Closeable {
val freeType = FreeType() val freeType = FreeType()
val font = Font() val font = Font()
val box2dRenderer = Box2DRenderer()
val programs = GLPrograms() val programs = GLPrograms()
init { init {
@ -683,7 +681,8 @@ class StarboundClient : Closeable {
viewportRectangle = AABB.rectangle( viewportRectangle = AABB.rectangle(
camera.pos, camera.pos,
viewportWidth / settings.zoom / PIXELS_IN_STARBOUND_UNIT, 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 viewportCellX = roundTowardsNegativeInfinity(viewportRectangle.mins.x) - 16
viewportCellY = roundTowardsNegativeInfinity(viewportRectangle.mins.y) - 16 viewportCellY = roundTowardsNegativeInfinity(viewportRectangle.mins.y) - 16
@ -855,10 +854,6 @@ class StarboundClient : Closeable {
layers.render() layers.render()
box2dRenderer.begin()
world.physics.debugDraw()
box2dRenderer.render()
for (lambda in onPostDrawWorld) { for (lambda in onPostDrawWorld) {
lambda.invoke() lambda.invoke()
} }

View File

@ -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)
}
}

View File

@ -5,7 +5,7 @@ import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.Scheduler import com.github.benmanes.caffeine.cache.Scheduler
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL45.* 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.Registries
import ru.dbotthepony.kstarbound.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.* import ru.dbotthepony.kstarbound.client.gl.*

View File

@ -5,12 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.longs.LongArraySet import it.unimi.dsi.fastutil.longs.LongArraySet
import it.unimi.dsi.fastutil.objects.ObjectArrayList import it.unimi.dsi.fastutil.objects.ObjectArrayList
import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import ru.dbotthepony.kbox2d.api.BodyDef import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITf
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.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh import ru.dbotthepony.kstarbound.client.render.ConfiguredMesh
import ru.dbotthepony.kstarbound.client.render.LayeredRenderer 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.math.roundTowardsPositiveInfinity
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE import ru.dbotthepony.kstarbound.world.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.ChunkPos 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.World
import ru.dbotthepony.kstarbound.world.api.ITileAccess import ru.dbotthepony.kstarbound.world.api.ITileAccess
import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess import ru.dbotthepony.kstarbound.world.api.OffsetCellAccess
import ru.dbotthepony.kstarbound.world.api.TileView import ru.dbotthepony.kstarbound.world.api.TileView
import ru.dbotthepony.kstarbound.world.castRay
import ru.dbotthepony.kstarbound.world.positiveModulo import ru.dbotthepony.kstarbound.world.positiveModulo
import ru.dbotthepony.kvector.api.IStruct2i import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.util2d.AABB import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.RGBAColor import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector2i import ru.dbotthepony.kvector.vector.Vector2i
import java.util.concurrent.Callable import java.util.concurrent.Callable
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.Future import java.util.concurrent.Future
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
class ClientWorld( class ClientWorld(
val client: StarboundClient, val client: StarboundClient,
@ -50,10 +36,6 @@ class ClientWorld(
loopX: Boolean = false, loopX: Boolean = false,
loopY: Boolean = false loopY: Boolean = false
) : World<ClientWorld, ClientChunk>(seed, size, loopX, loopY) { ) : World<ClientWorld, ClientChunk>(seed, size, loopX, loopY) {
init {
physics.debugDraw = client.box2dRenderer
}
private fun determineChunkSize(cells: Int): Int { private fun determineChunkSize(cells: Int): Int {
for (i in 32 downTo 1) { for (i in 32 downTo 1) {
if (cells % i == 0) { if (cells % i == 0) {

View File

@ -7,11 +7,11 @@ import ru.dbotthepony.kstarbound.util.KOptional
@JsonImplementation(BaseMovementParameters.Impl::class) @JsonImplementation(BaseMovementParameters.Impl::class)
interface BaseMovementParameters { interface BaseMovementParameters {
val mass: KOptional<Float> val mass: KOptional<Double>
val gravityMultiplier: KOptional<Float> val gravityMultiplier: KOptional<Double>
val liquidBuoyancy: KOptional<Float> val liquidBuoyancy: KOptional<Double>
val airBuoyancy: KOptional<Float> val airBuoyancy: KOptional<Double>
val bounceFactor: KOptional<Float> val bounceFactor: KOptional<Double>
// If set to true, during an update that has more than one internal movement // If set to true, during an update that has more than one internal movement
// step, the movement will stop on the first bounce. // 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 // other directions (within a set limit). Allows smooth sliding along
// horizontal ground without losing horizontal speed. // horizontal ground without losing horizontal speed.
val enableSurfaceSlopeCorrection: KOptional<Boolean> val enableSurfaceSlopeCorrection: KOptional<Boolean>
val slopeSlidingFactor: KOptional<Float> val slopeSlidingFactor: KOptional<Double>
val maxMovementPerStep: KOptional<Float> val maxMovementPerStep: KOptional<Double>
val maximumCorrection: KOptional<Float> val maximumCorrection: KOptional<Double>
val speedLimit: KOptional<Float> val speedLimit: KOptional<Double>
val stickyCollision: KOptional<Boolean> val stickyCollision: KOptional<Boolean>
val stickyForce: KOptional<Float> val stickyForce: KOptional<Double>
val airFriction: KOptional<Float> val airFriction: KOptional<Double>
val liquidFriction: KOptional<Float> val liquidFriction: KOptional<Double>
val groundFriction: KOptional<Float> val groundFriction: KOptional<Double>
val collisionEnabled: KOptional<Boolean> val collisionEnabled: KOptional<Boolean>
val frictionEnabled: KOptional<Boolean> val frictionEnabled: KOptional<Boolean>
val gravityEnabled: KOptional<Boolean> val gravityEnabled: KOptional<Boolean>
val maximumPlatformCorrection: KOptional<Float> val maximumPlatformCorrection: KOptional<Double>
val maximumPlatformCorrectionVelocityFactor: KOptional<Float> val maximumPlatformCorrectionVelocityFactor: KOptional<Double>
val physicsEffectCategories: KOptional<ImmutableSet<String>> val physicsEffectCategories: KOptional<ImmutableSet<String>>
@JsonFactory @JsonFactory
data class Impl( data class Impl(
override val mass: KOptional<Float> = KOptional.empty(), override val mass: KOptional<Double> = KOptional.empty(),
override val gravityMultiplier: KOptional<Float> = KOptional.empty(), override val gravityMultiplier: KOptional<Double> = KOptional.empty(),
override val liquidBuoyancy: KOptional<Float> = KOptional.empty(), override val liquidBuoyancy: KOptional<Double> = KOptional.empty(),
override val airBuoyancy: KOptional<Float> = KOptional.empty(), override val airBuoyancy: KOptional<Double> = KOptional.empty(),
override val bounceFactor: KOptional<Float> = KOptional.empty(), override val bounceFactor: KOptional<Double> = KOptional.empty(),
override val stopOnFirstBounce: KOptional<Boolean> = KOptional.empty(), override val stopOnFirstBounce: KOptional<Boolean> = KOptional.empty(),
override val enableSurfaceSlopeCorrection: KOptional<Boolean> = KOptional.empty(), override val enableSurfaceSlopeCorrection: KOptional<Boolean> = KOptional.empty(),
override val slopeSlidingFactor: KOptional<Float> = KOptional.empty(), override val slopeSlidingFactor: KOptional<Double> = KOptional.empty(),
override val maxMovementPerStep: KOptional<Float> = KOptional.empty(), override val maxMovementPerStep: KOptional<Double> = KOptional.empty(),
override val maximumCorrection: KOptional<Float> = KOptional.empty(), override val maximumCorrection: KOptional<Double> = KOptional.empty(),
override val speedLimit: KOptional<Float> = KOptional.empty(), override val speedLimit: KOptional<Double> = KOptional.empty(),
override val stickyCollision: KOptional<Boolean> = KOptional.empty(), override val stickyCollision: KOptional<Boolean> = KOptional.empty(),
override val stickyForce: KOptional<Float> = KOptional.empty(), override val stickyForce: KOptional<Double> = KOptional.empty(),
override val airFriction: KOptional<Float> = KOptional.empty(), override val airFriction: KOptional<Double> = KOptional.empty(),
override val liquidFriction: KOptional<Float> = KOptional.empty(), override val liquidFriction: KOptional<Double> = KOptional.empty(),
override val groundFriction: KOptional<Float> = KOptional.empty(), override val groundFriction: KOptional<Double> = KOptional.empty(),
override val collisionEnabled: KOptional<Boolean> = KOptional.empty(), override val collisionEnabled: KOptional<Boolean> = KOptional.empty(),
override val frictionEnabled: KOptional<Boolean> = KOptional.empty(), override val frictionEnabled: KOptional<Boolean> = KOptional.empty(),
override val gravityEnabled: KOptional<Boolean> = KOptional.empty(), override val gravityEnabled: KOptional<Boolean> = KOptional.empty(),
override val maximumPlatformCorrection: KOptional<Float> = KOptional.empty(), override val maximumPlatformCorrection: KOptional<Double> = KOptional.empty(),
override val maximumPlatformCorrectionVelocityFactor: KOptional<Float> = KOptional.empty(), override val maximumPlatformCorrectionVelocityFactor: KOptional<Double> = KOptional.empty(),
override val physicsEffectCategories: KOptional<ImmutableSet<String>> = KOptional.empty(), override val physicsEffectCategories: KOptional<ImmutableSet<String>> = KOptional.empty(),
) : BaseMovementParameters { ) : BaseMovementParameters {
fun merge(other: Impl): Impl { fun merge(other: Impl): Impl {

View File

@ -8,7 +8,7 @@ import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import org.apache.logging.log4j.LogManager 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.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.render.IGeometryLayer import ru.dbotthepony.kstarbound.client.render.IGeometryLayer

View File

@ -1,10 +1,9 @@
package ru.dbotthepony.kstarbound.defs 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.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
import ru.dbotthepony.kstarbound.util.KOptional import ru.dbotthepony.kstarbound.util.KOptional
import ru.dbotthepony.kvector.vector.Vector2d import ru.dbotthepony.kstarbound.world.physics.Poly
@JsonFactory @JsonFactory
data class MovementParameters( data class MovementParameters(
@ -12,7 +11,7 @@ data class MovementParameters(
val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(), val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(),
val discontinuityThreshold: KOptional<Float> = KOptional.empty(), 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 ignorePlatformCollision: KOptional<Boolean> = KOptional.empty(),
val restDuration: KOptional<Int> = KOptional.empty(), val restDuration: KOptional<Int> = KOptional.empty(),
) : BaseMovementParameters by base { ) : BaseMovementParameters by base {

View File

@ -20,8 +20,8 @@ import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL45 import org.lwjgl.opengl.GL45
import org.lwjgl.stb.STBImage import org.lwjgl.stb.STBImage
import org.lwjgl.system.MemoryUtil import org.lwjgl.system.MemoryUtil
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNIT
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi import ru.dbotthepony.kstarbound.world.PIXELS_IN_STARBOUND_UNITi
import ru.dbotthepony.kstarbound.Starbound import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.api.IStarboundFile import ru.dbotthepony.kstarbound.api.IStarboundFile
import ru.dbotthepony.kstarbound.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient

View File

@ -10,7 +10,7 @@ import com.google.gson.TypeAdapter
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter 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.client.render.RenderLayer
import ru.dbotthepony.kstarbound.defs.Drawable import ru.dbotthepony.kstarbound.defs.Drawable
import ru.dbotthepony.kstarbound.defs.JsonReference import ru.dbotthepony.kstarbound.defs.JsonReference

View File

@ -1,14 +1,12 @@
package ru.dbotthepony.kstarbound.defs.player 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.BaseMovementParameters
import ru.dbotthepony.kstarbound.defs.JumpProfile import ru.dbotthepony.kstarbound.defs.JumpProfile
import ru.dbotthepony.kstarbound.io.json.builder.JsonAlias import ru.dbotthepony.kstarbound.io.json.builder.JsonAlias
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
import ru.dbotthepony.kstarbound.util.KOptional import ru.dbotthepony.kstarbound.util.KOptional
import ru.dbotthepony.kvector.vector.Vector2d import ru.dbotthepony.kstarbound.world.physics.Poly
@JsonFactory @JsonFactory
data class PlayerMovementParameters( data class PlayerMovementParameters(
@ -16,9 +14,9 @@ data class PlayerMovementParameters(
val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(), val base: BaseMovementParameters.Impl = BaseMovementParameters.Impl(),
@JsonAlias("collisionPoly") @JsonAlias("collisionPoly")
val standingPoly: KOptional<ImmutableList<Vector2d>> = KOptional.empty(), val standingPoly: KOptional<Poly> = KOptional.empty(),
@JsonAlias("collisionPoly") @JsonAlias("collisionPoly")
val crouchingPoly: KOptional<ImmutableList<Vector2d>> = KOptional.empty(), val crouchingPoly: KOptional<Poly> = KOptional.empty(),
val walkSpeed: KOptional<Double> = KOptional.empty(), val walkSpeed: KOptional<Double> = KOptional.empty(),
val runSpeed: KOptional<Double> = KOptional.empty(), val runSpeed: KOptional<Double> = KOptional.empty(),

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.AssetReference 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 import ru.dbotthepony.kstarbound.defs.ThingDescription
object BuiltinMetaMaterials { object BuiltinMetaMaterials {

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs.tile
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.AssetReference 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.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory

View File

@ -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())
}
}

View File

@ -1,10 +1,6 @@
package ru.dbotthepony.kstarbound.world package ru.dbotthepony.kstarbound.world
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet 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.BuiltinMetaMaterials
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
@ -49,8 +45,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
private set private set
var cellChangeset = 0 var cellChangeset = 0
private set private set
var collisionChangeset = 0
private set
var foregroundChangeset = 0 var foregroundChangeset = 0
private set private set
@ -101,28 +95,15 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
private val collisionCache = ArrayList<AABB>() private val collisionCache = ArrayList<AABB>()
private val collisionCacheView = Collections.unmodifiableCollection(collisionCache) 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) { protected open fun foregroundChanges(cell: Cell) {
cellChanges(cell) cellChanges(cell)
tileChangeset++ tileChangeset++
collisionChangeset++
foregroundChangeset++ foregroundChangeset++
markPhysicsDirty()
} }
protected open fun backgroundChanges(cell: Cell) { protected open fun backgroundChanges(cell: Cell) {
cellChanges(cell) cellChanges(cell)
tileChangeset++ tileChangeset++
backgroundChangeset++ backgroundChangeset++
} }
@ -147,14 +128,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
world.chunkMap[pos.bottomRight]?.let(block) 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 { inner class Cell(x: Int, y: Int) : IChunkCell {
override val x: Int = x + pos.x * CHUNK_SIZE override val x: Int = x + pos.x * CHUNK_SIZE
override val y: Int = y + pos.y * 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 { 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) return world.randomLongFor(x or pos.x shl CHUNK_SIZE_BITS, y or pos.y shl CHUNK_SIZE_BITS)
} }

View 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

View File

@ -1,6 +1,6 @@
package ru.dbotthepony.kstarbound.world 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.math.roundTowardsNegativeInfinity
import ru.dbotthepony.kstarbound.world.api.ICellAccess import ru.dbotthepony.kstarbound.world.api.ICellAccess
import ru.dbotthepony.kstarbound.world.api.IChunkCell import ru.dbotthepony.kstarbound.world.api.IChunkCell
@ -10,8 +10,6 @@ import kotlin.collections.ArrayList
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.sqrt import kotlin.math.sqrt
const val EARTH_FREEFALL_ACCELERATION = 9.8312 / METRES_IN_STARBOUND_UNIT
data class RayCastResult( data class RayCastResult(
val traversedTiles: List<HitCell>, val traversedTiles: List<HitCell>,
val hitTile: HitCell?, val hitTile: HitCell?,

View File

@ -5,14 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
import ru.dbotthepony.kbox2d.api.ContactImpulse import ru.dbotthepony.kstarbound.client.world.ClientWorld
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.math.* import ru.dbotthepony.kstarbound.math.*
import ru.dbotthepony.kstarbound.util.ManualExecutorService import ru.dbotthepony.kstarbound.util.ManualExecutorService
import ru.dbotthepony.kstarbound.world.api.ICellAccess 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.api.TileView
import ru.dbotthepony.kstarbound.world.entities.Entity import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.entities.WorldObject 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.IStruct2d
import ru.dbotthepony.kvector.api.IStruct2i import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.arrays.Object2DArray import ru.dbotthepony.kvector.arrays.Object2DArray
@ -30,12 +26,6 @@ import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.random.RandomGenerator 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") @Suppress("UNCHECKED_CAST")
abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>( abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, ChunkType>>(
val seed: Long, val seed: Long,
@ -244,81 +234,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
val random: RandomGenerator = RandomGenerator.of("Xoroshiro128PlusPlus") val random: RandomGenerator = RandomGenerator.of("Xoroshiro128PlusPlus")
/** var gravity = Vector2d(0.0, -EARTH_FREEFALL_ACCELERATION)
* 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 ticks = 0 var ticks = 0
private set private set
@ -326,12 +242,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
fun think() { fun think() {
try { try {
executor.executeQueuedTasks() executor.executeQueuedTasks()
for (chunk in dirtyPhysicsChunks)
chunk.bakeCollisions()
dirtyPhysicsChunks.clear()
physics.step(Starbound.TICK_TIME_ADVANCE, 6, 4)
thinkInner() thinkInner()
ticks++ ticks++
} catch(err: Throwable) { } catch(err: Throwable) {
@ -353,16 +263,9 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
val objects = ReferenceLinkedOpenHashSet<WorldObject>() val objects = ReferenceLinkedOpenHashSet<WorldObject>()
/**
* Стандартное ускорение свободного падения в Starbound Units/секунда^2
*
* При Vector2d.ZERO = невесомость
*/
var gravity by physics::gravity
protected abstract fun chunkFactory(pos: ChunkPos): ChunkType 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() val tiles = aabb.encasingIntAABB()
for (x in tiles.mins.x .. tiles.maxs.x) { 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 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
}
} }

View File

@ -32,9 +32,6 @@ interface IChunkCell : IStruct2i {
} }
val polies: Collection<Poly> get() { val polies: Collection<Poly> get() {
if (foreground.material.isMeta)
return emptyList()
return listOf(rect + Vector2d(this.x.toDouble(), this.y.toDouble())) return listOf(rect + Vector2d(this.x.toDouble(), this.y.toDouble()))
} }

View File

@ -1,15 +1,17 @@
package ru.dbotthepony.kstarbound.world.entities 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.client.StarboundClient
import ru.dbotthepony.kstarbound.defs.BaseMovementParameters
import ru.dbotthepony.kstarbound.world.Chunk import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.World import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kstarbound.world.physics.CollisionPoly
import ru.dbotthepony.kstarbound.world.physics.Poly import ru.dbotthepony.kstarbound.world.physics.Poly
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Vector2d import ru.dbotthepony.kvector.vector.Vector2d
abstract class Entity(val world: World<*, *>) { 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 var chunk: Chunk<*, *>? = null
set(value) { set(value) {
if (!isSpawned) { 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() var position = Vector2d()
set(value) { set(value) {
if (field == 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 var velocity = Vector2d.ZERO
val hitboxes = ArrayList<Poly>() val hitboxes = ArrayList<Poly>()
open var movementParameters: BaseMovementParameters = GlobalDefaults.movementParameters
/** /**
* Whenever is this entity spawned in world ([spawn] called). * Whenever is this entity spawned in world ([spawn] called).
@ -128,9 +102,6 @@ abstract class Entity(val world: World<*, *>) {
} }
} }
/**
* Заставляет сущность "думать".
*/
fun think() { fun think() {
if (!isSpawned) { if (!isSpawned) {
throw IllegalStateException("Tried to think before spawning in world") throw IllegalStateException("Tried to think before spawning in world")
@ -143,24 +114,20 @@ abstract class Entity(val world: World<*, *>) {
protected abstract fun thinkInner() protected abstract fun thinkInner()
protected open fun move() { protected open fun move() {
position += velocity velocity += world.gravity * Starbound.TICK_TIME_ADVANCE
position += velocity * Starbound.TICK_TIME_ADVANCE
val polies = ArrayList<Poly>() if (hitboxes.isEmpty()) return
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)
}
}
}
for (i in 0 until 10) { 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 intersects = ArrayList<Poly.Penetration<CollisionPoly>>()
val hitbox = hitbox0 + position
polies.forEach { poly -> hitbox.intersect(poly)?.let { intersects.add(it) } } localHitboxes.forEach { hitbox ->
polies.forEach { poly -> hitbox.intersect(poly.poly, poly)?.let { intersects.add(it) } }
} }
if (intersects.isEmpty()) if (intersects.isEmpty())
@ -170,7 +137,13 @@ abstract class Entity(val world: World<*, *>) {
// resolve collision // resolve collision
position += max.vector position += max.vector
// collision response // 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
} }
} }
} }

View File

@ -1,11 +1,5 @@
package ru.dbotthepony.kstarbound.world.entities 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.defs.item.api.IItemDefinition
import ru.dbotthepony.kstarbound.world.World import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kstarbound.world.physics.Poly import ru.dbotthepony.kstarbound.world.physics.Poly

View File

@ -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
)

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.kstarbound.defs package ru.dbotthepony.kstarbound.world.physics
enum class CollisionType(val isEmpty: Boolean) { enum class CollisionType(val isEmpty: Boolean) {
NULL(true), NULL(true),

View File

@ -1,10 +1,18 @@
package ru.dbotthepony.kstarbound.world.physics package ru.dbotthepony.kstarbound.world.physics
import com.google.common.collect.ImmutableList 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 it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import org.lwjgl.opengl.GL11.GL_LINES import org.lwjgl.opengl.GL11.GL_LINES
import ru.dbotthepony.kstarbound.client.StarboundClient import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType 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.api.IStruct2d
import ru.dbotthepony.kvector.arrays.Matrix3f import ru.dbotthepony.kvector.arrays.Matrix3f
import ru.dbotthepony.kvector.util2d.AABB 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 val vector = axis * penetration
override fun compareTo(other: Penetration): Int { override fun compareTo(other: Penetration<*>): Int {
return penetration.absoluteValue.compareTo(other.penetration.absoluteValue) 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 vertices = ImmutableList.Builder<Vector2d>()
val edges = ImmutableList.Builder<Edge>() val edges = ImmutableList.Builder<Edge>()
@ -136,7 +144,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
return Vector2d(min, max) return Vector2d(min, max)
} }
fun intersect(other: Poly): Penetration? { fun <T> intersect(other: Poly, data: T): Penetration<T>? {
if (!aabb.intersectWeak(other.aabb)) if (!aabb.intersectWeak(other.aabb))
return null return null
@ -144,7 +152,7 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
edges.forEach { normals.add(it.normal) } edges.forEach { normals.add(it.normal) }
other.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) { for (normal in normals) {
val projectThis = project(normal) val projectThis = project(normal)
@ -165,10 +173,10 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
if (minMin <= maxMax) { if (minMin <= maxMax) {
// push to left // push to left
intersections.add(Penetration(normal, -minMin - width)) intersections.add(Penetration(normal, -minMin - width, data))
} else { } else {
// push to right // push to right
intersections.add(Penetration(normal, maxMax + width)) intersections.add(Penetration(normal, maxMax + width, data))
} }
} else if ( } else if (
projectThis.component1() in projectOther.component1() .. projectOther.component2() && 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) { if (minMin <= maxMax) {
// push to left // push to left
intersections.add(Penetration(normal, -minMin - width)) intersections.add(Penetration(normal, -minMin - width, data))
} else { } else {
// push to right // 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()) { } else if (projectOther.component1() in projectThis.component1() .. projectThis.component2()) {
// other's min point is within this // 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 { } else {
// other's max point in within this // 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 return null
} }
} }
@ -205,19 +213,23 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
return intersections.min() return intersections.min()
} }
fun intersect(other: Poly) = intersect(other, Unit)
fun render(client: StarboundClient = StarboundClient.current(), color: RGBAColor = RGBAColor.LIGHT_GREEN) { fun render(client: StarboundClient = StarboundClient.current(), color: RGBAColor = RGBAColor.LIGHT_GREEN) {
val program = client.programs.position val program = client.programs.position
val lines = program.builder.builder val lines = program.builder.builder
program.use() program.use()
lines.begin(GeometryType.LINES) lines.begin(GeometryType.LINES)
val normalSize = (aabb.width.coerceAtMost(aabb.height) / 3.0).coerceAtLeast(0.1)
for (edge in edges) { for (edge in edges) {
val current = edge.p0 val current = edge.p0
val next = edge.p1 val next = edge.p1
lines.vertex(client.stack.last(), current) lines.vertex(client.stack.last(), current)
lines.vertex(client.stack.last(), next) lines.vertex(client.stack.last(), next)
lines.vertex(client.stack.last(), (next + current) / 2.0) 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 program.modelMatrix = identity
@ -227,10 +239,40 @@ class Poly private constructor(val edges: ImmutableList<Edge>, val vertices: Imm
} }
override fun toString(): String { 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() 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
}
} }
} }