split player in remote and local player, entity effect particles

This commit is contained in:
Bixilon 2021-05-29 22:49:05 +02:00
parent 8517ca0424
commit 15918d9a90
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
32 changed files with 291 additions and 65 deletions

View File

@ -33,7 +33,7 @@ import de.bixilon.minosoft.data.entities.entities.monster.piglin.PiglinBrute
import de.bixilon.minosoft.data.entities.entities.monster.raid.*
import de.bixilon.minosoft.data.entities.entities.npc.villager.Villager
import de.bixilon.minosoft.data.entities.entities.npc.villager.WanderingTrader
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
import de.bixilon.minosoft.data.entities.entities.projectile.*
import de.bixilon.minosoft.data.entities.entities.vehicle.*
import de.bixilon.minosoft.data.entities.meta.EntityMetaData
@ -156,7 +156,7 @@ object DefaultEntityFactories : DefaultFactory<EntityFactory<out Entity>>(
ZombieVillager,
ZombiePigman,
ZombifiedPiglin,
PlayerEntity,
RemotePlayerEntity,
FishingHook,
GlowSquid,
EvokerFangs,

View File

@ -21,7 +21,7 @@ import de.bixilon.minosoft.data.inventory.InventorySlots.EquipmentSlots
import de.bixilon.minosoft.data.inventory.ItemStack
import de.bixilon.minosoft.data.mappings.effects.StatusEffect
import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.physics.Speedable
import de.bixilon.minosoft.data.physics.PhysicsEntity
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY
@ -34,13 +34,15 @@ import glm_.vec3.Vec3
import java.lang.reflect.InvocationTargetException
import java.util.*
import kotlin.math.pow
import kotlin.random.Random
abstract class Entity(
protected val connection: PlayConnection,
val entityType: EntityType,
override var position: Vec3,
var rotation: EntityRotation,
) : Speedable {
) : PhysicsEntity {
protected val random = Random
val equipment: MutableMap<EquipmentSlots, ItemStack> = mutableMapOf()
val activeStatusEffects: MutableMap<StatusEffect, StatusEffectInstance> = synchronizedMapOf()
@ -62,6 +64,8 @@ abstract class Entity(
Vec3(+(entityType.width / 2 + HITBOX_MARGIN), entityType.height, +(entityType.width / 2 + HITBOX_MARGIN))
)
private var lastTickTime = -1L
fun forceMove(deltaPosition: Vec3) {
position = position + deltaPosition
}
@ -232,7 +236,15 @@ abstract class Entity(
check(deltaMillis > 0L) { "Delta tick time is <= 0: $deltaMillis" }
tickMovement(deltaMillis)
val currentTime = System.currentTimeMillis()
if (currentTime - lastTickTime >= ProtocolDefinition.TICK_TIME) {
realTick()
lastTickTime = currentTime
}
}
open fun realTick() {}
private val aabb: AABB
get() = defaultAABB + position

View File

@ -17,17 +17,25 @@ import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.attributes.DefaultEntityAttributes
import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.data.text.ChatColors
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.data.text.RGBColor.Companion.asRGBColor
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell.AmbientEntityEffectParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell.EntityEffectParticle
import de.bixilon.minosoft.gui.rendering.util.VecUtil.vertical
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.chance
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
abstract class LivingEntity(connection: PlayConnection, entityType: EntityType, position: Vec3, rotation: EntityRotation) : Entity(connection, entityType, position, rotation) {
private val entityEffectParticle = connection.registries.particleTypeRegistry[EntityEffectParticle]
private val ambientEntityEffectParticle = connection.registries.particleTypeRegistry[AmbientEntityEffectParticle]
private fun getLivingEntityFlag(bitMask: Int): Boolean {
return entityMetaData.sets.getBitMask(EntityMetaDataFields.LIVING_ENTITY_FLAGS, bitMask)
}
// = isUsingItem
@get:EntityMetaDataFunction(name = "Is hand active")
val isHandActive: Boolean
get() = getLivingEntityFlag(0x01)
@ -52,8 +60,8 @@ abstract class LivingEntity(connection: PlayConnection, entityType: EntityType,
}
@get:EntityMetaDataFunction(name = "Effect color")
val effectColor: Int
get() = entityMetaData.sets.getInt(EntityMetaDataFields.LIVING_ENTITY_EFFECT_COLOR)
val effectColor: RGBColor
get() = entityMetaData.sets.getInt(EntityMetaDataFields.LIVING_ENTITY_EFFECT_COLOR).asRGBColor()
@get:EntityMetaDataFunction(name = "Is effect ambient")
val effectAmbient: Boolean
@ -70,4 +78,46 @@ abstract class LivingEntity(connection: PlayConnection, entityType: EntityType,
@get:EntityMetaDataFunction(name = "Bed location")
val bedPosition: Vec3i?
get() = entityMetaData.sets.getBlockPosition(EntityMetaDataFields.LIVING_ENTITY_BED_POSITION)
private fun tickStatusEffects() {
if (entityEffectParticle == null && ambientEntityEffectParticle == null) {
return
}
if (effectColor == ChatColors.BLACK) {
return
}
var spawnParticles = if (isInvisible) {
random.nextInt(15) == 0
} else {
random.nextBoolean()
}
if (effectAmbient) {
spawnParticles = spawnParticles && random.chance(20)
}
if (!spawnParticles) {
return
}
val particlePosition = position + Vec3.vertical(
{ entityType.width * ((2.0f * random.nextFloat() - 1.0f) * 0.5f) },
entityType.height * random.nextFloat()
)
if (effectAmbient) {
ambientEntityEffectParticle ?: return
connection.world += AmbientEntityEffectParticle(connection, particlePosition, effectColor, ambientEntityEffectParticle.default())
} else {
entityEffectParticle ?: return
connection.world += EntityEffectParticle(connection, particlePosition, effectColor, entityEffectParticle.default())
}
}
override fun realTick() {
super.realTick()
tickStatusEffects()
}
}

View File

@ -17,8 +17,6 @@ import de.bixilon.minosoft.data.entities.EntityMetaDataFields
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.EntityMetaDataFunction
import de.bixilon.minosoft.data.entities.entities.LivingEntity
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.entities.EntityFactory
import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.player.Hands
import de.bixilon.minosoft.data.player.PlayerProperties
@ -27,7 +25,7 @@ import de.bixilon.minosoft.data.player.tab.TabListItem
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import glm_.vec3.Vec3
class PlayerEntity(
abstract class PlayerEntity(
connection: PlayConnection,
entityType: EntityType,
position: Vec3 = Vec3(0, 0, 0),
@ -82,8 +80,4 @@ class PlayerEntity(
@get:EntityMetaDataFunction(name = "Right shoulder entity data")
val rightShoulderData: Map<String, Any>?
get() = entityMetaData.sets.getNBT(EntityMetaDataFields.PLAYER_RIGHT_SHOULDER_DATA)
companion object : EntityFactory<PlayerEntity> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("player")
}
}

View File

@ -0,0 +1,40 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.entities.entities.player
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.entities.EntityFactory
import de.bixilon.minosoft.data.mappings.entities.EntityType
import de.bixilon.minosoft.data.player.PlayerProperties
import de.bixilon.minosoft.data.player.PlayerProperty
import de.bixilon.minosoft.data.player.tab.TabListItem
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import glm_.vec3.Vec3
class RemotePlayerEntity(
connection: PlayConnection,
entityType: EntityType,
position: Vec3 = Vec3(0, 0, 0),
rotation: EntityRotation = EntityRotation(0.0, 0.0),
name: String = "TBA",
properties: Map<PlayerProperties, PlayerProperty> = mapOf(),
tabListItem: TabListItem = TabListItem(name = name, gamemode = Gamemodes.SURVIVAL, properties = properties),
) : PlayerEntity(connection, entityType, position, rotation, name, properties, tabListItem) {
companion object : EntityFactory<PlayerEntity> {
override val RESOURCE_LOCATION: ResourceLocation = ResourceLocation("minecraft:player")
}
}

View File

@ -36,7 +36,7 @@ open class BlockItem(
val block: Block = registries.blockRegistry[data["block"].asInt]
override fun use(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i, raycastHit: RaycastHit, hands: Hands, itemStack: ItemStack): BlockUsages {
if (!connection.player.entity.gamemode.canBuild) {
if (!connection.player.gamemode.canBuild) {
return BlockUsages.PASS
}
@ -57,7 +57,7 @@ open class BlockItem(
connection.world[placePosition] = placeBlockState
if (connection.player.entity.gamemode != Gamemodes.CREATIVE) {
if (connection.player.gamemode != Gamemodes.CREATIVE) {
itemStack.count--
connection.player.inventory.validate()
}

View File

@ -53,7 +53,7 @@ abstract class MiningToolItem(
}
protected fun interactWithTool(connection: PlayConnection, blockPosition: Vec3i, replace: BlockState?): BlockUsages {
if (!connection.player.entity.gamemode.useTools) {
if (!connection.player.gamemode.useTools) {
return BlockUsages.PASS
}

View File

@ -22,6 +22,6 @@ object GameMoveChangeGameEventHandler : GameEventHandler {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:gamemode_change".asResourceLocation()
override fun handle(data: Float, connection: PlayConnection) {
connection.player.entity.tabListItem.gamemode = Gamemodes[data.toInt()]
connection.player.tabListItem.gamemode = Gamemodes[data.toInt()]
}
}

View File

@ -42,19 +42,19 @@ class CollisionDetector(val connection: PlayConnection) {
return result
}
fun collide(speedable: Speedable, deltaPosition: Vec3, collisionsToCheck: VoxelShape, aabb: AABB): Vec3 {
fun collide(physicsEntity: PhysicsEntity, deltaPosition: Vec3, collisionsToCheck: VoxelShape, aabb: AABB): Vec3 {
val delta = Vec3(deltaPosition)
if (delta.y != 0.0f) {
delta.y = collisionsToCheck.computeOffset(aabb, deltaPosition.y, Axes.Y)
if (delta.y != deltaPosition.y) {
speedable.onGround = false
speedable.velocity.y = 0.0f
physicsEntity.onGround = false
physicsEntity.velocity.y = 0.0f
if (deltaPosition.y < 0) {
speedable.onGround = true
physicsEntity.onGround = true
}
aabb += Vec3(0f, delta.y, 0f)
} else if (delta.y < 0) {
speedable.onGround = false
physicsEntity.onGround = false
}
}
if ((deltaPosition.x != 0f || deltaPosition.z != 0f)) {
@ -72,21 +72,21 @@ class CollisionDetector(val connection: PlayConnection) {
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
aabb += Vec3(delta.x, 0f, 0f)
if (delta.x != deltaPosition.x) {
speedable.velocity.x = 0.0f
physicsEntity.velocity.x = 0.0f
}
}
if (delta.z != 0.0f) {
delta.z = collisionsToCheck.computeOffset(aabb, deltaPosition.z, Axes.Z)
aabb += Vec3(0f, 0f, delta.z)
if (delta.z != deltaPosition.z) {
speedable.velocity.z = 0.0f
physicsEntity.velocity.z = 0.0f
}
}
if (delta.x != 0.0f && !xPriority) {
delta.x = collisionsToCheck.computeOffset(aabb, deltaPosition.x, Axes.X)
// no need to offset the aabb any more, as it won't be used any more
if (delta.x != deltaPosition.x) {
speedable.velocity.x = 0.0f
physicsEntity.velocity.x = 0.0f
}
}
if (delta.length() > deltaPosition.length() + Entity.STEP_HEIGHT) {

View File

@ -15,7 +15,7 @@ package de.bixilon.minosoft.data.physics
import glm_.vec3.Vec3
interface Speedable {
interface PhysicsEntity {
val position: Vec3
val velocity: Vec3
var onGround: Boolean

View File

@ -16,6 +16,7 @@ import de.bixilon.minosoft.data.abilities.ItemCooldown
import de.bixilon.minosoft.data.accounts.Account
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
import de.bixilon.minosoft.data.mappings.items.Item
import de.bixilon.minosoft.data.mappings.other.containers.Container
import de.bixilon.minosoft.data.mappings.other.containers.PlayerInventory
@ -26,14 +27,13 @@ import de.bixilon.minosoft.util.KUtil.synchronizedMapOf
import glm_.vec3.Vec3
import glm_.vec3.Vec3i
class Player(
class LocalPlayerEntity(
account: Account,
connection: PlayConnection,
) {
) : PlayerEntity(connection, connection.registries.entityTypeRegistry[RemotePlayerEntity.RESOURCE_LOCATION]!!, Vec3.EMPTY, EntityRotation(0.0, 0.0), account.username) {
val healthCondition = PlayerHealthCondition()
val experienceCondition = PlayerExperienceCondition()
var spawnPosition: Vec3i = Vec3i.EMPTY
val entity: PlayerEntity = PlayerEntity(connection, connection.registries.entityTypeRegistry[PlayerEntity.RESOURCE_LOCATION]!!, Vec3.EMPTY, EntityRotation(0.0, 0.0), account.username)
@Deprecated(message = "Will be replaced with some kind of teleport manager, ...")
var isSpawnConfirmed = false

View File

@ -184,7 +184,7 @@ class World(
}
private fun randomTick(radius: Int) {
val blockPosition = connection.player.entity.position.blockPosition + { random.nextInt(radius) } - { random.nextInt(radius) }
val blockPosition = connection.player.position.blockPosition + { random.nextInt(radius) } - { random.nextInt(radius) }
val blockState = this[blockPosition] ?: return

View File

@ -150,7 +150,7 @@ class BlockOutlineRenderer(
return
}
if (connection.player.entity.gamemode == Gamemodes.ADVENTURE || connection.player.entity.gamemode == Gamemodes.SPECTATOR) {
if (connection.player.gamemode == Gamemodes.ADVENTURE || connection.player.gamemode == Gamemodes.SPECTATOR) {
if (raycastHit.blockState.block.blockEntityType == null) {
unload()
return

View File

@ -76,7 +76,7 @@ class HUDWorldDebugNode(hudRenderer: HUDRenderer) : DebugScreenNode(hudRenderer)
// ToDo: Prepare on change
gamemodeText.sText = "Gamemode: ${hudRenderer.connection.player.entity.gamemode.name.lowercase(Locale.getDefault())}"
gamemodeText.sText = "Gamemode: ${hudRenderer.connection.player.gamemode.name.lowercase(Locale.getDefault())}"
positionText.sText = "XYZ ${getPosition()}"
blockPositionText.sText = "Block ${getBlockPosition()}"
chunkPositionText.sText = "Chunk ${getChunkLocation()}"

View File

@ -91,7 +91,7 @@ class LeftClickHandler(
return false
}
if (!connection.player.entity.gamemode.canBreak) {
if (!connection.player.gamemode.canBreak) {
cancelDigging()
return false
}
@ -140,7 +140,7 @@ class LeftClickHandler(
val canStartBreaking = currentTime - breakSent >= ProtocolDefinition.TICK_TIME
val canInstantBreak = connection.player.baseAbilities.canInstantBreak || connection.player.entity.gamemode == Gamemodes.CREATIVE
val canInstantBreak = connection.player.baseAbilities.canInstantBreak || connection.player.gamemode == Gamemodes.CREATIVE
if (canInstantBreak) {
if (!canStartBreaking) {
@ -189,17 +189,17 @@ class LeftClickHandler(
}
}
connection.player.entity.activeStatusEffects[hasteStatusEffect]?.let {
connection.player.activeStatusEffects[hasteStatusEffect]?.let {
speedMultiplier *= (0.2f * it.amplifier) + 1.0f
}
connection.player.entity.activeStatusEffects[miningFatigueStatusEffect]?.let {
connection.player.activeStatusEffects[miningFatigueStatusEffect]?.let {
speedMultiplier *= 0.3f.pow(it.amplifier + 1)
}
// ToDo: Check if is in water
if (!connection.player.entity.onGround) {
if (!connection.player.onGround) {
speedMultiplier /= 5.0f
}

View File

@ -61,7 +61,7 @@ class Camera(
private var lastMouseX = 0.0
private var lastMouseY = 0.0
val playerEntity: PlayerEntity
get() = connection.player.entity
get() = connection.player
var yaw = 0.0
var pitch = 0.0
private var zoom = 0.0f
@ -222,7 +222,7 @@ class Camera(
if (renderWindow.inputHandler.currentKeyConsumer != null) { // ToDo
return
}
var cameraSpeed = if (connection.player.entity.isFlying) {
var cameraSpeed = if (connection.player.isFlying) {
flyingSpeed
} else {
walkingSpeed

View File

@ -21,6 +21,8 @@ import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.Ex
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.dust.DustParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.fire.SmokeParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.lava.LavaParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell.AmbientEntityEffectParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell.EntityEffectParticle
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.suspend.DolphinParticle
object DefaultParticleFactory : DefaultFactory<ParticleFactory<out Particle>>(
@ -32,4 +34,6 @@ object DefaultParticleFactory : DefaultFactory<ParticleFactory<out Particle>>(
SmokeParticle,
DolphinParticle,
DustParticle,
EntityEffectParticle,
AmbientEntityEffectParticle,
)

View File

@ -14,7 +14,7 @@
package de.bixilon.minosoft.gui.rendering.particle.types
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
import de.bixilon.minosoft.data.physics.Speedable
import de.bixilon.minosoft.data.physics.PhysicsEntity
import de.bixilon.minosoft.gui.rendering.chunk.models.AABB
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
import de.bixilon.minosoft.gui.rendering.particle.ParticleMesh
@ -36,7 +36,7 @@ abstract class Particle(
final override val position: Vec3,
final override val velocity: Vec3 = Vec3.EMPTY,
data: ParticleData? = null,
) : Speedable {
) : PhysicsEntity {
protected val data: ParticleData = data ?: let {
val resourceLocation = this::class.companionObjectInstance as ParticleFactory<*>
connection.registries.particleTypeRegistry[resourceLocation]!!.default()

View File

@ -0,0 +1,37 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
import glm_.vec3.Vec3
class AmbientEntityEffectParticle(connection: PlayConnection, position: Vec3, color: RGBColor, data: ParticleData? = null) : SpellParticle(connection, position, Vec3(color.red, color.green, color.blue), data) {
init {
this.color = color.with(alpha = 0.15f)
}
companion object : ParticleFactory<AmbientEntityEffectParticle> {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:ambient_entity_effect".asResourceLocation()
override fun build(connection: PlayConnection, position: Vec3, velocity: Vec3, data: ParticleData): AmbientEntityEffectParticle {
return AmbientEntityEffectParticle(connection, position, color = RGBColor(velocity.x, velocity.y, velocity.z), data)
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell
import de.bixilon.minosoft.data.mappings.ResourceLocation
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
import de.bixilon.minosoft.data.text.RGBColor
import de.bixilon.minosoft.gui.rendering.particle.ParticleFactory
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.KUtil.asResourceLocation
import glm_.vec3.Vec3
class EntityEffectParticle(connection: PlayConnection, position: Vec3, color: RGBColor, data: ParticleData? = null) : SpellParticle(connection, position, Vec3(color.red, color.green, color.blue), data) {
init {
this.color = color
}
companion object : ParticleFactory<EntityEffectParticle> {
override val RESOURCE_LOCATION: ResourceLocation = "minecraft:entity_effect".asResourceLocation()
override fun build(connection: PlayConnection, position: Vec3, velocity: Vec3, data: ParticleData): EntityEffectParticle {
return EntityEffectParticle(connection, position, color = RGBColor(velocity.x, velocity.y, velocity.z), data)
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Minosoft
* Copyright (C) 2021 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.spell
import de.bixilon.minosoft.data.mappings.particle.data.ParticleData
import de.bixilon.minosoft.gui.rendering.particle.types.render.texture.simple.SimpleTextureParticle
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
import de.bixilon.minosoft.util.MMath
import glm_.vec3.Vec3
import kotlin.random.Random
abstract class SpellParticle(connection: PlayConnection, position: Vec3, velocity: Vec3, data: ParticleData? = null) : SimpleTextureParticle(connection, position, Vec3(0.5f - Random.nextFloat(), velocity.y, 0.5 - Random.nextFloat()), data) {
init {
friction = 0.96f
gravityStrength = -0.1f
accelerateIfYBlocked = true
this.velocity.y *= 0.20000000298023224f
if (velocity.x == 0.0f && velocity.z == 0.0f) {
this.velocity.x *= 0.10000000149011612f
this.velocity.z *= 0.10000000149011612f
}
super.scale *= 0.75f
maxAge = (8.0f / (random.nextFloat() * 0.8f + 0.2f)).toInt()
this.physics = false
// ToDo: Toggle if using spyglass
}
override fun realTick() {
super.realTick()
color = color.with(alpha = MMath.lerp(0.05f, color.floatAlpha, 1.0f))
}
}

View File

@ -25,7 +25,7 @@ import de.bixilon.minosoft.data.mappings.recipes.Recipes
import de.bixilon.minosoft.data.mappings.versions.Registries
import de.bixilon.minosoft.data.mappings.versions.Version
import de.bixilon.minosoft.data.physics.CollisionDetector
import de.bixilon.minosoft.data.player.Player
import de.bixilon.minosoft.data.player.LocalPlayerEntity
import de.bixilon.minosoft.data.player.tab.TabList
import de.bixilon.minosoft.data.scoreboard.ScoreboardManager
import de.bixilon.minosoft.data.tags.Tag
@ -75,7 +75,7 @@ class PlayConnection(
var rendering: Rendering? = null
private set
lateinit var player: Player
lateinit var player: LocalPlayerEntity
private set
private lateinit var entityTickTask: TimeWorkerTask
@ -186,7 +186,7 @@ class PlayConnection(
version.load(latch) // ToDo: show gui loader
assetsManager = MultiAssetsManager(version.assetsManager, Minosoft.MINOSOFT_ASSETS_MANAGER, Minosoft.MINECRAFT_FALLBACK_ASSETS_MANAGER)
registries.parentRegistries = version.registries
player = Player(account, this)
player = LocalPlayerEntity(account, this)
if (!RenderConstants.DISABLE_RENDERING && !StaticConfiguration.HEADLESS_MODE) {
val renderer = Rendering(this)

View File

@ -12,7 +12,7 @@
*/
package de.bixilon.minosoft.protocol.packets.c2s.login
import de.bixilon.minosoft.data.player.Player
import de.bixilon.minosoft.data.player.LocalPlayerEntity
import de.bixilon.minosoft.protocol.packets.c2s.PlayC2SPacket
import de.bixilon.minosoft.protocol.protocol.PlayOutByteBuffer
import de.bixilon.minosoft.util.logging.Log
@ -23,7 +23,7 @@ class LoginStartC2SP(
val username: String,
) : PlayC2SPacket {
constructor(player: Player) : this(player.entity.name)
constructor(player: LocalPlayerEntity) : this(player.name)
override fun write(buffer: PlayOutByteBuffer) {
buffer.writeString(username)

View File

@ -35,7 +35,7 @@ class LoginSuccessS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
override fun handle(connection: PlayConnection) {
connection.connectionState = ConnectionStates.PLAY
val playerEntity = connection.player.entity
val playerEntity = connection.player
playerEntity.tabListItem.name = name
playerEntity.tabListItem.displayName = ChatComponent.of(name)

View File

@ -41,7 +41,7 @@ class ExplosionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
val blockPosition = Vec3i(position + record)
connection.world.setBlockState(blockPosition, null)
}
connection.player.entity.velocity = connection.player.entity.velocity + velocity
connection.player.velocity = connection.player.velocity + velocity
connection.fireEvent(ExplosionEvent(connection, this))
}

View File

@ -136,7 +136,7 @@ class JoinGameS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
if (connection.fireEvent(JoinGameEvent(connection, this))) {
return
}
val playerEntity = connection.player.entity
val playerEntity = connection.player
playerEntity.tabListItem.gamemode = gamemode
connection.world.hardcore = isHardcore

View File

@ -46,7 +46,7 @@ class PlayerAbilitiesS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
}
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Player abilities: (isInvulnerable=$isInvulnerable, isFlying=$isFlying, canFly=$canFly, canInstantBuild=$canInstantBuild, flyingSpeed=$flyingSpeed, walkingSpeed=$walkingSpeed)" }
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "LocalPlayerEntity abilities: (isInvulnerable=$isInvulnerable, isFlying=$isFlying, canFly=$canFly, canInstantBuild=$canInstantBuild, flyingSpeed=$flyingSpeed, walkingSpeed=$walkingSpeed)" }
}
override fun handle(connection: PlayConnection) {

View File

@ -16,6 +16,7 @@ import de.bixilon.minosoft.config.StaticConfiguration
import de.bixilon.minosoft.data.PlayerPropertyData
import de.bixilon.minosoft.data.entities.EntityRotation
import de.bixilon.minosoft.data.entities.entities.player.PlayerEntity
import de.bixilon.minosoft.data.entities.entities.player.RemotePlayerEntity
import de.bixilon.minosoft.data.entities.meta.EntityMetaData
import de.bixilon.minosoft.modding.event.events.EntitySpawnEvent
import de.bixilon.minosoft.protocol.network.connection.PlayConnection
@ -66,9 +67,9 @@ class PlayerEntitySpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
if (buffer.versionId < ProtocolVersions.V_19W34A) {
metaData = buffer.readMetaData()
}
entity = PlayerEntity(
entity = RemotePlayerEntity(
connection = buffer.connection,
entityType = buffer.connection.registries.entityTypeRegistry[PlayerEntity.RESOURCE_LOCATION]!!,
entityType = buffer.connection.registries.entityTypeRegistry[RemotePlayerEntity.RESOURCE_LOCATION]!!,
position = position,
rotation = EntityRotation(yaw.toFloat(), pitch.toFloat(), 0.0f),
name = name,
@ -91,6 +92,6 @@ class PlayerEntitySpawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
}
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Player entity spawn (position=${entity.position}, entityId=$entityId, name=${entity.name}, uuid=$entityUUID)" }
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "LocalPlayerEntity entity spawn (position=${entity.position}, entityId=$entityId, name=${entity.name}, uuid=$entityUUID)" }
}
}

View File

@ -51,7 +51,7 @@ class PositionAndRotationS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
}
override fun handle(connection: PlayConnection) {
val entity = connection.player.entity
val entity = connection.player
// correct position with flags (relative position possible)
if (BitByte.isBitMask(flags, 0x01)) {
position.x += entity.position.x
@ -82,6 +82,6 @@ class PositionAndRotationS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
}
override fun log() {
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Player position (position=$position, rotation=$rotation, onGround=$isOnGround)" }
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "LocalPlayerEntity position (position=$position, rotation=$rotation, onGround=$isOnGround)" }
}
}

View File

@ -89,8 +89,8 @@ class RespawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
connection.world.chunks.clear()
connection.world.dimension = dimension
connection.player.isSpawnConfirmed = false
connection.player.entity.tabListItem.gamemode = gamemode
connection.player.entity.velocity = Vec3()
connection.player.tabListItem.gamemode = gamemode
connection.player.velocity = Vec3()
connection.fireEvent(RespawnEvent(connection, this))
}

View File

@ -158,7 +158,7 @@ class TabListDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
} ?: continue
if (entity === connection.player.entity) {
if (entity === connection.player) {
entity.tabListItem.specialMerge(data)
continue
}

View File

@ -97,10 +97,15 @@ object MMath {
val Float.ceilInt: Int get() = glm.ceil(this).toInt()
val Boolean.positiveNegative: Int get() =
val Boolean.positiveNegative: Int
get() =
if (this) {
1
} else {
-1
}
fun lerp(delta: Float, start: Float, end: Float): Float {
return start + delta * (end - start)
}
}