moved to ItemDisplays and added support for CustomModelData
This commit is contained in:
@@ -18,7 +18,7 @@ import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory
|
||||
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry
|
||||
import net.fabricmc.loader.api.FabricLoader
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.entity.decoration.DisplayEntity.BlockDisplayEntity
|
||||
import net.minecraft.entity.decoration.DisplayEntity.ItemDisplayEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -38,7 +38,6 @@ import java.util.*
|
||||
// Allowing the use of regular Minecraft particles instead of just BDEs.
|
||||
// Better command auto-completion. (and change names of args)
|
||||
// force field "config" option
|
||||
// blockCurve array not needing "minecraft:"
|
||||
|
||||
// Parameters
|
||||
// rotWithVel / scaleWithVel (bool)
|
||||
@@ -70,6 +69,11 @@ class Bde_particles : ModInitializer {
|
||||
GameRules.Category.UPDATES,
|
||||
GameRuleFactory.createIntRule(3000, 0)
|
||||
)
|
||||
val SHOW_PARTICLE_DEBUG: GameRules.Key<GameRules.BooleanRule> = GameRuleRegistry.register(
|
||||
"ShowParticleDebug",
|
||||
GameRules.Category.UPDATES,
|
||||
GameRuleFactory.createBooleanRule(false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onInitialize() {
|
||||
@@ -122,10 +126,10 @@ fun tick(server: MinecraftServer) {
|
||||
runBlocking {
|
||||
server.worlds.map { world ->
|
||||
async {
|
||||
val blockDisplayEntities = world.iterateEntities()
|
||||
.filter { it.type == EntityType.BLOCK_DISPLAY }
|
||||
for (entity in blockDisplayEntities) {
|
||||
if (displayEntityContainsTag(entity as BlockDisplayEntity, "BPS_UUID")
|
||||
val displayEntities = world.iterateEntities()
|
||||
.filter { it.type == EntityType.ITEM_DISPLAY }
|
||||
for (entity in displayEntities) {
|
||||
if (displayEntityContainsTag(entity as ItemDisplayEntity, "BPS_UUID")
|
||||
&& !displayEntityContainsTag(entity, SESSION_UUID.toString())) {
|
||||
|
||||
entity.kill()
|
||||
@@ -185,7 +189,7 @@ fun emitterParamsToJson(params: EmitterParams) : Map<String, Any> { // TODO: map
|
||||
*/
|
||||
|
||||
|
||||
fun displayEntityContainsTag(entity: BlockDisplayEntity, tag: String) : Boolean {
|
||||
fun displayEntityContainsTag(entity: ItemDisplayEntity, tag: String) : Boolean {
|
||||
val nbt = NbtCompound()
|
||||
entity.writeNbt(nbt)
|
||||
val tagsNbtList = nbt.getList("Tags", 8)
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
package com.bytedice.bde_particles
|
||||
|
||||
import net.minecraft.component.Component
|
||||
import net.minecraft.component.ComponentType
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.entity.decoration.DisplayEntity.BlockDisplayEntity
|
||||
import net.minecraft.entity.decoration.DisplayEntity.ItemDisplayEntity
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtFloat
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
class DisplayEntity(private var properties: DisplayEntityProperties?) {
|
||||
private var hasSpawned = false
|
||||
private var entity: BlockDisplayEntity? = null
|
||||
private var entity: ItemDisplayEntity? = null
|
||||
|
||||
fun spawn(world: ServerWorld) {
|
||||
if (hasSpawned || properties == null) { return }
|
||||
|
||||
entity = BlockDisplayEntity(EntityType.BLOCK_DISPLAY, world)
|
||||
entity = ItemDisplayEntity(EntityType.ITEM_DISPLAY, world)
|
||||
updateProperties(properties!!)
|
||||
|
||||
world.spawnEntity(entity)
|
||||
@@ -25,6 +30,21 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
|
||||
|
||||
|
||||
fun updateProperties(properties: DisplayEntityProperties) {
|
||||
val customModelRegex = "^([^/]+)(?:/([0-9]+))?$".toRegex()
|
||||
val matchResult = customModelRegex.find(properties.model)
|
||||
|
||||
val modelName: String
|
||||
val customModelNum: Int
|
||||
|
||||
if (matchResult != null) {
|
||||
modelName = matchResult.groupValues[1]
|
||||
customModelNum = matchResult.groupValues[2].toInt()
|
||||
}
|
||||
else {
|
||||
modelName = properties.model
|
||||
customModelNum = 0
|
||||
}
|
||||
|
||||
val nbt = NbtCompound().apply {
|
||||
val tagList = NbtList()
|
||||
|
||||
@@ -34,7 +54,11 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
|
||||
|
||||
put("Tags", tagList)
|
||||
|
||||
put("block_state", NbtCompound().apply { putString("Name", properties.blockType) })
|
||||
put("item", NbtCompound().apply {
|
||||
putString("id", modelName)
|
||||
putInt("count", 1)
|
||||
put("components", NbtCompound().apply { putInt("minecraft:custom_model_data", customModelNum) })
|
||||
})
|
||||
|
||||
put("transformation", NbtCompound().apply {
|
||||
val offsetList = NbtList().apply {
|
||||
@@ -65,6 +89,9 @@ class DisplayEntity(private var properties: DisplayEntityProperties?) {
|
||||
put("scale", scaleList)
|
||||
put("right_rotation", rightRotList)
|
||||
})
|
||||
|
||||
put("view_range", NbtCompound().apply { properties.viewRange })
|
||||
|
||||
}
|
||||
|
||||
entity?.readNbt(nbt)
|
||||
|
||||
@@ -9,11 +9,13 @@ data class DisplayEntityProperties (
|
||||
val pos: Vec3d = Vec3d(0.0, 0.0, 0.0),
|
||||
val rot: Vector2f = Vector2f(0.0f, 0.0f),
|
||||
|
||||
val blockType: String = "minecraft:purple_concrete",
|
||||
val model: String = "minecraft:purple_concrete", // end with "/{num}" for custom model
|
||||
val tags: Array<String> = emptyArray(),
|
||||
|
||||
val translation: Vector3f = Vector3f(-0.5f, -0.5f, -0.5f),
|
||||
val leftRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
val scale: Vector3f = Vector3f(1.0f, 1.0f, 1.0f),
|
||||
val rightRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f)
|
||||
val rightRotation: Vector4f = Vector4f(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
|
||||
val viewRange: Float = 2.0f
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ data class EmitterParams (
|
||||
var offsetCurve: ParamClasses.LerpVal,
|
||||
var rotVelCurve: ParamClasses.LerpVal,
|
||||
var scaleCurve: ParamClasses.LerpVal,
|
||||
var blockCurve: Pair<Array<String>, LerpCurves>,
|
||||
var modelCurve: Pair<Array<String>, LerpCurves>,
|
||||
)
|
||||
{
|
||||
companion object Presets {
|
||||
@@ -42,7 +42,7 @@ data class EmitterParams (
|
||||
spawnPosOffset = Vector3f(0.0f, 0.0f, 0.0f),
|
||||
lifeTime = ParamClasses.PairInt(25, 40),
|
||||
shape = SpawningShape.Sphere(1.0f, true),
|
||||
offset = ParamClasses.PairVec3f.Uniform(-0.5f, -0.5f),
|
||||
offset = ParamClasses.PairVec3f.Uniform(0.0f, 0.0f),
|
||||
initRot = ParamClasses.PairVec3f.NonUniform(0.0f, 0.0f, 0.0f, 360.0f, 360.0f, 360.0f),
|
||||
rotVel = ParamClasses.PairVec3f.NonUniform(-0.2f, -0.2f, -0.2f, 0.2f, 0.2f, 0.2f),
|
||||
initVel = ParamClasses.PairVec3f.Null,
|
||||
@@ -56,8 +56,8 @@ data class EmitterParams (
|
||||
offsetCurve = ParamClasses.LerpVal.NoLerpVec3f,
|
||||
rotVelCurve = ParamClasses.LerpVal.LerpUniform(1.0f, 0.0f, LerpCurves.Sqrt),
|
||||
scaleCurve = ParamClasses.LerpVal.LerpUniform(0.0f, 2.0f, LerpCurves.Linear),
|
||||
blockCurve = Pair(
|
||||
arrayOf("shroomlight", "orange_concrete", "orange_stained_glass", "gray_wool", "gray_stained_glass", "light_gray_stained_glass"),
|
||||
modelCurve = Pair(
|
||||
arrayOf("shroomlight", "orange_concrete", "orange_stained_glass", "gray_wool", "gray_stained_glass", "light_gray_stained_glass", "light_gray_stained_glass_pane"),
|
||||
LerpCurves.Sqrt
|
||||
),
|
||||
)
|
||||
|
||||
@@ -16,9 +16,13 @@ scaleWithVel: Boolean (NEW)
|
||||
*/
|
||||
|
||||
|
||||
class Particle(private val emitterParams: EmitterParams, private var entityPos: Vec3d, private val entityRot: Vector2f) {
|
||||
class Particle(
|
||||
private val emitterParams: EmitterParams,
|
||||
private var entityPos: Vec3d,
|
||||
private val entityRot: Vector2f,
|
||||
private var debug: Boolean
|
||||
) {
|
||||
private var pos = Vector3f(0.0f, 0.0f, 0.0f)
|
||||
private var blockDisplay: DisplayEntity = DisplayEntity(DisplayEntityProperties())
|
||||
private var timeAlive = 0
|
||||
private var isInit = false
|
||||
var isDead = false
|
||||
@@ -56,6 +60,9 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
|
||||
private var lifeTime = emitterParams.lifeTime.randomize()
|
||||
|
||||
private lateinit var particleEntity: DisplayEntity
|
||||
private lateinit var debugOriginEntity: DisplayEntity
|
||||
private lateinit var debugVelEntity: DisplayEntity
|
||||
|
||||
fun init() {
|
||||
val so = emitterParams.spawnPosOffset
|
||||
@@ -76,14 +83,14 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
val properties = DisplayEntityProperties(
|
||||
pos = entityPos,
|
||||
rot = entityRot,
|
||||
blockType = lerpArray(emitterParams.blockCurve.first as Array<Any>, 0.0f, emitterParams.blockCurve.second) as String,
|
||||
model = lerpArray(emitterParams.modelCurve.first as Array<Any>, 0.0f, emitterParams.modelCurve.second) as String,
|
||||
translation = newPos.add(pos),
|
||||
leftRotation = quatRot,
|
||||
scale = scale,
|
||||
tags = arrayOf("BPS_Particle", "BPS_UUID", SESSION_UUID.toString())
|
||||
)
|
||||
|
||||
blockDisplay = DisplayEntity(properties)
|
||||
particleEntity = DisplayEntity(properties)
|
||||
|
||||
isInit = true
|
||||
}
|
||||
@@ -91,7 +98,7 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
|
||||
fun spawn(world: ServerWorld) {
|
||||
if (isInit) {
|
||||
blockDisplay.spawn(world)
|
||||
particleEntity.spawn(world)
|
||||
LIVING_PARTICLE_COUNT += 1
|
||||
}
|
||||
else { error("Particle is not initialized before being spawned. Please use Particle.init() to initialize it.") }
|
||||
@@ -103,7 +110,7 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
|
||||
val newProperties = calcNewProperties()
|
||||
|
||||
blockDisplay.updateProperties(newProperties)
|
||||
particleEntity.updateProperties(newProperties)
|
||||
|
||||
if (timeAlive > lifeTime) { kill() }
|
||||
|
||||
@@ -127,7 +134,7 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
private fun calcNewProperties() : DisplayEntityProperties {
|
||||
val timeAliveClamped = (timeAlive.toFloat() / lifeTime.toFloat()).coerceIn(0.0f, 1.0f)
|
||||
|
||||
val newBlock = lerpArray(emitterParams.blockCurve.first as Array<Any>, timeAliveClamped, emitterParams.blockCurve.second) as String
|
||||
val newModel = lerpArray(emitterParams.modelCurve.first as Array<Any>, timeAliveClamped, emitterParams.modelCurve.second) as String
|
||||
val (newVel, newPos) = calcPos()
|
||||
val newRot = calcRot(timeAliveClamped)
|
||||
val newScale = calcScale(timeAliveClamped)
|
||||
@@ -147,7 +154,7 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
|
||||
val newProperties = DisplayEntityProperties(
|
||||
pos = entityPos,
|
||||
blockType = newBlock,
|
||||
model = newModel,
|
||||
translation = combinedOffset.add(newOriginOffset),
|
||||
leftRotation = quatRot,
|
||||
scale = newScale,
|
||||
@@ -223,9 +230,28 @@ class Particle(private val emitterParams: EmitterParams, private var entityPos:
|
||||
}
|
||||
|
||||
|
||||
private fun spawnDebug() {
|
||||
// spawn cube at particle origin
|
||||
// show arrow pointing toward particle direction
|
||||
// name-tag its data
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun updateDebug() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun calcDebug() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun kill() {
|
||||
if (!isDead) {
|
||||
blockDisplay.kill()
|
||||
particleEntity.kill()
|
||||
LIVING_PARTICLE_COUNT -= 1
|
||||
isDead = true
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ class ParticleEmitter(private val pos: Vec3d, private val rot: Vector2f, private
|
||||
val randomSpawnChance = randomFloatBetween(0.0f, params.spawnChance.coerceIn(0.0f, 1.0f))
|
||||
if (randomSpawnChance > params.spawnChance) { return }
|
||||
|
||||
val particle = Particle(params, pos, rot)
|
||||
val debug = world.gameRules.getBoolean(Bde_particles.SHOW_PARTICLE_DEBUG)
|
||||
val particle = Particle(params, pos, rot, debug)
|
||||
particle.init()
|
||||
particle.spawn(world)
|
||||
|
||||
|
||||
@@ -13,17 +13,17 @@ fun addToRegister(id: String, params: EmitterParams) : Pair<String, Boolean> {
|
||||
return Pair(newId, false)
|
||||
}
|
||||
|
||||
val newBlocks: MutableList<String> = mutableListOf()
|
||||
val newModels: MutableList<String> = mutableListOf()
|
||||
|
||||
for (block in params.blockCurve.first) {
|
||||
val blockModIdRegex = ".*:".toRegex()
|
||||
if (blockModIdRegex.containsMatchIn(block)) { break }
|
||||
for (model in params.modelCurve.first) {
|
||||
val modelModIdRegex = ".*:".toRegex()
|
||||
if (modelModIdRegex.containsMatchIn(model)) { break }
|
||||
else {
|
||||
newBlocks.add("minecraft:$block")
|
||||
newModels.add("minecraft:$model")
|
||||
}
|
||||
}
|
||||
|
||||
params.blockCurve = Pair(newBlocks.toTypedArray(), params.blockCurve.second)
|
||||
params.modelCurve = Pair(newModels.toTypedArray(), params.modelCurve.second)
|
||||
|
||||
idRegister[id] = params
|
||||
println("BPS - Registered Emitter ID \"$newId\".")
|
||||
|
||||
Reference in New Issue
Block a user