Skip to content

Commit

Permalink
Got basic physics entity working
Browse files Browse the repository at this point in the history
  • Loading branch information
StewStrong authored and StewStrong committed Aug 18, 2023
1 parent a57ea93 commit 3fed532
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class VSPhysicsEntityRenderer(context: EntityRendererProvider.Context) : EntityR
poseStack.pushPose()
val blockPos = BlockPos(fallingBlockEntity.x, fallingBlockEntity.boundingBox.maxY, fallingBlockEntity.z)
poseStack.mulPose(fallingBlockEntity.rotation.toMinecraft())
poseStack.translate(-0.5, 0.0, -0.5)
poseStack.translate(-0.5, -0.5, -0.5)
val blockRenderDispatcher = Minecraft.getInstance().blockRenderer
blockRenderDispatcher.modelRenderer.tesselateBlock(
level, blockRenderDispatcher.getBlockModel(blockState), blockState, blockPos, poseStack,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,58 +1,137 @@
package org.valkyrienskies.mod.common.entity

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.protocol.Packet
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.level.Level
import org.joml.Quaternionf
import org.joml.Quaternionfc
import net.minecraft.world.level.entity.EntityInLevelCallback
import org.joml.Matrix3d
import org.joml.Quaterniond
import org.joml.Quaterniondc
import org.joml.Vector3d
import org.valkyrienskies.core.api.ships.properties.ShipId
import org.valkyrienskies.core.api.ships.properties.ShipInertiaData
import org.valkyrienskies.core.api.ships.properties.ShipTransform
import org.valkyrienskies.core.apigame.physics.PhysicsEntityData
import org.valkyrienskies.core.apigame.physics.PhysicsEntityServer
import org.valkyrienskies.core.apigame.physics.VSSphereCollisionShapeData
import org.valkyrienskies.core.apigame.world.ServerShipWorldCore
import org.valkyrienskies.core.impl.game.ships.ShipInertiaDataImpl
import org.valkyrienskies.core.impl.util.serialization.VSJacksonUtil
import org.valkyrienskies.mod.common.dimensionId
import org.valkyrienskies.mod.common.shipObjectWorld
import org.valkyrienskies.mod.common.util.toMinecraft

class VSPhysicsEntity(type: EntityType<VSPhysicsEntity>, level: Level) : Entity(type, level) {
private var shipId: ShipId? = null
var rotation: Quaternionfc = Quaternionf()
// Physics data, persistent
private var physicsEntityData: PhysicsEntityData? = null

fun setShipId(shipId: ShipId) {
if (this.shipId != null) {
throw IllegalStateException("Cannot define shipId, its already defined!")
// The physics entity, transient, only exists server side after this entity has been added to a world
private var physicsEntityServer: PhysicsEntityServer? = null

var rotation: Quaterniondc = Quaterniond()

fun setPhysicsEntityData(physicsEntityData: PhysicsEntityData) {
if (this.physicsEntityData != null) {
throw IllegalStateException("Cannot define physicsEntityData, its already defined!")
}
this.physicsEntityData = physicsEntityData
}

override fun tick() {
if (!this.level.isClientSide) {
val physicsEntityServerCopy = physicsEntityServer
if (physicsEntityServerCopy != null) {
this.setPos(physicsEntityServerCopy.shipTransform.positionInWorld.toMinecraft())
rotation = physicsEntityServerCopy.shipTransform.shipToWorldRotation
}
}
this.shipId = shipId
super.tick()
}

override fun defineSynchedData() {
// Naw, send pos/rotation using physics packets
// TODO: Send rotation
}

override fun readAdditionalSaveData(compoundTag: CompoundTag) {
this.shipId = compoundTag.getLong("shipId")
val physicsEntityDataAsBytes: ByteArray = compoundTag.getByteArray(PHYS_DATA_NBT_KEY)
val physicsEntityData = getMapper().readValue<PhysicsEntityData>(physicsEntityDataAsBytes)
setPhysicsEntityData(physicsEntityData)
}

override fun addAdditionalSaveData(compoundTag: CompoundTag) {
compoundTag.putLong("shipId", shipId!!)
val physicsEntityDataAsBytes = getMapper().writeValueAsBytes(physicsEntityData)
compoundTag.putByteArray(PHYS_DATA_NBT_KEY, physicsEntityDataAsBytes)
}

override fun getAddEntityPacket(): Packet<*> {
return ClientboundAddEntityPacket(this)
}

override fun saveWithoutId(compoundTag: CompoundTag): CompoundTag {
compoundTag.putLong("shipId", shipId!!)
compoundTag.putFloat("rotationX", rotation.x())
compoundTag.putFloat("rotationY", rotation.y())
compoundTag.putFloat("rotationZ", rotation.z())
compoundTag.putFloat("rotationW", rotation.w())
val physicsEntityDataAsBytes = getMapper().writeValueAsBytes(physicsEntityData)
compoundTag.putByteArray(PHYS_DATA_NBT_KEY, physicsEntityDataAsBytes)
return super.saveWithoutId(compoundTag)
}

override fun load(compoundTag: CompoundTag) {
this.shipId = compoundTag.getLong("shipId")
val rotationX = compoundTag.getFloat("rotationX")
val rotationY = compoundTag.getFloat("rotationY")
val rotationZ = compoundTag.getFloat("rotationZ")
val rotationW = compoundTag.getFloat("rotationW")
this.rotation = Quaternionf(rotationX, rotationY, rotationZ, rotationW)
if (!this.level.isClientSide && physicsEntityData != null) {
throw IllegalStateException("This entity is already loaded!")
}
val physicsEntityDataAsBytes: ByteArray = compoundTag.getByteArray(PHYS_DATA_NBT_KEY)
val physicsEntityData = getMapper().readValue<PhysicsEntityData>(physicsEntityDataAsBytes)
setPhysicsEntityData(physicsEntityData)
super.load(compoundTag)
}

override fun setLevelCallback(callback: EntityInLevelCallback?) {
super.setLevelCallback(callback)
if (!this.level.isClientSide) {
if (callback != null) {
// Try adding the rigid body of this entity from the world
if (physicsEntityServer != null) {
throw IllegalStateException("Rigid body is already in the world!")
}
physicsEntityServer = (level.shipObjectWorld as ServerShipWorldCore).createPhysicsEntity(
physicsEntityData!!, level.dimensionId
)
} else {
// Try removing the rigid body of this entity from the world
if (physicsEntityServer == null) {
throw IllegalStateException("Rigid body does not exist in the world!")
}
(level.shipObjectWorld as ServerShipWorldCore).deletePhysicsEntity(physicsEntityData!!.shipId)
physicsEntityServer = null
}
}
}

companion object {
private const val PHYS_DATA_NBT_KEY = "phys_entity_data"

private fun getMapper(): ObjectMapper {
return VSJacksonUtil.defaultMapper
}

fun createBasicSphereData(
shipId: ShipId, transform: ShipTransform, radius: Double = 0.5, mass: Double = 10000.0
): PhysicsEntityData {
val inertia = 0.4 * mass * radius * radius
val inertiaData: ShipInertiaData = ShipInertiaDataImpl(Vector3d(), mass, Matrix3d().scale(inertia))
val collisionShapeData = VSSphereCollisionShapeData(radius)
return PhysicsEntityData(
shipId = shipId,
transform = transform,
inertiaData = inertiaData,
linearVelocity = Vector3d(),
angularVelocity = Vector3d(),
collisionShapeData = collisionShapeData,
isStatic = false
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import net.minecraft.world.InteractionResult
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.UseOnContext
import org.joml.Vector3d
import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl.Companion
import org.valkyrienskies.mod.common.ValkyrienSkiesMod
import org.valkyrienskies.mod.common.dimensionId
import org.valkyrienskies.mod.common.entity.VSPhysicsEntity
import org.valkyrienskies.mod.common.shipObjectWorld
import org.valkyrienskies.mod.common.util.toJOML

class PhysicsEntityCreatorItem(
properties: Properties
Expand All @@ -22,7 +26,9 @@ class PhysicsEntityCreatorItem(
if (!level.isClientSide) {
val entity = ValkyrienSkiesMod.PHYSICS_ENTITY_TYPE.create(level)!!
val shipId = level.shipObjectWorld.allocateShipId(level.dimensionId)
entity.setShipId(shipId)
val transform = Companion.create(ctx.clickLocation.toJOML(), Vector3d())
val physicsEntityData = VSPhysicsEntity.createBasicSphereData(shipId, transform)
entity.setPhysicsEntityData(physicsEntityData)
entity.setPos(ctx.clickLocation)
level.addFreshEntity(entity)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import org.valkyrienskies.core.api.world.LevelYRange
import org.valkyrienskies.core.apigame.ShipTeleportData
import org.valkyrienskies.core.apigame.constraints.VSConstraint
import org.valkyrienskies.core.apigame.constraints.VSConstraintId
import org.valkyrienskies.core.apigame.physics.PhysicsEntityData
import org.valkyrienskies.core.apigame.physics.PhysicsEntityServer
import org.valkyrienskies.core.apigame.world.IPlayer
import org.valkyrienskies.core.apigame.world.ServerShipWorldCore
import org.valkyrienskies.core.apigame.world.chunks.BlockType
Expand Down Expand Up @@ -48,6 +50,14 @@ object DummyShipWorldServer : ServerShipWorldCore {
TODO("Not yet implemented")
}

override fun createPhysicsEntity(physicsEntityData: PhysicsEntityData, dimensionId: DimensionId): PhysicsEntityServer {
TODO("Not yet implemented")
}

override fun deletePhysicsEntity(id: ShipId) {
TODO("Not yet implemented")
}

override fun allocateShipId(dimensionId: DimensionId): ShipId {
TODO("Not yet implemented")
}
Expand Down
2 changes: 1 addition & 1 deletion vs-core

0 comments on commit 3fed532

Please sign in to comment.