Rewrite location classes and add Position, add packets for spawning entities
This commit is contained in:
parent
4d8a5ed603
commit
e7d5576269
38 changed files with 593 additions and 193 deletions
|
@ -17,5 +17,9 @@ allprojects {
|
||||||
tasks.withType<KotlinCompile> {
|
tasks.withType<KotlinCompile> {
|
||||||
kotlinOptions.jvmTarget = "14"
|
kotlinOptions.jvmTarget = "14"
|
||||||
kotlinOptions.freeCompilerArgs += "-progressive"
|
kotlinOptions.freeCompilerArgs += "-progressive"
|
||||||
|
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalStdlibApi"
|
||||||
|
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalUnsignedTypes"
|
||||||
|
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.time.ExperimentalTime"
|
||||||
|
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.contracts.ExperimentalContracts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,37 +19,44 @@ class EntitiesGenerator(
|
||||||
) {
|
) {
|
||||||
fun generate() {
|
fun generate() {
|
||||||
val entitiesJson = workingDir.resolve("entities.json").readText()
|
val entitiesJson = workingDir.resolve("entities.json").readText()
|
||||||
val entities = JsonIterator.deserialize(entitiesJson).asList()
|
val types = JsonIterator.deserialize(entitiesJson).asList()
|
||||||
|
|
||||||
generateEntityStubs(entities)
|
generateEntityTypes(types)
|
||||||
generateEntitiesList(entities)
|
generateEntityStubs(types)
|
||||||
|
generateEntityTypeList(types)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val typeLines = listOf("%L", "%S", "%Lf", "%Lf")
|
private fun generateEntityTypes(types: List<JsonAny>) {
|
||||||
|
for (entity in types) {
|
||||||
private fun generateEntityStubs(entities: List<JsonAny>) {
|
|
||||||
for (entity in entities) {
|
|
||||||
val name =
|
val name =
|
||||||
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, entity.get("name").toString())!! + "Entity"
|
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, entity.get("name").toString())!! + "EntityType"
|
||||||
|
|
||||||
val filePathRelativeToSourceRoot = "./${BLOCK_PACKAGE.replace(".", "/")}/$name.kt"
|
|
||||||
if (sourcesDir.resolve(filePathRelativeToSourceRoot).exists()) continue
|
|
||||||
|
|
||||||
val typeArgs = arrayOf(
|
|
||||||
entity.get("id").toInt(),
|
|
||||||
"minecraft:" + entity.get("name").toString(),
|
|
||||||
entity.get("width").toFloat(),
|
|
||||||
entity.get("height").toFloat()
|
|
||||||
)
|
|
||||||
|
|
||||||
val type = TypeSpec.classBuilder(name)
|
val type = TypeSpec.classBuilder(name)
|
||||||
.superclass(ENTITY_TYPE)
|
.addModifiers(KModifier.ABSTRACT)
|
||||||
.addType(
|
.primaryConstructor(FunSpec.constructorBuilder().addModifiers(KModifier.INTERNAL).build())
|
||||||
TypeSpec.companionObjectBuilder()
|
.addSuperinterface(ENTITY_TYPE_TYPE)
|
||||||
.addSuperinterface(
|
.addProperty(
|
||||||
ENTITY_TYPE_TYPE.parameterizedBy(ClassName(ENTITY_PACKAGE, name)),
|
PropertySpec
|
||||||
CodeBlock.of("type(\n${typeLines.joinToString(",\n") { " $it" }}\n)", *typeArgs)
|
.builder("numericID", Int::class, KModifier.OVERRIDE)
|
||||||
)
|
.initializer("%L", entity.get("id").toInt())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec
|
||||||
|
.builder("id", String::class, KModifier.OVERRIDE)
|
||||||
|
.initializer("%S", "minecraft:" + entity.get("name").toString())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec
|
||||||
|
.builder("width", Float::class, KModifier.OVERRIDE)
|
||||||
|
.initializer("%Lf", entity.get("width").toFloat())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec
|
||||||
|
.builder("height", Float::class, KModifier.OVERRIDE)
|
||||||
|
.initializer("%Lf", entity.get("height").toFloat())
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
@ -61,19 +68,48 @@ class EntitiesGenerator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateEntitiesList(entities: List<JsonAny>) {
|
private fun generateEntityStubs(types: List<JsonAny>) {
|
||||||
|
for (entity in types) {
|
||||||
|
val name =
|
||||||
|
CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, entity.get("name").toString())!! + "Entity"
|
||||||
|
|
||||||
|
val filePathRelativeToSourceRoot = "./${BLOCK_PACKAGE.replace(".", "/")}/$name.kt"
|
||||||
|
if (sourcesDir.resolve(filePathRelativeToSourceRoot).exists()) continue
|
||||||
|
|
||||||
|
val type = TypeSpec.classBuilder(name)
|
||||||
|
.superclass(ENTITY_TYPE)
|
||||||
|
.addProperty(
|
||||||
|
PropertySpec.builder("type", ENTITY_TYPE_TYPE, KModifier.OVERRIDE, KModifier.FINAL)
|
||||||
|
.initializer("Type")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.addType(
|
||||||
|
TypeSpec.companionObjectBuilder("Type")
|
||||||
|
.superclass(ClassName(ENTITY_PACKAGE, name + "Type"))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
FileSpec.builder(ENTITY_PACKAGE, name)
|
||||||
|
.addType(type)
|
||||||
|
.build()
|
||||||
|
.writeTo(outputDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateEntityTypeList(entities: List<JsonAny>) {
|
||||||
val names = entities
|
val names = entities
|
||||||
.map { it.get("name").toString() }
|
.map { it.get("name").toString() }
|
||||||
.map { CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, it) + "Entity" }
|
.map { CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, it) + "Entity" }
|
||||||
|
|
||||||
val property = PropertySpec.builder(
|
val property = PropertySpec.builder(
|
||||||
"GENERATED_ENTITIES",
|
"ENTITY_TYPES",
|
||||||
List::class.asTypeName().parameterizedBy(ENTITY_TYPE_TYPE.parameterizedBy(STAR))
|
List::class.asTypeName().parameterizedBy(ENTITY_TYPE_TYPE)
|
||||||
)
|
)
|
||||||
.initializer("listOf(\n${names.joinToString(",\n")}\n)")
|
.initializer("listOf(\n${names.joinToString(",\n")}\n)")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
FileSpec.builder(ENTITY_PACKAGE, "Entities")
|
FileSpec.builder(ENTITY_PACKAGE, "EntityTypes")
|
||||||
.addProperty(property)
|
.addProperty(property)
|
||||||
.build()
|
.build()
|
||||||
.writeTo(outputDir)
|
.writeTo(outputDir)
|
||||||
|
|
|
@ -15,10 +15,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.ExperimentalUnsignedTypes"
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
archiveFileName.set("TestPlugin.jar")
|
archiveFileName.set("TestPlugin.jar")
|
||||||
destinationDirectory.set(file("../serverData/plugins"))
|
destinationDirectory.set(file("../serverData/plugins"))
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
package space.uranos.testplugin
|
package space.uranos.testplugin
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.Uranos
|
import space.uranos.Uranos
|
||||||
import space.uranos.chat.TextComponent
|
import space.uranos.chat.TextComponent
|
||||||
import space.uranos.net.ServerListInfo
|
import space.uranos.net.ServerListInfo
|
||||||
|
@ -15,7 +16,6 @@ import space.uranos.plugin.Plugin
|
||||||
import space.uranos.testplugin.anvil.AnvilWorld
|
import space.uranos.testplugin.anvil.AnvilWorld
|
||||||
import space.uranos.world.Dimension
|
import space.uranos.world.Dimension
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
import space.uranos.world.WorldAndLocationWithRotation
|
|
||||||
import space.uranos.world.block.CraftingTableBlock
|
import space.uranos.world.block.CraftingTableBlock
|
||||||
import space.uranos.world.block.GreenWoolBlock
|
import space.uranos.world.block.GreenWoolBlock
|
||||||
import space.uranos.world.block.RedWoolBlock
|
import space.uranos.world.block.RedWoolBlock
|
||||||
|
@ -46,10 +46,11 @@ class TestPlugin: Plugin("Test", "1.0.0") {
|
||||||
event.gameMode = GameMode.CREATIVE
|
event.gameMode = GameMode.CREATIVE
|
||||||
event.canFly = true
|
event.canFly = true
|
||||||
event.flying = true
|
event.flying = true
|
||||||
event.initialWorldAndLocation = WorldAndLocationWithRotation(
|
event.initialWorldAndLocation = VoxelLocation
|
||||||
world,
|
.of(0, 2, 0)
|
||||||
VoxelLocation.of(0, 2, 0).atTopCenter().withRotation(0f, 0f)
|
.atTopCenter()
|
||||||
)
|
.withRotation(0f, 0f)
|
||||||
|
.inside(world)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,21 +35,9 @@ dependencies {
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
sourceSets["main"].kotlin.srcDir("src/main/generatedKotlin")
|
sourceSets["main"].kotlin.srcDir("src/main/generatedKotlin")
|
||||||
|
|
||||||
sourceSets.all {
|
|
||||||
languageSettings.enableLanguageFeature("InlineClasses")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
|
||||||
"-Xopt-in=kotlin.contracts.ExperimentalContracts",
|
|
||||||
"-Xopt-in=kotlin.ExperimentalUnsignedTypes",
|
|
||||||
"-Xopt-in=kotlin.RequiresOptIn"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
38
uranos-api/src/main/kotlin/space/uranos/Location.kt
Normal file
38
uranos-api/src/main/kotlin/space/uranos/Location.kt
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos
|
||||||
|
|
||||||
|
import space.uranos.world.VoxelLocation
|
||||||
|
import space.uranos.world.World
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a combination of x, y and z coordinates.
|
||||||
|
*/
|
||||||
|
data class Location(val x: Double, val y: Double, val z: Double) {
|
||||||
|
/**
|
||||||
|
* Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt],
|
||||||
|
* in contrast to [roundToBlock] which uses [Double.roundToInt].
|
||||||
|
*/
|
||||||
|
fun toVoxelLocation(): VoxelLocation = VoxelLocation(x.toInt(), y.toInt().toUByte(), z.toInt())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt],
|
||||||
|
* in contrast to [toVoxelLocation] which uses [Double.toInt].
|
||||||
|
*/
|
||||||
|
fun roundToBlock(): VoxelLocation = VoxelLocation(x.roundToInt(), y.roundToInt().toUByte(), z.roundToInt())
|
||||||
|
|
||||||
|
fun withRotation(yaw: Float, pitch: Float) = Position(x, y, z, yaw, pitch)
|
||||||
|
fun asVector() = Vector(x, y, z)
|
||||||
|
|
||||||
|
infix fun inside(world: World): Pair<World, Location> = world to this
|
||||||
|
|
||||||
|
operator fun get(part: CoordinatePart): Double = when (part) {
|
||||||
|
CoordinatePart.X -> x
|
||||||
|
CoordinatePart.Y -> y
|
||||||
|
CoordinatePart.Z -> z
|
||||||
|
}
|
||||||
|
}
|
53
uranos-api/src/main/kotlin/space/uranos/Position.kt
Normal file
53
uranos-api/src/main/kotlin/space/uranos/Position.kt
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos
|
||||||
|
|
||||||
|
import space.uranos.world.VoxelLocation
|
||||||
|
import space.uranos.world.World
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A combination of x, y and z coordinates and an orientation (yaw and pitch).
|
||||||
|
*
|
||||||
|
* @param yaw The yaw rotation in degrees. Must be in `[0; 360[`.
|
||||||
|
* @param pitch The pitch rotation as a value between -90 (up) and 90 (down).
|
||||||
|
*/
|
||||||
|
data class Position(val x: Double, val y: Double, val z: Double, val yaw: Float, val pitch: Float) {
|
||||||
|
init {
|
||||||
|
if (yaw >= 360) throw IllegalArgumentException("yaw must be lower than 360")
|
||||||
|
if (yaw < 0) throw IllegalArgumentException("yaw must not be negative")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt],
|
||||||
|
* in contrast to [roundToBlock] which uses [Double.roundToInt].
|
||||||
|
*/
|
||||||
|
fun toVoxelLocation(): VoxelLocation = VoxelLocation(x.toInt(), y.toInt().toUByte(), z.toInt())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts this Position to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt],
|
||||||
|
* in contrast to [toVoxelLocation] which uses [Double.toInt].
|
||||||
|
*/
|
||||||
|
fun roundToBlock(): VoxelLocation = VoxelLocation(x.roundToInt(), y.roundToInt().toUByte(), z.roundToInt())
|
||||||
|
|
||||||
|
fun toLocation(): Location = Location(x, y, z)
|
||||||
|
fun toVector() = Vector(x, y, z)
|
||||||
|
infix fun inside(world: World): Pair<World, Position> = world to this
|
||||||
|
|
||||||
|
val yawIn256Steps get() = ((yaw / 360) * 256).toInt().toUByte()
|
||||||
|
val pitchIn256Steps get() = ((yaw / 360) * 256).toInt().toUByte()
|
||||||
|
|
||||||
|
operator fun get(part: CoordinatePart): Double = when (part) {
|
||||||
|
CoordinatePart.X -> x
|
||||||
|
CoordinatePart.Y -> y
|
||||||
|
CoordinatePart.Z -> z
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val ZERO = Position(0.0, 0.0, 0.0, 0f, 0f)
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@
|
||||||
package space.uranos
|
package space.uranos
|
||||||
|
|
||||||
import space.uranos.util.clamp
|
import space.uranos.util.clamp
|
||||||
import space.uranos.world.Location
|
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
@ -51,6 +50,8 @@ data class Vector(val x: Double, val y: Double, val z: Double) {
|
||||||
|
|
||||||
return sqrt(sqrt(x.pow(2) + y.pow(2)) + z.pow(2))
|
return sqrt(sqrt(x.pow(2) + y.pow(2)) + z.pow(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ZERO = Vector(0.0, 0.0, 0.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,24 +5,13 @@
|
||||||
|
|
||||||
package space.uranos.entity
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.Location
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
abstract class Entity internal constructor() {
|
abstract class Entity internal constructor() {
|
||||||
val uuid: UUID = UUID.randomUUID()
|
val uuid: UUID = UUID.randomUUID()
|
||||||
|
|
||||||
companion object {
|
abstract val type: EntityType
|
||||||
internal inline fun <reified T : Entity> type(
|
val globallyUniqueNumericID: Int = 0 // TODO: Get a real value
|
||||||
numericID: Int,
|
|
||||||
id: String,
|
|
||||||
width: Float,
|
|
||||||
height: Float
|
|
||||||
) : EntityType<T> = object : EntityType<T> {
|
|
||||||
override val entityClass: KClass<T> = T::class
|
|
||||||
override val numericID: Int = numericID
|
|
||||||
override val id: String = id
|
|
||||||
override val width: Float = width
|
|
||||||
override val height: Float = height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@ package space.uranos.entity
|
||||||
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
interface EntityType<T : Entity> {
|
interface EntityType {
|
||||||
val entityClass: KClass<T>
|
|
||||||
val numericID: Int
|
val numericID: Int
|
||||||
val id: String
|
val id: String
|
||||||
val width: Float
|
val width: Float
|
||||||
|
@ -18,13 +17,7 @@ interface EntityType<T : Entity> {
|
||||||
/**
|
/**
|
||||||
* All entity types, sorted by their numeric ID in ascending order.
|
* All entity types, sorted by their numeric ID in ascending order.
|
||||||
*/
|
*/
|
||||||
val all = GENERATED_ENTITIES
|
val all = ENTITY_TYPES
|
||||||
val byID = GENERATED_ENTITIES.map { it.id to it }.toMap()
|
val byID = ENTITY_TYPES.map { it.id to it }.toMap()
|
||||||
|
|
||||||
private val byClass = GENERATED_ENTITIES.map { it.entityClass to it }.toMap()
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun <T: Entity> byClass(entityClass: KClass<T>): EntityType<T>? = byClass[entityClass] as EntityType<T>?
|
|
||||||
inline fun <reified T: Entity> byClass(): EntityType<T>? = byClass(T::class)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
uranos-api/src/main/kotlin/space/uranos/entity/ItemEntity.kt
Normal file
14
uranos-api/src/main/kotlin/space/uranos/entity/ItemEntity.kt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
|
||||||
|
class ItemEntity(override var position: Position) : ObjectEntity() {
|
||||||
|
override val type: EntityType = Type
|
||||||
|
|
||||||
|
companion object Type : ItemEntityType()
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
|
||||||
|
abstract class LivingEntity : Entity(), Mobile {
|
||||||
|
abstract val headPitch: Float
|
||||||
|
abstract override val position: Position
|
||||||
|
abstract override val velocity: Vector
|
||||||
|
}
|
18
uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt
Normal file
18
uranos-api/src/main/kotlin/space/uranos/entity/Mobile.kt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
|
||||||
|
interface Mobile {
|
||||||
|
val position: Position
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The velocity in blocks per tick.
|
||||||
|
*/
|
||||||
|
val velocity: Vector
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
|
||||||
|
abstract class ObjectEntity : Entity(), Mobile {
|
||||||
|
abstract override var position: Position
|
||||||
|
|
||||||
|
final override var velocity: Vector = Vector.ZERO
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
import space.uranos.CardinalDirection
|
||||||
|
import space.uranos.world.VoxelLocation
|
||||||
|
|
||||||
|
class PaintingEntity(
|
||||||
|
val topLeftLocation: VoxelLocation,
|
||||||
|
val direction: CardinalDirection,
|
||||||
|
val motive: PaintingMotive
|
||||||
|
) : Entity() {
|
||||||
|
override val type: EntityType = Type
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
companion object Type : PaintingEntityType()
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.entity
|
||||||
|
|
||||||
|
enum class PaintingMotive(val width: Int, val height: Int) {
|
||||||
|
// Order is important
|
||||||
|
KEBAB(1, 1),
|
||||||
|
AZTEC(1, 1),
|
||||||
|
ALBAN(1, 1),
|
||||||
|
AZTEC2(1, 1),
|
||||||
|
BOMB(1, 1),
|
||||||
|
PLANT(1, 1),
|
||||||
|
WASTELAND(1, 1),
|
||||||
|
POOL(2, 1),
|
||||||
|
COURBET(2, 1),
|
||||||
|
SEA(2, 1),
|
||||||
|
SUNSET(2, 1),
|
||||||
|
CREEBET(2, 1),
|
||||||
|
WANDERER(1, 2),
|
||||||
|
GRAHAM(1, 2),
|
||||||
|
MATCH(2, 2),
|
||||||
|
BUST(2, 2),
|
||||||
|
STAGE(2, 2),
|
||||||
|
VOID(2, 2),
|
||||||
|
SKULL_AND_ROSES(2, 2),
|
||||||
|
WITHER(2, 2),
|
||||||
|
FIGHTERS(4, 2),
|
||||||
|
POINTER(4, 4),
|
||||||
|
PIGSCENE(4, 4),
|
||||||
|
BURNING_SKULL(4, 4),
|
||||||
|
SKELETON(4, 3),
|
||||||
|
DONKEY_KONG(4, 3);
|
||||||
|
|
||||||
|
val numericID = ordinal
|
||||||
|
}
|
|
@ -6,13 +6,14 @@
|
||||||
package space.uranos.net
|
package space.uranos.net
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf
|
import io.netty.buffer.ByteBuf
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.chat.TextComponent
|
import space.uranos.chat.TextComponent
|
||||||
import space.uranos.event.EventBusWrapper
|
import space.uranos.event.EventBusWrapper
|
||||||
import space.uranos.net.packet.OutgoingPacket
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
import space.uranos.net.packet.Protocol
|
import space.uranos.net.packet.Protocol
|
||||||
import space.uranos.player.GameMode
|
import space.uranos.player.GameMode
|
||||||
import space.uranos.player.Player
|
import space.uranos.player.Player
|
||||||
import space.uranos.world.WorldAndLocationWithRotation
|
import space.uranos.world.World
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
@ -73,7 +74,8 @@ abstract class Session {
|
||||||
val flyingSpeed: Float,
|
val flyingSpeed: Float,
|
||||||
val fieldOfView: Float,
|
val fieldOfView: Float,
|
||||||
val gameMode: GameMode,
|
val gameMode: GameMode,
|
||||||
val initialWorldAndLocation: WorldAndLocationWithRotation,
|
val world: World,
|
||||||
|
val position: Position,
|
||||||
val invulnerable: Boolean,
|
val invulnerable: Boolean,
|
||||||
val reducedDebugInfo: Boolean,
|
val reducedDebugInfo: Boolean,
|
||||||
val selectedHotbarSlot: Int
|
val selectedHotbarSlot: Int
|
||||||
|
|
|
@ -5,11 +5,12 @@
|
||||||
|
|
||||||
package space.uranos.net.event
|
package space.uranos.net.event
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.event.Cancellable
|
import space.uranos.event.Cancellable
|
||||||
import space.uranos.net.Session
|
import space.uranos.net.Session
|
||||||
import space.uranos.player.GameMode
|
import space.uranos.player.GameMode
|
||||||
import space.uranos.player.Player
|
import space.uranos.player.Player
|
||||||
import space.uranos.world.WorldAndLocationWithRotation
|
import space.uranos.world.World
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted after a [Session] finished logging in.
|
* Emitted after a [Session] finished logging in.
|
||||||
|
@ -27,7 +28,7 @@ class SessionAfterLoginEvent(override val target: Session) : SessionEvent(), Can
|
||||||
/**
|
/**
|
||||||
* The location where the player will spawn. If this is null after all handlers ran, the session is disconnected.
|
* The location where the player will spawn. If this is null after all handlers ran, the session is disconnected.
|
||||||
*/
|
*/
|
||||||
var initialWorldAndLocation: WorldAndLocationWithRotation? = null
|
var initialWorldAndLocation: Pair<World, Position>? = null
|
||||||
|
|
||||||
var maxViewDistance: Int = 32
|
var maxViewDistance: Int = 32
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
package space.uranos.player
|
package space.uranos.player
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.chat.TextComponent
|
import space.uranos.chat.TextComponent
|
||||||
import space.uranos.net.Session
|
import space.uranos.net.Session
|
||||||
import space.uranos.world.Chunk
|
import space.uranos.world.Chunk
|
||||||
import space.uranos.world.LocationWithRotation
|
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
import space.uranos.world.World
|
import space.uranos.world.World
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -55,9 +55,9 @@ interface Player {
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current location of this player.
|
* The current position of this player.
|
||||||
*/
|
*/
|
||||||
var location: LocationWithRotation
|
var position: Position
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The world which currently contains this player.
|
* The world which currently contains this player.
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
|
||||||
*/
|
|
||||||
|
|
||||||
package space.uranos.world
|
|
||||||
|
|
||||||
import space.uranos.CoordinatePart
|
|
||||||
import space.uranos.Vector
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
sealed class AbstractWorldAndLocation<T : AbstractLocation> {
|
|
||||||
abstract val world: World
|
|
||||||
abstract val location: T
|
|
||||||
}
|
|
||||||
|
|
||||||
data class WorldAndLocation(
|
|
||||||
override val world: World,
|
|
||||||
override val location: Location
|
|
||||||
) : AbstractWorldAndLocation<Location>()
|
|
||||||
|
|
||||||
data class WorldAndLocationWithRotation(
|
|
||||||
override val world: World,
|
|
||||||
override val location: LocationWithRotation
|
|
||||||
) : AbstractWorldAndLocation<LocationWithRotation>()
|
|
||||||
|
|
||||||
sealed class AbstractLocation {
|
|
||||||
abstract val x: Double
|
|
||||||
abstract val y: Double
|
|
||||||
abstract val z: Double
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.toInt],
|
|
||||||
* in contrast to [roundToBlock] which uses [Double.roundToInt].
|
|
||||||
*/
|
|
||||||
fun toVoxelLocation(): VoxelLocation = VoxelLocation(x.toInt(), y.toInt().toUByte(), z.toInt())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this Location to a VoxelLocation by converting [x], [y] and [z] to integers using [Double.roundToInt],
|
|
||||||
* in contrast to [toVoxelLocation] which uses [Double.toInt].
|
|
||||||
*/
|
|
||||||
fun roundToBlock(): VoxelLocation = VoxelLocation(x.roundToInt(), y.roundToInt().toUByte(), z.roundToInt())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a LocationWithRotation composed of this location, [yaw] and [pitch].
|
|
||||||
*/
|
|
||||||
fun withRotation(yaw: Float, pitch: Float) = LocationWithRotation(x, y, z, yaw, pitch)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a pair of [world] and this location.
|
|
||||||
*/
|
|
||||||
abstract infix fun inside(world: World): AbstractWorldAndLocation<*>
|
|
||||||
|
|
||||||
operator fun get(part: CoordinatePart): Double = when (part) {
|
|
||||||
CoordinatePart.X -> x
|
|
||||||
CoordinatePart.Y -> y
|
|
||||||
CoordinatePart.Z -> z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a set of x, y and z coordinates.
|
|
||||||
*
|
|
||||||
* Whenever used as a type, [AbstractLocation] should be preferred so that [LocationWithRotation] is also a valid value.
|
|
||||||
*/
|
|
||||||
data class Location(override val x: Double, override val y: Double, override val z: Double) : AbstractLocation() {
|
|
||||||
override fun inside(world: World) = WorldAndLocation(world, this)
|
|
||||||
|
|
||||||
fun asVector() = Vector(x, y, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class LocationWithRotation(
|
|
||||||
override val x: Double,
|
|
||||||
override val y: Double,
|
|
||||||
override val z: Double,
|
|
||||||
val yaw: Float,
|
|
||||||
val pitch: Float
|
|
||||||
) : AbstractLocation() {
|
|
||||||
override fun inside(world: World) = WorldAndLocationWithRotation(world, this)
|
|
||||||
|
|
||||||
fun toVector() = Vector(x, y, z)
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@
|
||||||
package space.uranos.world
|
package space.uranos.world
|
||||||
|
|
||||||
import space.uranos.CoordinatePart
|
import space.uranos.CoordinatePart
|
||||||
|
import space.uranos.Location
|
||||||
import space.uranos.Vector
|
import space.uranos.Vector
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
package space.uranos.world.block
|
package space.uranos.world.block
|
||||||
|
|
||||||
|
import kotlin.annotation.Target
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @suppress
|
* @suppress
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,10 +27,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ object JoinGamePacketCodec : OutgoingPacketCodec<JoinGamePacket>(0x24, JoinGameP
|
||||||
dst.writeVarInt(1)
|
dst.writeVarInt(1)
|
||||||
dst.writeString("uranos:world")
|
dst.writeString("uranos:world")
|
||||||
|
|
||||||
val dimensionsByID = Uranos.dimensionRegistry.items.values.mapIndexed { index, dimension ->
|
val dimensionsByID = Uranos.dimensionRegistry.items.values.map { dimension ->
|
||||||
dimension.id to buildNBT {
|
dimension.id to buildNBT {
|
||||||
"natural" setAsByte !dimension.compassesSpinRandomly
|
"natural" setAsByte !dimension.compassesSpinRandomly
|
||||||
"ambient_light" set dimension.ambientLight
|
"ambient_light" set dimension.ambientLight
|
||||||
|
|
|
@ -26,6 +26,10 @@ object PlayProtocol : Protocol(
|
||||||
ServerDifficultyPacketCodec,
|
ServerDifficultyPacketCodec,
|
||||||
SetCompassTargetPacketCodec,
|
SetCompassTargetPacketCodec,
|
||||||
SetSelectedHotbarSlotPacketCodec,
|
SetSelectedHotbarSlotPacketCodec,
|
||||||
|
SpawnExperienceOrbPacketCodec,
|
||||||
|
SpawnLivingEntityPacketCodec,
|
||||||
|
SpawnObjectEntityPacketCodec,
|
||||||
|
SpawnPaintingPacketCodec,
|
||||||
TagsPacketCodec,
|
TagsPacketCodec,
|
||||||
UpdateViewPositionPacketCodec
|
UpdateViewPositionPacketCodec
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,11 +13,11 @@ import space.uranos.util.bitmask
|
||||||
object PlayerPositionAndLookPacketCodec :
|
object PlayerPositionAndLookPacketCodec :
|
||||||
OutgoingPacketCodec<PlayerPositionAndLookPacket>(0x34, PlayerPositionAndLookPacket::class) {
|
OutgoingPacketCodec<PlayerPositionAndLookPacket>(0x34, PlayerPositionAndLookPacket::class) {
|
||||||
override fun PlayerPositionAndLookPacket.encode(dst: ByteBuf) {
|
override fun PlayerPositionAndLookPacket.encode(dst: ByteBuf) {
|
||||||
dst.writeDouble(locationWithRotation.x)
|
dst.writeDouble(position.x)
|
||||||
dst.writeDouble(locationWithRotation.y)
|
dst.writeDouble(position.y)
|
||||||
dst.writeDouble(locationWithRotation.z)
|
dst.writeDouble(position.z)
|
||||||
dst.writeFloat(locationWithRotation.yaw)
|
dst.writeFloat(position.yaw)
|
||||||
dst.writeFloat(locationWithRotation.pitch)
|
dst.writeFloat(position.pitch)
|
||||||
dst.writeByte(bitmask(relativeX, relativeY, relativeZ, relativeYaw, relativePitch))
|
dst.writeByte(bitmask(relativeX, relativeY, relativeZ, relativeYaw, relativePitch))
|
||||||
dst.writeVarInt(0) // Teleport ID, I am not sure why this is needed
|
dst.writeVarInt(0) // Teleport ID, I am not sure why this is needed
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import space.uranos.Difficulty
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
|
import space.uranos.net.packet.OutgoingPacketCodec
|
||||||
|
|
||||||
|
object SpawnExperienceOrbPacketCodec : OutgoingPacketCodec<SpawnExperienceOrbPacket>(0x01, SpawnExperienceOrbPacket::class) {
|
||||||
|
override fun SpawnExperienceOrbPacket.encode(dst: ByteBuf) {
|
||||||
|
dst.writeVarInt(entityID)
|
||||||
|
dst.writeDouble(location.x)
|
||||||
|
dst.writeDouble(location.y)
|
||||||
|
dst.writeDouble(location.z)
|
||||||
|
dst.writeShort(amount.toInt())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import space.uranos.Difficulty
|
||||||
|
import space.uranos.entity.LivingEntity
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeUUID
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
|
import space.uranos.net.packet.OutgoingPacketCodec
|
||||||
|
|
||||||
|
object SpawnLivingEntityPacketCodec : OutgoingPacketCodec<SpawnLivingEntityPacket>(0x02, SpawnLivingEntityPacket::class) {
|
||||||
|
@Suppress("DuplicatedCode")
|
||||||
|
override fun SpawnLivingEntityPacket.encode(dst: ByteBuf) {
|
||||||
|
dst.writeVarInt(entityID)
|
||||||
|
dst.writeUUID(uuid)
|
||||||
|
dst.writeVarInt(type.numericID)
|
||||||
|
dst.writeDouble(position.x)
|
||||||
|
dst.writeDouble(position.y)
|
||||||
|
dst.writeDouble(position.z)
|
||||||
|
dst.writeByte(position.yawIn256Steps.toInt())
|
||||||
|
dst.writeByte(position.pitchIn256Steps.toInt())
|
||||||
|
dst.writeByte(((headPitch / 360) * 256).toInt())
|
||||||
|
dst.writeShort((velocity.x * 8000).toInt().toShort().toInt())
|
||||||
|
dst.writeShort((velocity.y * 8000).toInt().toShort().toInt())
|
||||||
|
dst.writeShort((velocity.z * 8000).toInt().toShort().toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPacketFromEntity(entity: LivingEntity) = SpawnLivingEntityPacket(
|
||||||
|
entity.globallyUniqueNumericID,
|
||||||
|
entity.uuid,
|
||||||
|
entity.type,
|
||||||
|
entity.position,
|
||||||
|
entity.headPitch,
|
||||||
|
entity.velocity
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import space.uranos.entity.Entity
|
||||||
|
import space.uranos.entity.ItemEntity
|
||||||
|
import space.uranos.entity.ObjectEntity
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeUUID
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
|
import space.uranos.net.packet.OutgoingPacketCodec
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
object SpawnObjectEntityPacketCodec : OutgoingPacketCodec<SpawnObjectEntityPacket>(0x00, SpawnObjectEntityPacket::class) {
|
||||||
|
@Suppress("DuplicatedCode")
|
||||||
|
override fun SpawnObjectEntityPacket.encode(dst: ByteBuf) {
|
||||||
|
dst.writeVarInt(entityID)
|
||||||
|
dst.writeUUID(uuid)
|
||||||
|
dst.writeVarInt(type.numericID)
|
||||||
|
dst.writeDouble(position.x)
|
||||||
|
dst.writeDouble(position.y)
|
||||||
|
dst.writeDouble(position.z)
|
||||||
|
dst.writeByte(position.yawIn256Steps.toInt())
|
||||||
|
dst.writeByte(position.pitchIn256Steps.toInt())
|
||||||
|
dst.writeInt(data)
|
||||||
|
dst.writeShort((velocity.x * 8000).toInt().toShort().toInt())
|
||||||
|
dst.writeShort((velocity.y * 8000).toInt().toShort().toInt())
|
||||||
|
dst.writeShort((velocity.z * 8000).toInt().toShort().toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPacketFromEntity(entity: ObjectEntity) = SpawnObjectEntityPacket(
|
||||||
|
entity.globallyUniqueNumericID,
|
||||||
|
entity.uuid,
|
||||||
|
entity.type,
|
||||||
|
entity.position,
|
||||||
|
getDataForEntity(entity),
|
||||||
|
entity.velocity
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getDataForEntity(entity: ObjectEntity): Int = when(entity) {
|
||||||
|
is ItemEntity -> 1
|
||||||
|
// TODO: Add remaining
|
||||||
|
else -> throw IllegalArgumentException("Unknown entity type")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import space.uranos.CardinalDirection
|
||||||
|
import space.uranos.Difficulty
|
||||||
|
import space.uranos.entity.PaintingEntity
|
||||||
|
import space.uranos.entity.PaintingMotive
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeUUID
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVarInt
|
||||||
|
import space.uranos.net.MinecraftProtocolDataTypes.writeVoxelLocation
|
||||||
|
import space.uranos.net.packet.OutgoingPacketCodec
|
||||||
|
import space.uranos.world.Voxel
|
||||||
|
import space.uranos.world.VoxelLocation
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
object SpawnPaintingPacketCodec : OutgoingPacketCodec<SpawnPaintingPacket>(0x03, SpawnPaintingPacket::class) {
|
||||||
|
override fun SpawnPaintingPacket.encode(dst: ByteBuf) {
|
||||||
|
dst.writeVarInt(entityID)
|
||||||
|
dst.writeUUID(uuid)
|
||||||
|
dst.writeVarInt(motive.numericID)
|
||||||
|
dst.writeVoxelLocation(centerLocation)
|
||||||
|
dst.writeByte(when(direction) {
|
||||||
|
CardinalDirection.NORTH -> 2
|
||||||
|
CardinalDirection.SOUTH -> 0
|
||||||
|
CardinalDirection.WEST -> 1
|
||||||
|
CardinalDirection.EAST -> 3
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPacketFromEntity(entity: PaintingEntity) = SpawnPaintingPacket(
|
||||||
|
entity.globallyUniqueNumericID,
|
||||||
|
entity.uuid,
|
||||||
|
entity.motive,
|
||||||
|
getCenterLocation(entity.topLeftLocation, entity.motive),
|
||||||
|
entity.direction
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getCenterLocation(topLeftLocation: VoxelLocation, motive: PaintingMotive): VoxelLocation =
|
||||||
|
topLeftLocation.copy(
|
||||||
|
x = max(0, motive.width / 2) + topLeftLocation.x,
|
||||||
|
z = motive.height / 2 + topLeftLocation.z
|
||||||
|
)
|
||||||
|
}
|
|
@ -5,15 +5,15 @@
|
||||||
|
|
||||||
package space.uranos.net.packet.play
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.net.packet.OutgoingPacket
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
import space.uranos.world.LocationWithRotation
|
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Teleports the receiving player to the specified location.
|
* Teleports the receiving player to the specified position.
|
||||||
*/
|
*/
|
||||||
data class PlayerPositionAndLookPacket(
|
data class PlayerPositionAndLookPacket(
|
||||||
val locationWithRotation: LocationWithRotation,
|
val position: Position,
|
||||||
val relativeX: Boolean = false,
|
val relativeX: Boolean = false,
|
||||||
val relativeY: Boolean = false,
|
val relativeY: Boolean = false,
|
||||||
val relativeZ: Boolean = false,
|
val relativeZ: Boolean = false,
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.Location
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
import space.uranos.entity.EntityType
|
||||||
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
|
import space.uranos.world.Chunk
|
||||||
|
import space.uranos.world.ChunkData
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sent to spawn experience orbs.
|
||||||
|
*/
|
||||||
|
data class SpawnExperienceOrbPacket(
|
||||||
|
val entityID: Int,
|
||||||
|
val location: Location,
|
||||||
|
val amount: Short
|
||||||
|
) : OutgoingPacket()
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
import space.uranos.entity.EntityType
|
||||||
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
|
import space.uranos.world.Chunk
|
||||||
|
import space.uranos.world.ChunkData
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sent to spawn **living** entities.
|
||||||
|
*/
|
||||||
|
data class SpawnLivingEntityPacket(
|
||||||
|
val entityID: Int,
|
||||||
|
val uuid: UUID,
|
||||||
|
val type: EntityType,
|
||||||
|
val position: Position,
|
||||||
|
val headPitch: Float,
|
||||||
|
/**
|
||||||
|
* Velocity in blocks per tick
|
||||||
|
*/
|
||||||
|
val velocity: Vector
|
||||||
|
) : OutgoingPacket()
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
|
import space.uranos.Vector
|
||||||
|
import space.uranos.entity.EntityType
|
||||||
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
|
import space.uranos.world.Chunk
|
||||||
|
import space.uranos.world.ChunkData
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sent to spawn object entities.
|
||||||
|
*/
|
||||||
|
data class SpawnObjectEntityPacket(
|
||||||
|
val entityID: Int,
|
||||||
|
val uuid: UUID,
|
||||||
|
val type: EntityType,
|
||||||
|
val position: Position,
|
||||||
|
val data: Int,
|
||||||
|
val velocity: Vector
|
||||||
|
) : OutgoingPacket()
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020-2021 Moritz Ruth and Uranos contributors
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
package space.uranos.net.packet.play
|
||||||
|
|
||||||
|
import space.uranos.CardinalDirection
|
||||||
|
import space.uranos.Location
|
||||||
|
import space.uranos.entity.PaintingMotive
|
||||||
|
import space.uranos.net.packet.OutgoingPacket
|
||||||
|
import space.uranos.world.VoxelLocation
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sent to spawn **living** entities.
|
||||||
|
*/
|
||||||
|
data class SpawnPaintingPacket(
|
||||||
|
val entityID: Int,
|
||||||
|
val uuid: UUID,
|
||||||
|
val motive: PaintingMotive,
|
||||||
|
val centerLocation: VoxelLocation,
|
||||||
|
val direction: CardinalDirection
|
||||||
|
) : OutgoingPacket()
|
|
@ -50,10 +50,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
compileKotlin {
|
|
||||||
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
||||||
0,
|
0,
|
||||||
event.gameMode,
|
event.gameMode,
|
||||||
event.hardcoreHearts,
|
event.hardcoreHearts,
|
||||||
initialWorldAndLocation.world,
|
initialWorldAndLocation.first,
|
||||||
event.maxViewDistance,
|
event.maxViewDistance,
|
||||||
event.reducedDebugInfo,
|
event.reducedDebugInfo,
|
||||||
event.respawnScreenEnabled
|
event.respawnScreenEnabled
|
||||||
|
@ -133,7 +133,8 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
||||||
event.flyingSpeed,
|
event.flyingSpeed,
|
||||||
event.fieldOfView,
|
event.fieldOfView,
|
||||||
event.gameMode,
|
event.gameMode,
|
||||||
initialWorldAndLocation,
|
initialWorldAndLocation.first,
|
||||||
|
initialWorldAndLocation.second,
|
||||||
event.invulnerable,
|
event.invulnerable,
|
||||||
event.reducedDebugInfo,
|
event.reducedDebugInfo,
|
||||||
event.selectedHotbarSlot
|
event.selectedHotbarSlot
|
||||||
|
@ -159,8 +160,8 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
||||||
state.uuid,
|
state.uuid,
|
||||||
state.gameMode,
|
state.gameMode,
|
||||||
settings,
|
settings,
|
||||||
state.initialWorldAndLocation.world,
|
state.world,
|
||||||
state.initialWorldAndLocation.location,
|
state.position,
|
||||||
state.reducedDebugInfo,
|
state.reducedDebugInfo,
|
||||||
state.fieldOfView,
|
state.fieldOfView,
|
||||||
state.canFly,
|
state.canFly,
|
||||||
|
@ -181,7 +182,7 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
||||||
// session.send(DeclareCommandsPacket(session.server.commandRegistry.items.values))
|
// session.send(DeclareCommandsPacket(session.server.commandRegistry.items.values))
|
||||||
// UnlockRecipes
|
// UnlockRecipes
|
||||||
|
|
||||||
session.send(PlayerPositionAndLookPacket(state.initialWorldAndLocation.location))
|
session.send(PlayerPositionAndLookPacket(state.position))
|
||||||
|
|
||||||
session.send(PlayerInfoPacket(PlayerInfoPacket.Action.AddPlayer((session.server.players + player).map {
|
session.send(PlayerInfoPacket(PlayerInfoPacket.Action.AddPlayer((session.server.players + player).map {
|
||||||
it.uuid to PlayerInfoPacket.Action.AddPlayer.Data(
|
it.uuid to PlayerInfoPacket.Action.AddPlayer.Data(
|
||||||
|
@ -202,14 +203,14 @@ class LoginAndJoinProcedure(val session: UranosSession) {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
session.send(UpdateViewPositionPacket(Chunk.Key.from(player.location.toVoxelLocation())))
|
session.send(UpdateViewPositionPacket(Chunk.Key.from(player.position.toVoxelLocation())))
|
||||||
|
|
||||||
session.scheduleKeepAlivePacket(true)
|
session.scheduleKeepAlivePacket(true)
|
||||||
player.sendChunksAndLight()
|
player.sendChunksAndLight()
|
||||||
|
|
||||||
// WorldBorder
|
// WorldBorder
|
||||||
session.send(SetCompassTargetPacket(player.compassTarget))
|
session.send(SetCompassTargetPacket(player.compassTarget))
|
||||||
session.send(PlayerPositionAndLookPacket(state.initialWorldAndLocation.location))
|
session.send(PlayerPositionAndLookPacket(state.position))
|
||||||
|
|
||||||
// TODO: Wait for ClientStatus(action=0) packet
|
// TODO: Wait for ClientStatus(action=0) packet
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
package space.uranos.player
|
package space.uranos.player
|
||||||
|
|
||||||
|
import space.uranos.Position
|
||||||
import space.uranos.chat.TextComponent
|
import space.uranos.chat.TextComponent
|
||||||
import space.uranos.net.Session
|
import space.uranos.net.Session
|
||||||
import space.uranos.net.packet.play.ChunkDataPacket
|
import space.uranos.net.packet.play.ChunkDataPacket
|
||||||
import space.uranos.net.packet.play.ChunkLightDataPacket
|
import space.uranos.net.packet.play.ChunkLightDataPacket
|
||||||
import space.uranos.world.Chunk
|
import space.uranos.world.Chunk
|
||||||
import space.uranos.world.LocationWithRotation
|
|
||||||
import space.uranos.world.VoxelLocation
|
import space.uranos.world.VoxelLocation
|
||||||
import space.uranos.world.World
|
import space.uranos.world.World
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -23,7 +23,7 @@ class UranosPlayer(
|
||||||
override var gameMode: GameMode,
|
override var gameMode: GameMode,
|
||||||
override var settings: Player.Settings,
|
override var settings: Player.Settings,
|
||||||
override val world: World,
|
override val world: World,
|
||||||
override var location: LocationWithRotation,
|
override var position: Position,
|
||||||
override var reducedDebugInfo: Boolean,
|
override var reducedDebugInfo: Boolean,
|
||||||
override var fieldOfView: Float,
|
override var fieldOfView: Float,
|
||||||
override var canFly: Boolean,
|
override var canFly: Boolean,
|
||||||
|
@ -53,9 +53,8 @@ class UranosPlayer(
|
||||||
/**
|
/**
|
||||||
* Sets [currentlyViewedChunks] to all chunks in the view distance.
|
* Sets [currentlyViewedChunks] to all chunks in the view distance.
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
private fun updateCurrentlyViewedChunks() {
|
||||||
fun updateCurrentlyViewedChunks() {
|
val (centerX, centerZ) = Chunk.Key.from(position.toVoxelLocation())
|
||||||
val (centerX, centerZ) = Chunk.Key.from(location.toVoxelLocation())
|
|
||||||
|
|
||||||
val edgeLength = settings.viewDistance + 1
|
val edgeLength = settings.viewDistance + 1
|
||||||
|
|
||||||
|
|
Reference in a new issue