### SequencedParticleComposition Example in Kotlin Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/particle-composition.md Provides an example of implementing SequencedParticleComposition for effects that involve gradual creation or removal of particles. It demonstrates generating particles in a spiral pattern and managing their sequence. ```kotlin @CooAutoRegister class MySeqComposition(pos: Vec3, world: Level? = null) : AutoSequencedParticleComposition(pos, world) { override fun getParticleSequenced(): SortedMap { var order = 0 return PointsBuilder() .addSpiral(0.0, 8.0, 6.0, 1024, Math.PI / 32) .createWithCompositionDataSorted { CompositionData().apply { this.order = order++ } } } override fun onDisplay() { addPreTickAction { if (!client) { addMultiple(30) } } } } ``` -------------------------------- ### CompositionData Initialization Examples in Kotlin Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/particle-composition.md Illustrates how to use CompositionData to initialize individual particles and controllers within a particle composition. It shows setting a displayer supplier and adding particle instance initializers. ```kotlin CompositionData() .setDisplayerSupplier { ParticleDisplayer.withSingle(ControlableEndRodEffect(it)) } .addParticleInstanceInit { colorOfRGBA(120, 220, 255, 1f) } ``` -------------------------------- ### Server-Side Logic Check in doTick Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/auto-particle-emitters.md This example shows how to differentiate between server-side and client-side execution within the doTick() method. This is crucial for logic that should only run on the server, such as physics updates or game state changes. ```kotlin if (!world!!.isClientSide) { // server logic here } ``` -------------------------------- ### Generate Circle Points with Math3DUtil Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Demonstrates generating a set of points forming a circle in the XZ plane using Math3DUtil. The generated points can then be transformed, for example, by offsetting their Y-coordinate. ```kotlin val points = Math3DUtil.getCircleXZ(3.0, 128) val rotated = points.onEach { it.y += 1.5 } ``` -------------------------------- ### Create Server-Synchronized Particle Composition (Kotlin) Source: https://context7.com/coostack/cooparticlesapi/llms.txt This Kotlin example demonstrates creating a server-synchronized particle composition using `AutoParticleComposition`. It utilizes annotations like `@CooAutoRegister` and `@CodecField` for automatic registration and synchronization. The `getParticles` method defines the particle shapes and initial properties, while `onDisplay` handles dynamic behavior like rotation. ```kotlin @CooAutoRegister class MyComposition(position: Vec3, world: Level? = null) : AutoParticleComposition(position, world) { // 使用 @CodecField 标注的字段会自动同步到客户端 @CodecField var radius = 6.0 @CodecField var color = Vector3f(1f, 0.8f, 0.3f) override fun getParticles(): Map { // 使用 PointsBuilder 构建圆形点集 return PointsBuilder() .addCircle(radius, 200) .createWithCompositionData { CompositionData() .setDisplayerSupplier { ParticleDisplayer.withSingle(ControlableEndRodEffect(it)) } .addParticleInstanceInit { colorOfRGBA(255, 200, 80, 1f) } } } override fun onDisplay() { // 添加每 tick 执行的旋转动画 addPreTickAction { rotateAsAxis(Math.PI / 64) } } } // 服务端生成组合粒子 val composition = MyComposition(pos, serverLevel) composition.spawn(serverLevel, pos) ``` -------------------------------- ### Implement Auto-Decoding Particle Emitters (Kotlin) Source: https://context7.com/coostack/cooparticlesapi/llms.txt This Kotlin example defines an `AutoParticleEmitters` class for creating continuously emitting particle effects with synchronized parameters. It uses `@CodecField` for synchronization and `enableInterpolator` for smooth particle movement. The `genParticles` method generates particle data, and `singleParticleAction` defines individual particle behavior. ```kotlin @CooAutoRegister class MyEmitter(pos: Vec3, world: Level?) : AutoParticleEmitters(pos, world) { @CodecField var speed = 0.35 @CodecField var color = Vector3f(0.8f, 0.4f, 1.0f) init { // 启用插值器以平滑高速移动时的粒子轨迹 enableInterpolator = true emittersInterpolator.setRefiner(10.0) } override fun doTick() { // 服务端/客户端都会执行 if (!world!!.isClientSide) { // 服务端逻辑 } } override fun genParticles(lerpProgress: Float): List> { return PointsBuilder() .addCircle(3.0, 60) .create() .map { ControlableParticleData().apply { this.speed = this@MyEmitter.speed } to it } } override fun singleParticleAction( controler: ParticleControler, data: ControlableParticleData, spawnPos: RelativeLocation, spawnWorld: Level, particleLerpProgress: Float, posLerpProgress: Float ) { // 初始化单个粒子的控制器 controler.addPreTickAction { // 粒子每 tick 的行为 } } } // 服务端生成并启动发射器 val emitter = MyEmitter(pos, serverLevel) emitter.spawn(serverLevel, pos) emitter.start() // 更新参数后同步 emitter.color = Vector3f(1f, 0f, 0f) ParticleEmittersManager.updateEmitters(emitter) ``` -------------------------------- ### Kotlin: Generated Particle Composition Class Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/require.md An example of a generated Kotlin class for a particle composition. It includes properties for color, size, and radius, and defines particle generation logic using PointsBuilder and CompositionData. ```kotlin @CooAutoRegister class TestComposition(position: Vec3, world: Level? = null) : AutoParticleComposition(position, world) { @CodecField var color: Vector3f = Vector3f(0f,1f,1f) @CodecField var size: Float = 1f @CodecField var r: Double = 2.0 @CodecField var countPow: Int = 4 val options: Int = 4 override fun getParticles(): Map { return PointsBuilder().addBall(r, countPow * options / 2) .createWithCompositionData { CompositionData().setDisplayerSupplier { ParticleDisplayer.withSingle( ControlableEnchantmentEffect(it) ) }.addParticleInstanceInit { color = this@TestComposition.color size = this@TestComposition.size currentAge = Random.nextInt(lifetime) }.addParticleControlerInstanceInit { var tick = true addPreTickAction { // 注意下面是由js翻译过来的 if (particle.particleAlpha >= 0.9f) { tick = false } if (particle.particleAlpha <= 0.2f) { tick = true } particle.particleAlpha += if (tick) 0.05f else -0.05f } } } } override fun onDisplay() { addPreTickAction { // 如果是卡片就直接加, 如果是表达式就翻译成kotlin rotateToWithAngle(direction,speed / 180 * PI) } } } ``` -------------------------------- ### Register and Handle Events with Listeners (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/event-bus.md Demonstrates how to create an event listener class `MyEventListener` annotated with `@EventListener`. Methods within this class annotated with `@EventHandler` will be invoked when specific events are triggered. The example shows how to check and set the `isCancelled` property of a `MyEvent`. ```kotlin @EventListener("your_mod_id") object MyEventListener { @EventHandler(EventPriority.HIGH) fun onMyEvent(event: MyEvent) { if (/* ... */) { event.isCancelled = true } } } ``` -------------------------------- ### Example of @CooAutoRegister with AutoParticleEmitters Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/codecfield-auto-register.md An example demonstrating the use of @CooAutoRegister on a custom class that extends AutoParticleEmitters. It includes fields annotated with @CodecField for automatic serialization. This class will be automatically registered by the ParticleEmittersManager. ```kotlin @CooAutoRegister class MyEmitter(pos: Vec3, world: Level?) : AutoParticleEmitters(pos, world) { @CodecField var speed = 0.4 @CodecField var color = Vector3f(1f, 0f, 0f) override fun doTick() {} override fun genParticles(lerpProgress: Float): List> { // ... } override fun singleParticleAction( controler: ParticleControler, data: ControlableParticleData, spawnPos: RelativeLocation, spawnWorld: Level, particleLerpProgress: Float, posLerpProgress: Float ) {} } ``` -------------------------------- ### ShaderPipe: Create and Register a Post-Processing Rendering Pipeline Source: https://context7.com/coostack/cooparticlesapi/llms.txt Demonstrates how to create a ShaderPipe manager for post-processing effects, including adding transformations, defining shaders for input, blur (using PingPongShaderPipe for iterations), and output, linking them, and registering the pipeline with the client. It also shows how to write frame data and render the pipeline. ```kotlin val manager = ShaderPipeManager(ResourceLocation.fromNamespaceAndPath("yourmod", "bloom_pipe")) .addTransformUniformMatrix() .setLinkerFunc { linker -> val input = valueInput( SimpleShaderPipe( IdentifierShader( ResourceLocation.fromNamespaceAndPath("yourmod", "pipe/frag/basic.fsh"), GlShaderType.FRAGMENT ), { minecraft.mainRenderTarget.depthTextureId } ) ) val blur = PingPongShaderPipe( IdentifierShader( ResourceLocation.fromNamespaceAndPath("yourmod", "pipe/frag/blur.fsh"), GlShaderType.FRAGMENT ), iterations = 8 ) val output = valueOutput( SimpleShaderPipe( IdentifierShader( ResourceLocation.fromNamespaceAndPath("yourmod", "pipe/frag/output.fsh"), GlShaderType.FRAGMENT ), { minecraft.mainRenderTarget.depthTextureId } ) ) linker.from(input, 0).to(blur, 0) linker.from(blur, 0).to(output, 0) } ClientRenderPipelineManager.register(manager) manager.writeFrame { // 把内容写入 input pipe } manager.render() manager.updateGlobalUniform("viewMat", viewMatrix) ``` -------------------------------- ### Build Point Set with PointsBuilder DSL Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Illustrates the use of the PointsBuilder DSL to construct a point set. It shows how to add shapes like circles, apply transformations such as noise offset and rotation, and finally create the point set. ```kotlin val points = PointsBuilder() .addCircle(6.0, 200) .applyNoiseOffset(0.1, mode = NoiseMode.SPHERE_UNIFORM) .rotateAsAxis(Math.PI / 8) .create() ``` -------------------------------- ### PipeLink DSL 示例 (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/shader-pipe.md 展示了 PipeLink DSL 的使用方式,用于更清晰地描述渲染管道中不同 Pipe 通道之间的连接关系。指定了输出 Pipe 的通道和输入 Pipe 的通道。 ```kotlin linker.from(outputPipe, 0).to(inputPipe, 1) ``` -------------------------------- ### 执行 ShaderPipe 渲染帧 (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/shader-pipe.md 展示了如何在每一帧中执行 ShaderPipe 渲染管线。首先使用 writeFrame 写入世界或实体渲染内容到输入 Pipe,然后调用 render() 方法执行整个管线。 ```kotlin manager.writeFrame { // 把世界/实体渲染内容写入 input pipe } manager.render() ``` -------------------------------- ### Generate Fourier Curve from Image with FourierPhotoUtil Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Shows how to generate a Fourier curve from an image using FourierPhotoUtil. This involves converting the image into a Fourier builder with specified sample counts and harmonics, and then building the curve. ```kotlin val builder = FourierPhotoUtil.toFourierBuilder(image, sampleCount = 1024, harmonics = 120) val points = builder.build() ``` -------------------------------- ### 全局 Uniform 更新 (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/shader-pipe.md 演示了如何在 ShaderPipeManager 中注入全局 Uniform,以便在每个 Pipe 执行前访问。例如,可以注入转换矩阵或视图矩阵。 ```kotlin manager.addTransformUniformMatrix() // transMat/viewMat/projMat manager.updateGlobalUniform("viewMat", viewMatrix) ``` -------------------------------- ### 最小实现 DisplayEntity - Kotlin Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/display-entity.md 展示如何使用 Kotlin 实现一个基本的 DisplayEntity。需要继承 DisplayEntity 类,并实现 render 和 getCodec 方法。@CooAutoRegister 注解用于自动注册。 ```kotlin @CooAutoRegister class MyDisplayEntity(pos: Vec3, world: Level?) : DisplayEntity(pos, world) { @CodecField var lookDir = Vec3(0.0, 1.0, 0.0) override fun render( view: Matrix4f, proj: Matrix4f, modelMatrixStack: PoseStack, buffer: MultiBufferSource, delta: Float, camera: Camera ) { // 自定义渲染逻辑 } override fun getCodec(): StreamCodec { return DisplayEntityHelper.generateCodec(this) } } ``` -------------------------------- ### 创建和配置 ShaderPipeManager (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/shader-pipe.md 演示了如何使用 Kotlin 创建一个 ShaderPipeManager 实例,设置链接函数来定义渲染管道的输入和输出,并注册到 ClientRenderPipelineManager。需要 Minecraft 客户端环境和自定义着色器资源。 ```kotlin val manager = ShaderPipeManager(ResourceLocation.fromNamespaceAndPath("yourmod", "my_pipe")) .addTransformUniformMatrix() .setLinkerFunc { linker -> val input = valueInput( SimpleShaderPipe( IdentifierShader(ResourceLocation.fromNamespaceAndPath("yourmod", "pipe/frag/basic.fsh"), GlShaderType.FRAGMENT), { minecraft.mainRenderTarget.depthTextureId } ) ) val output = valueOutput( SimpleShaderPipe( IdentifierShader(ResourceLocation.fromNamespaceAndPath("yourmod", "pipe/frag/output.fsh"), GlShaderType.FRAGMENT), { minecraft.mainRenderTarget.depthTextureId } ) ) linker.from(input, 0).to(output, 0) } ClientRenderPipelineManager.register(manager) ``` -------------------------------- ### Minimal AutoParticleComposition Implementation in Kotlin Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/particle-composition.md Demonstrates the basic structure for creating a custom particle composition using AutoParticleComposition. It shows how to define particle properties, generate particle locations, and set up initial display actions. Requires the `coostack` library. ```kotlin @CooAutoRegister class MyComposition(position: Vec3, world: Level? = null) : AutoParticleComposition(position, world) { @CodecField var radius = 6.0 override fun getParticles(): Map { return PointsBuilder() .addCircle(radius, 200) .createWithCompositionData { CompositionData().addParticleInstanceInit { colorOfRGBA(255, 200, 80, 1f) } } } override fun onDisplay() { addPreTickAction { rotateAsAxis(Math.PI / 64) } } } ``` -------------------------------- ### PointsBuilder: Generate and Transform Point Sets Source: https://context7.com/coostack/cooparticlesapi/llms.txt Illustrates the usage of PointsBuilder for creating various point sets, including circles, lines, spirals, and spheres. It also shows how to apply transformations like rotation, scaling, and noise offset, and how to convert the point set into CompositionData for particle systems. ```kotlin // 基础用法:创建圆形点集 val circlePoints = PointsBuilder() .addCircle(radius = 6.0, count = 200) .create() // 组合多个图形 val complexPoints = PointsBuilder() .addCircle(3.0, 100) .addLine(RelativeLocation(0, 0, 0), RelativeLocation(0, 5, 0), 50) .addSpiral(startY = 0.0, endY = 8.0, radius = 2.0, count = 500, deltaAngle = Math.PI / 16) .create() // 应用变换 val transformedPoints = PointsBuilder() .addCircle(4.0, 150) .rotateAsAxis(Math.PI / 4) // 绕轴旋转 .rotateTo(RelativeLocation(1.0, 1.0, 0.0)) // 指向目标方向 .scale(1.5) // 缩放 .applyNoiseOffset(0.1, mode = NoiseMode.SPHERE_UNIFORM) // 添加噪声偏移 .create() // 转换为 CompositionData val compositionData = PointsBuilder() .addBall(radius = 2.0, count = 1000) .createWithCompositionData { CompositionData() .setDisplayerSupplier { ParticleDisplayer.withSingle(ControlableEnchantmentEffect(it)) } .addParticleInstanceInit { colorOfRGBA(120, 220, 255, 1f) size = 0.5f } .addParticleControlerInstanceInit { controler -> controler.addPreTickAction { // 粒子透明度渐变 particle.particleAlpha -= 0.02f } } } // 从图片生成点集 val imagePoints = PointsBuilder() .addImage(ImagePointBuilder(texture, scale = 0.1)) .create() // 傅里叶曲线 val fourierBuilder = FourierPhotoUtil.toFourierBuilder(image, sampleCount = 1024, harmonics = 120) val fourierPoints = PointsBuilder() .addPoints(fourierBuilder.build()) .create() ``` -------------------------------- ### Server-Side Entity Creation and Synchronization Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/render-entity.md Illustrates how to create and spawn a RenderEntity on the server. It also outlines the synchronization rules, including when 'toggle' packets are sent based on 'dirty' and 'alwaysToggle' states, and how to manually request synchronization. ```kotlin val entity = MyRenderEntity(serverLevel) entity.spawn(serverLevel, pos) // 同步规则: // - `dirty = true` 才会发送 toggle 包 // - `alwaysToggle = true` 则每 tick 都发送 // - `requestSync()` 发送一次后自动清除 `dirty` ``` -------------------------------- ### Register Mod Package for Scanning (Fabric) Source: https://context7.com/coostack/cooparticlesapi/llms.txt In a Fabric environment, this Kotlin code snippet is used during mod initialization to register your mod's package path. This enables the CooParticlesAPI's automatic scanning and registration of components. NeoForge does not require this step. ```kotlin // 在模组初始化时调用 CooAPIScanner.registerPacket("your.mod.package") ``` -------------------------------- ### Register and Bind RenderEntity Pipeline on Client Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/render-entity.md Shows how to register a custom RenderEntity with the client's rendering manager and bind it to a specific rendering pipeline. This step is crucial for the client to know how to render the entity. ```kotlin ClientRenderEntityManager.register(MyRenderEntity.ID, MyRenderEntity.CODEC) ClientRenderEntityManager.bindEntityRenderPipe(MyRenderEntity.ID, ShaderPipeManagers.simpleBloom.pipeID) ``` -------------------------------- ### Gradle Repository Configuration Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/README.md Configures the Gradle build system to use the jsdu Maven repository. This repository hosts the CooParticlesAPI and its dependencies, allowing Gradle to download them during the build process. ```gradle repositories { maven { name = "jsdu" url = "https://nexus.jsdu.cn/repository/maven-public/" } } ``` -------------------------------- ### Implement Minimal RenderEntity in Kotlin Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/render-entity.md Demonstrates the basic structure for creating a custom RenderEntity. It includes defining a unique ID, a codec for serialization, and implementing core methods like initialization, rendering, and resource release. The 'tracked' delegate is used for automatic dirty marking. ```kotlin class MyRenderEntity(world: Level?) : RenderEntity(world) { companion object { val ID = ResourceLocation.fromNamespaceAndPath("yourmod", "my_render_entity") val CODEC = RenderEntity.createCodec( { MyRenderEntity(null) }, encodeExtra = { buf, e -> buf.writeFloat(e.radius) }, decodeExtra = { buf, e -> e.radius = buf.readFloat() } ) } var radius by tracked(1.0f) // 自动标记 dirty override fun initialize() { // 客户端初始化:加载 shader / buffer } override fun getCodec(): StreamCodec = CODEC override fun getRenderID(): ResourceLocation = ID override fun render( matrices: Matrix4fStack, viewMatrix: Matrix4f, projMatrix: Matrix4f, tickDelta: Float ) { // 自定义渲染逻辑 } override fun release() { // 释放资源 } } ``` -------------------------------- ### Send Camera Shake with ServerCameraUtil Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Illustrates sending a camera shake effect to the server using ServerCameraUtil. This function takes the world context, amplitude, and duration (in ticks) of the shake as parameters. ```kotlin ServerCameraUtil.sendShake(world, amplitude = 0.6, tick = 20) ``` -------------------------------- ### Manual Event Listener Registration (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/event-bus.md Provides a method for manually registering event listeners without relying on automatic scanning. `CooEventBus.appendListenerTarget()` adds a specific listener class to be managed, and `CooEventBus.initListeners()` finalizes the registration process. ```kotlin CooEventBus.appendListenerTarget("your_mod_id", "com.example.MyEventListener") CooEventBus.initListeners() ``` -------------------------------- ### 绑定 RenderEntity 到 ShaderPipe (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/shader-pipe.md 展示了如何使用 ClientRenderEntityManager 将特定类型的 RenderEntity 绑定到指定的 ShaderPipe 管线。这允许为特定实体应用自定义的渲染效果。 ```kotlin ClientRenderEntityManager.bindEntityRenderPipe(MyRenderEntity.ID, ShaderPipeManagers.simpleBloom.pipeID) ``` -------------------------------- ### Manual Synchronization Calls Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/render-entity.md Provides alternatives to the 'tracked' delegate for manual synchronization control. It details the usage of 'markDirty()' for continuous synchronization and 'requestSync()' for a one-time synchronization event. ```kotlin // 如果不使用 `tracked`,需要手动调用: // - `markDirty()`:持续同步 // - `requestSync()`:同步一次 ``` -------------------------------- ### Gradle Dependency Declaration Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/README.md Declares the CooParticlesAPI as a dependency in a Gradle build file. It provides separate implementation lines for NeoForge and Fabric, allowing developers to choose the appropriate version for their mod loader. Replace `` with the latest release number. ```gradle dependencies { // neoforge implementation("cn.coostack:cooparticlesapi-neoforge:") // fabric implementation("cn.coostack:cooparticlesapi-fabric:") } ``` -------------------------------- ### Register Scan Packages for Fabric (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/event-bus.md For Fabric integration, this code snippet demonstrates how to register a package for automatic scanning of event listeners. `CooAPIScanner.registerPacket()` tells the `CooEventBus` where to look for classes annotated with `@EventListener`. ```kotlin CooAPIScanner.registerPacket("your.mod.package") ``` -------------------------------- ### Implement AutoParticleEmitters with Automatic Registration and Codec Fields Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/auto-particle-emitters.md This Kotlin code demonstrates the basic structure of an AutoParticleEmitters implementation. It uses @CooAutoRegister for automatic registration and @CodecField for automatic codec generation of particle properties like speed and color. The constructor must accept (Vec3, Level?) or be parameterless. @CodecField variables must be 'var' and of types registered in CodecHelper. ```kotlin @CooAutoRegister class MyEmitter(pos: Vec3, world: Level?) : AutoParticleEmitters(pos, world) { @CodecField var speed = 0.35 @CodecField var color = Vector3f(0.8f, 0.4f, 1.0f) override fun doTick() { // 服务端/客户端都会执行,可在这里更新位置或参数 } override fun genParticles(lerpProgress: Float): List> { return PointsBuilder() .addCircle(3.0, 60) .create() .map { ControlableParticleData().apply { this.speed = this@MyEmitter.speed } to it } } override fun singleParticleAction( controler: ParticleControler, data: ControlableParticleData, spawnPos: RelativeLocation, spawnWorld: Level, particleLerpProgress: Float, posLerpProgress: Float ) { // 对单个粒子的控制器做初始化 } } ``` -------------------------------- ### Create Sequenced Particle Effects (Kotlin) Source: https://context7.com/coostack/cooparticlesapi/llms.txt This Kotlin snippet shows how to implement `AutoSequencedParticleComposition` for creating particle sequences that appear and disappear gradually. It uses `@CodecField` for synchronized parameters and defines the particle sequence in `getParticleSequenced`. The `onDisplay` method controls the particle emission rate. ```kotlin @CooAutoRegister class MySpiralComposition(pos: Vec3, world: Level? = null) : AutoSequencedParticleComposition(pos, world) { @CodecField var height = 8.0 override fun getParticleSequenced(): SortedMap { var order = 0 return PointsBuilder() .addSpiral(0.0, height, 6.0, 1024, Math.PI / 32) .createWithCompositionDataSorted { CompositionData().apply { this.order = order++ } } } override fun onDisplay() { addPreTickAction { // 服务端每 tick 添加 30 个粒子 if (!client) { addMultiple(30) } } } } // 服务端调用 val spiral = MySpiralComposition(pos, serverLevel)spiral.spawn(serverLevel, pos) ``` -------------------------------- ### CooEventBus: Event Dispatching in Kotlin Source: https://context7.com/coostack/cooparticlesapi/llms.txt CooEventBus provides a lightweight event dispatching mechanism supporting priority, cancelable, and interruptible events. It involves defining custom events, writing event listeners annotated with @EventListener and @EventHandler, and then calling events using CooEventBus.call(). Listeners can be manually registered and initialized. ```kotlin // 1. 定义自定义事件 data class PlayerSkillEvent(val player: ServerPlayer, val skillId: String) : CooEvent(), EventCancelable { override var isCancelled: Boolean = false } // 2. 编写事件监听器 @EventListener("your_mod_id") object SkillEventListener { @EventHandler(EventPriority.HIGH) fun onPlayerSkill(event: PlayerSkillEvent) { if (event.player.isCreative) { // 创造模式下取消技能消耗 event.isCancelled = true } } @EventHandler(EventPriority.NORMAL) fun onPlayerSkillLog(event: PlayerSkillEvent) { println("Player ${event.player.name} used skill: ${event.skillId}") } } // 3. 触发事件 val event = CooEventBus.call(PlayerSkillEvent(player, "fireball")) if (event.isCancelled) { return } // 继续执行技能逻辑 // 手动注册监听器(可选) CooEventBus.appendListenerTarget("your_mod_id", "com.example.SkillEventListener") CooEventBus.initListeners() ``` -------------------------------- ### Calculate Next Velocity with PhysicsUtil Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Shows how to calculate the next velocity of an object influenced by an attractive force using PhysicsUtil. This function takes the current position, velocity, and target position as input. ```kotlin val nextVel = PhysicsUtil.nextAttractVelocity(pos, vel, target) ``` -------------------------------- ### Interpolate Value with InterpolatorDouble Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Demonstrates interpolating a double value over time using InterpolatorDouble. It shows how to update the value and retrieve the interpolated current value based on a progress factor. ```kotlin val angle = InterpolatorDouble(0.0) angle += Math.PI / 8 val current = angle.getWithInterpolator(lerpProgress) ``` -------------------------------- ### Manual Registration of Particle Emitter Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/codecfield-auto-register.md Illustrates the manual registration of a particle emitter class if automatic registration is not used. This involves creating an instance of the emitter and explicitly registering it with the ParticleEmittersManager. ```kotlin ParticleEmittersManager.register(MyEmitter(Vec3.ZERO, null)) ``` -------------------------------- ### Using 'tracked' Delegate for Automatic Synchronization Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/render-entity.md Explains the 'tracked' delegate in Kotlin, which automatically calls 'markDirty()' when a field's value changes. This simplifies synchronization by ensuring that changes to tracked properties are automatically flagged for server updates. ```kotlin var color by tracked(Vector3f(1f, 1f, 1f)) ``` -------------------------------- ### Kotlin: Animate Particle Emission Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/require.md Defines animation sequences for SequencedParticleComposition, specifying the number of particles and conditions for emission. Conditions can utilize global composition variables and default variables. ```kotlin init{ // 第一个参数数字代表生成的点个数 (只能选择常数整数) // 第二个是条件表达式 // 条件表达式里的可选变量是 composition的全局变量 + composition默认提供的变量 animate.addAnimate(1) { age > 1 } .addAnimate(1) { age > 6 } .addAnimate(2) { age > 11 } .addAnimate(1) { age > 16 } } ``` -------------------------------- ### Camera Shake Effect (Kotlin) Source: https://context7.com/coostack/cooparticlesapi/llms.txt Allows sending camera shake effects from the server to the client using ServerCameraUtil. You can specify the amplitude and duration (in ticks) of the shake, and target specific players or all players in the world. ```kotlin import com.coostack.cooparticlesapi.core.util.ServerCameraUtil import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerPlayer // 假设 serverLevel 和 serverPlayer 是已定义的 ServerLevel 和 ServerPlayer 实例 // val serverLevel: ServerLevel? = null // val serverPlayer: ServerPlayer? = null // 服务端发送抖动效果 // ServerCameraUtil.sendShake( // world = serverLevel, // amplitude = 0.6, // 抖动幅度 // tick = 20 // 持续时间(tick) // ) // 向特定玩家发送 // ServerCameraUtil.sendShakeTo( // player = serverPlayer, // amplitude = 0.8, // tick = 15 // ) ``` -------------------------------- ### Trigger and Check an Event (Kotlin) Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/event-bus.md Shows the process of triggering an event using `CooEventBus.call()` and subsequently checking if the event was cancelled by any listeners. If `event.isCancelled` is true, further processing related to this event can be skipped. ```kotlin val event = CooEventBus.call(MyEvent(player)) if (event.isCancelled) { return } ``` -------------------------------- ### Register Custom StreamCodec with CodecHelper Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/codecfield-auto-register.md Demonstrates how to define a custom StreamCodec for a data class and register it with CodecHelper. This is necessary when using custom types that are not built-in. The StreamCodec defines how to encode and decode the custom type to and from a FriendlyByteBuf. ```kotlin data class MyOption(val id: String, val power: Int) val MY_CODEC = StreamCodec.of( { buf, data -> buf.writeUtf(data.id) buf.writeInt(data.power) }, { buf -> MyOption(buf.readUtf(), buf.readInt()) } ) CodecHelper.register(MyOption::class.java, MY_CODEC) ``` -------------------------------- ### Kotlin: Particle Controler Tick Action Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/require.md Allows setting custom tick actions for particle controllers. This enables dynamic modification of particle properties like color, size, age, and alpha during runtime. ```kotlin data.addParticleControlerInstanceInit{ it.addPreTickAction{ // 可以获取和修改如下参数 // color,size,age,alpha,textureSheet } } ``` -------------------------------- ### Annotate Controlable Buffer Field Source: https://github.com/coostack/cooparticlesapi/blob/multiplatform/docs/utils.md Demonstrates how to use the @ControlableBuffer annotation to mark a field within a Controlable class for synchronization. The annotation specifies the name of the buffer field to be synchronized. ```kotlin @ControlableBuffer("size") var size = 1.0f ```