From 2212e67da216941da2d2bb7d5e6e93d744c3be6b Mon Sep 17 00:00:00 2001 From: Dylan Date: Sat, 21 Dec 2019 00:23:09 -0500 Subject: [PATCH] Progress --- build.gradle | 11 +- .../kotlin/co/q64/stars/block/BaseBlock.kt | 9 +- .../co/q64/stars/block/DarknessBlock.kt | 7 + .../co/q64/stars/block/DecayingBlock.kt | 2 - .../kotlin/co/q64/stars/block/FormedBlocks.kt | 7 - .../kotlin/co/q64/stars/block/GatewayBlock.kt | 16 ++ .../kotlin/co/q64/stars/block/SeedBlocks.kt | 3 - .../kotlin/co/q64/stars/block/StarsBlocks.kt | 12 +- .../co/q64/stars/capability/Gardener.kt | 36 ++-- .../kotlin/co/q64/stars/capability/Hub.kt | 6 + .../co/q64/stars/client/ClientLoader.kt | 4 +- .../co/q64/stars/client/render/RenderSetup.kt | 10 + .../client/render/tile/FormingBlockRender.kt | 192 ++++++++++++++++++ .../co/q64/stars/client/render/tile/TESRs.kt | 14 ++ .../co/q64/stars/command/StarsCommand.kt | 13 ++ .../kotlin/co/q64/stars/command/TpxCommand.kt | 21 ++ .../kotlin/co/q64/stars/dimension/Biomes.kt | 15 -- .../co/q64/stars/dimension/Dimensions.kt | 15 -- .../stars/dimension/ModDimensionExtensions.kt | 7 + .../co/q64/stars/dimension/Registries.kt | 39 ++++ .../fleeting/feature/DecayBlobFeature.kt | 7 + .../fleeting/placement/DecayBlobPlacement.kt | 38 ++++ .../kotlin/co/q64/stars/entity/EntityTypes.kt | 19 ++ .../co/q64/stars/entity/PickupEntity.kt | 52 +++++ .../q64/stars/listener/CapabilityListener.kt | 19 ++ .../stars/listener/InitializationListener.kt | 24 +++ .../kotlin/co/q64/stars/listener/Listeners.kt | 4 +- .../co/q64/stars/listener/PlayerListener.kt | 7 - .../co/q64/stars/listener/RegistryListener.kt | 26 +++ .../kotlin/co/q64/stars/net/ChannelHolder.kt | 31 +++ src/main/kotlin/co/q64/stars/net/Handlers.kt | 43 ++++ src/main/kotlin/co/q64/stars/net/Packets.kt | 16 ++ .../co/q64/stars/net/packets/ClientPackets.kt | 29 +++ .../co/q64/stars/net/packets/ServerPackets.kt | 32 +++ .../kotlin/co/q64/stars/tile/DecayTile.kt | 30 ++- .../kotlin/co/q64/stars/tile/FormingTile.kt | 72 ++++--- src/main/kotlin/co/q64/stars/tile/SeedTile.kt | 100 +++++---- .../co/q64/stars/tile/SyncTileEntity.kt | 31 ++- .../co/q64/stars/type/FormingBlockType.kt | 72 ++++++- src/main/kotlin/co/q64/stars/type/Level.kt | 14 +- .../kotlin/co/q64/stars/util/Capabilities.kt | 72 +++++++ src/main/kotlin/co/q64/stars/util/Decay.kt | 8 +- src/main/kotlin/co/q64/stars/util/Fleeting.kt | 79 +++++++ .../co/q64/stars/util/PlayerExtensions.kt | 90 ++++++++ .../kotlin/co/q64/stars/util/Sterilization.kt | 39 ++++ .../kotlin/co/q64/stars/util/Structures.kt | 178 +++++++++++++++- 46 files changed, 1418 insertions(+), 153 deletions(-) create mode 100644 src/main/kotlin/co/q64/stars/block/DarknessBlock.kt create mode 100644 src/main/kotlin/co/q64/stars/block/GatewayBlock.kt create mode 100644 src/main/kotlin/co/q64/stars/capability/Hub.kt create mode 100644 src/main/kotlin/co/q64/stars/client/render/RenderSetup.kt create mode 100644 src/main/kotlin/co/q64/stars/client/render/tile/FormingBlockRender.kt create mode 100644 src/main/kotlin/co/q64/stars/client/render/tile/TESRs.kt create mode 100644 src/main/kotlin/co/q64/stars/command/StarsCommand.kt create mode 100644 src/main/kotlin/co/q64/stars/command/TpxCommand.kt delete mode 100644 src/main/kotlin/co/q64/stars/dimension/Biomes.kt delete mode 100644 src/main/kotlin/co/q64/stars/dimension/Dimensions.kt create mode 100644 src/main/kotlin/co/q64/stars/dimension/ModDimensionExtensions.kt create mode 100644 src/main/kotlin/co/q64/stars/dimension/Registries.kt create mode 100644 src/main/kotlin/co/q64/stars/dimension/fleeting/placement/DecayBlobPlacement.kt create mode 100644 src/main/kotlin/co/q64/stars/entity/EntityTypes.kt create mode 100644 src/main/kotlin/co/q64/stars/entity/PickupEntity.kt create mode 100644 src/main/kotlin/co/q64/stars/listener/CapabilityListener.kt create mode 100644 src/main/kotlin/co/q64/stars/listener/InitializationListener.kt create mode 100644 src/main/kotlin/co/q64/stars/net/ChannelHolder.kt create mode 100644 src/main/kotlin/co/q64/stars/net/Handlers.kt create mode 100644 src/main/kotlin/co/q64/stars/net/Packets.kt create mode 100644 src/main/kotlin/co/q64/stars/net/packets/ClientPackets.kt create mode 100644 src/main/kotlin/co/q64/stars/net/packets/ServerPackets.kt create mode 100644 src/main/kotlin/co/q64/stars/util/Capabilities.kt create mode 100644 src/main/kotlin/co/q64/stars/util/Fleeting.kt create mode 100644 src/main/kotlin/co/q64/stars/util/PlayerExtensions.kt create mode 100644 src/main/kotlin/co/q64/stars/util/Sterilization.kt diff --git a/build.gradle b/build.gradle index 28e2630..785bd06 100644 --- a/build.gradle +++ b/build.gradle @@ -6,19 +6,20 @@ buildscript { } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true + classpath "org.jetbrains.kotlin:kotlin-serialization:1.3.61" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" } } plugins { id "org.jetbrains.kotlin.jvm" version "1.3.61" + id 'org.jetbrains.kotlin.plugin.serialization' version '1.3.60' id 'com.github.johnrengelman.shadow' version '4.0.4' //id "net.ltgt.apt" version "0.21" //id "net.ltgt.apt-idea" version "0.21" } apply plugin: 'net.minecraftforge.gradle' -// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. apply plugin: 'eclipse' apply plugin: 'maven-publish' @@ -28,6 +29,12 @@ archivesBaseName = 'stars' sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. +tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } +} + minecraft { // The mappings can be changed at any time, and must be in the following format. // snapshot_YYYYMMDD Snapshot are built nightly. @@ -101,6 +108,7 @@ dependencies { // http://www.gradle.org/docs/current/userguide/dependency_management.html compile "org.jetbrains.kotlin:kotlin-stdlib" + compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.14.0" // Dev environment compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.26:api") @@ -128,6 +136,7 @@ shadowJar { } relocate('kotlin', 'co.q64.library.kotlin') + relocate('kotlinx', 'co.q64.library.kotlinx') } jar.dependsOn 'shadowJar' diff --git a/src/main/kotlin/co/q64/stars/block/BaseBlock.kt b/src/main/kotlin/co/q64/stars/block/BaseBlock.kt index 9eb41bf..f1293d1 100644 --- a/src/main/kotlin/co/q64/stars/block/BaseBlock.kt +++ b/src/main/kotlin/co/q64/stars/block/BaseBlock.kt @@ -1,11 +1,16 @@ package co.q64.stars.block +import co.q64.stars.id import net.minecraft.block.Block +import net.minecraft.block.SoundType import net.minecraft.block.material.Material -abstract class BaseBlock(id: String, properties: Properties = Properties.create(Material.IRON)) : Block(properties) { +val earth = Block.Properties.create(Material.EARTH).sound(SoundType.GROUND).hardnessAndResistance(0f, 0f) +val hard = Block.Properties.create(Material.IRON).sound(SoundType.METAL).hardnessAndResistance(-1f, 3600000f) + +abstract class BaseBlock(blockId: String, properties: Properties = Properties.create(Material.IRON)) : Block(properties) { init { - setRegistryName(id) + id = blockId } } diff --git a/src/main/kotlin/co/q64/stars/block/DarknessBlock.kt b/src/main/kotlin/co/q64/stars/block/DarknessBlock.kt new file mode 100644 index 0000000..13547bf --- /dev/null +++ b/src/main/kotlin/co/q64/stars/block/DarknessBlock.kt @@ -0,0 +1,7 @@ +package co.q64.stars.block + +import net.minecraft.state.BooleanProperty + +object DarknessBlock : BaseBlock("darkness", hard) { + val active: BooleanProperty = BooleanProperty.create("active") +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/block/DecayingBlock.kt b/src/main/kotlin/co/q64/stars/block/DecayingBlock.kt index 05bd78d..679f1a8 100644 --- a/src/main/kotlin/co/q64/stars/block/DecayingBlock.kt +++ b/src/main/kotlin/co/q64/stars/block/DecayingBlock.kt @@ -9,8 +9,6 @@ import net.minecraft.tileentity.TileEntity import net.minecraft.util.BlockRenderLayer import net.minecraft.world.IBlockReader -private val earth = Block.Properties.create(Material.EARTH).sound(SoundType.GROUND).hardnessAndResistance(0f, 0f) - object DecayingBlock : BaseBlock("decaying", earth) { override fun getRenderLayer() = BlockRenderLayer.CUTOUT override fun hasTileEntity(state: BlockState) = true diff --git a/src/main/kotlin/co/q64/stars/block/FormedBlocks.kt b/src/main/kotlin/co/q64/stars/block/FormedBlocks.kt index ed16b6c..b4d9b37 100644 --- a/src/main/kotlin/co/q64/stars/block/FormedBlocks.kt +++ b/src/main/kotlin/co/q64/stars/block/FormedBlocks.kt @@ -1,12 +1,5 @@ package co.q64.stars.block -import net.minecraft.block.Block -import net.minecraft.block.SoundType -import net.minecraft.block.material.Material - -private val earth = Block.Properties.create(Material.EARTH).sound(SoundType.GROUND).hardnessAndResistance(0f, 0f) -private val hard = Block.Properties.create(Material.IRON).sound(SoundType.METAL).hardnessAndResistance(-1f, 3600000f) - sealed class FormedBlock(id: String, properties: Properties = earth) : BaseBlock(id, properties) object BlueFormedBlock : FormedBlock("blue_formed") object BrownFormedBlock : FormedBlock("brown_formed") diff --git a/src/main/kotlin/co/q64/stars/block/GatewayBlock.kt b/src/main/kotlin/co/q64/stars/block/GatewayBlock.kt new file mode 100644 index 0000000..825d1ba --- /dev/null +++ b/src/main/kotlin/co/q64/stars/block/GatewayBlock.kt @@ -0,0 +1,16 @@ +package co.q64.stars.block + +import co.q64.stars.type.Level +import net.minecraft.block.Block +import net.minecraft.block.BlockState +import net.minecraft.state.BooleanProperty +import net.minecraft.state.EnumProperty +import net.minecraft.state.StateContainer + +object GatewayBlock : BaseBlock("gateway", hard) { + val type = EnumProperty.create("type", Level::class.java) + val complete = BooleanProperty.create("complete") + + override fun fillStateContainer(builder: StateContainer.Builder) = + super.fillStateContainer(builder.add(type).add(complete)) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/block/SeedBlocks.kt b/src/main/kotlin/co/q64/stars/block/SeedBlocks.kt index a0d73aa..4c60b6f 100644 --- a/src/main/kotlin/co/q64/stars/block/SeedBlocks.kt +++ b/src/main/kotlin/co/q64/stars/block/SeedBlocks.kt @@ -9,9 +9,6 @@ import net.minecraft.tileentity.TileEntity import net.minecraft.util.BlockRenderLayer import net.minecraft.world.IBlockReader -private val earth = Block.Properties.create(Material.EARTH).sound(SoundType.GROUND).hardnessAndResistance(0f, 0f) -private val hard = Block.Properties.create(Material.IRON).sound(SoundType.METAL).hardnessAndResistance(-1f, 3600000f) - sealed class BaseSeedBlock(id: String, properties: Properties = earth) : BaseBlock(id, properties) { override fun getRenderLayer() = BlockRenderLayer.CUTOUT override fun hasTileEntity(state: BlockState) = true diff --git a/src/main/kotlin/co/q64/stars/block/StarsBlocks.kt b/src/main/kotlin/co/q64/stars/block/StarsBlocks.kt index 0b68d6a..0a10f1c 100644 --- a/src/main/kotlin/co/q64/stars/block/StarsBlocks.kt +++ b/src/main/kotlin/co/q64/stars/block/StarsBlocks.kt @@ -10,6 +10,7 @@ val blocks: List by lazy { BrownFormedBlock, CyanFormedBlock, GreenFormedBlock, + GreenFruitBlock, OrangeFormedBlock, PinkFormedBlock, PurpleFormedBlock, @@ -24,10 +25,19 @@ val blocks: List by lazy { BrownFormedBlockHard, CyanFormedBlockHard, GreenFormedBlockHard, + GreenFruitBlockHard, OrangeFormedBlockHard, PurpleFormedBlockHard, RedFormedBlockHard, RedPrimedBlockHard, - YellowFormedBlockHard + YellowFormedBlockHard, + + DecayBlock, + DecaySolidBlock, + AirDecayBlock, + SpecialDecayBlock, + SpecialDecaySolidBlock, + DarknessBlock, + GatewayBlock ) } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/capability/Gardener.kt b/src/main/kotlin/co/q64/stars/capability/Gardener.kt index 1bbbd20..fb25caa 100644 --- a/src/main/kotlin/co/q64/stars/capability/Gardener.kt +++ b/src/main/kotlin/co/q64/stars/capability/Gardener.kt @@ -1,13 +1,19 @@ +@file:UseSerializers(BlockPosSerializer::class, ResourceLocationSerializer::class, SoundEventSerializer::class) + package co.q64.stars.capability -import co.q64.stars.type.FleetingStage -import co.q64.stars.type.FormingBlockType -import co.q64.stars.type.Level +import co.q64.stars.type.* +import co.q64.stars.util.BlockPosSerializer +import co.q64.stars.util.ResourceLocationSerializer +import co.q64.stars.util.SoundEventSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.UseSerializers import net.minecraft.util.ResourceLocation import net.minecraft.util.SoundEvent import net.minecraft.util.math.BlockPos import java.util.* +@Serializable data class Gardener( var seeds: Int = 0, var keys: Int = 0, @@ -23,13 +29,19 @@ data class Gardener( var completeChallenge: Boolean = false, var tutorialMode: Boolean = false, var fleetingStage: FleetingStage = FleetingStage.NONE, - var level: Level, - var hubSpawn: BlockPos, - var hubEntryPosition: BlockPos, - var hubEntryDimension: ResourceLocation, - var tutorialEntryPosition: BlockPos, - var tutorialEntryDimension: ResourceLocation, - var nextSeeds: Deque = ArrayDeque(), + var lastSeed: FormingBlockType = BlueFormingBlockType, + var level: Level = RedLevel, // TODO + var hubSpawn: BlockPos = BlockPos.ZERO, + var hubEntryPosition: BlockPos = BlockPos.ZERO, + var hubEntryDimension: ResourceLocation? = null, + var tutorialEntryPosition: BlockPos = BlockPos.ZERO, + var tutorialEntryDimension: ResourceLocation? = null, + var nextSeeds: MutableList = mutableListOf(), var lastSounds: Set = mutableSetOf(), - var lastPlayed: Map = mutableMapOf() -) \ No newline at end of file + var lastPlayed: MutableMap = mutableMapOf() +) { + //fun getLastPlayed(event: SoundEvent) = lastPlayed.getOrDefault(event, 0L) + //fun updatePlayed(event: SoundEvent, time: Long) { + //lastPlayed[event] = time + // } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/capability/Hub.kt b/src/main/kotlin/co/q64/stars/capability/Hub.kt new file mode 100644 index 0000000..a731fef --- /dev/null +++ b/src/main/kotlin/co/q64/stars/capability/Hub.kt @@ -0,0 +1,6 @@ +package co.q64.stars.capability + +import kotlinx.serialization.Serializable + +@Serializable +data class Hub(var next: Int = 0) \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/client/ClientLoader.kt b/src/main/kotlin/co/q64/stars/client/ClientLoader.kt index 72763c9..7274827 100644 --- a/src/main/kotlin/co/q64/stars/client/ClientLoader.kt +++ b/src/main/kotlin/co/q64/stars/client/ClientLoader.kt @@ -1,5 +1,7 @@ package co.q64.stars.client -fun startClient() { +import co.q64.stars.client.render.initializeRendering +fun startClient() { + initializeRendering() } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/client/render/RenderSetup.kt b/src/main/kotlin/co/q64/stars/client/render/RenderSetup.kt new file mode 100644 index 0000000..5ff063d --- /dev/null +++ b/src/main/kotlin/co/q64/stars/client/render/RenderSetup.kt @@ -0,0 +1,10 @@ +package co.q64.stars.client.render + +import co.q64.stars.client.render.tile.tesrs +import net.minecraftforge.fml.client.registry.ClientRegistry + +fun initializeRendering() { + tesrs.forEach { (type, render) -> + ClientRegistry.bindTileEntitySpecialRenderer(type.java, render) + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/client/render/tile/FormingBlockRender.kt b/src/main/kotlin/co/q64/stars/client/render/tile/FormingBlockRender.kt new file mode 100644 index 0000000..81d35cb --- /dev/null +++ b/src/main/kotlin/co/q64/stars/client/render/tile/FormingBlockRender.kt @@ -0,0 +1,192 @@ +package co.q64.stars.client.render.tile + +import co.q64.stars.tile.FormingTile +import co.q64.stars.type.FormingBlockType +import com.mojang.blaze3d.platform.GlStateManager +import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.renderer.tileentity.TileEntityRenderer +import net.minecraft.client.renderer.vertex.DefaultVertexFormats +import net.minecraft.util.Direction +import org.lwjgl.opengl.GL11 + + +object FormingBlockRender : TileEntityRenderer() { + private const val width = 0.0625f + + override fun render(tile: FormingTile, x: Double, y: Double, z: Double, partialTicks: Float, destroyStage: Int) { + if (!tile.data.ready) { + return + } + val type: FormingBlockType = tile.data.type + val direction: Direction = tile.data.direction + val buildTime: Int = tile.data.buildTime + var timeSincePlace: Float = (System.currentTimeMillis() - tile.data.placed).toFloat() + if (timeSincePlace > buildTime) { + timeSincePlace = buildTime.toFloat() + } + val progress = timeSincePlace / buildTime + var bottomCapProgress = progress * 5 + var sideProgress = (progress - 0.2f) * 1.666f + var topCapProgress = (progress - 0.8f) * 5 + bottomCapProgress = if (bottomCapProgress > 1) 1f else bottomCapProgress + sideProgress = if (sideProgress > 1) 1f else sideProgress + topCapProgress = if (topCapProgress > 1) 1f else topCapProgress + GlStateManager.disableLighting() + GlStateManager.disableCull() + GlStateManager.enableBlend() + GlStateManager.disableTexture() + GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO) + GlStateManager.color4f(type.red / 256f, type.green / 256f, type.blue / 256f, 1f) + GlStateManager.polygonOffset(-1f, -1f) + GlStateManager.enablePolygonOffset() + GlStateManager.pushMatrix() + GlStateManager.translated(x, y, z) + when (direction) { + Direction.DOWN -> { + GlStateManager.translated(0.0, 1.0, 1.0) + GlStateManager.rotated(180.0, 1.0, 0.0, 0.0) + } + Direction.NORTH -> { + GlStateManager.translated(0.0, 0.0, 1.0) + GlStateManager.rotated(90.0, -1.0, 0.0, 0.0) + } + Direction.SOUTH -> { + GlStateManager.translated(0.0, 1.0, 0.0) + GlStateManager.rotated(90.0, 1.0, 0.0, 0.0) + } + Direction.WEST -> { + GlStateManager.translated(1.0, 0.0, 0.0) + GlStateManager.rotated(90.0, 0.0, 0.0, 1.0) + } + Direction.EAST -> { + GlStateManager.translated(0.0, 1.0, 0.0) + GlStateManager.rotated(90.0, 0.0, 0.0, -1.0) + } + Direction.UP -> { + } + } + val tessellator = Tessellator.getInstance() + val builder = tessellator.buffer + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION) + renderBottomCap(builder, bottomCapProgress) + if (sideProgress > 0) { + renderSides(builder, sideProgress) + } + if (topCapProgress > 0) { + renderTopCap(builder, topCapProgress) + } + tessellator.draw() + GlStateManager.popMatrix() + GlStateManager.enableCull() + GlStateManager.enableTexture() + GlStateManager.enableLighting() + GlStateManager.disableBlend() + GlStateManager.disablePolygonOffset() + } + + private fun renderSides(builder: BufferBuilder, progress: Float) = with(builder) { + pos(0.0, 0.0, 0.0).endVertex() + pos(width.toDouble(), 0.0, 0.0).endVertex() + pos(width.toDouble(), progress.toDouble(), 0.0).endVertex() + pos(0.0, progress.toDouble(), 0.0).endVertex() + pos(0.0, 0.0, 0.0).endVertex() + pos(0.0, 0.0, width.toDouble()).endVertex() + pos(0.0, progress.toDouble(), width.toDouble()).endVertex() + pos(0.0, progress.toDouble(), 0.0).endVertex() + pos(1.0, 0.0, 0.0).endVertex() + pos(1 - width.toDouble(), 0.0, 0.0).endVertex() + pos(1 - width.toDouble(), progress.toDouble(), 0.0).endVertex() + pos(1.0, progress.toDouble(), 0.0).endVertex() + pos(1.0, 0.0, 0.0).endVertex() + pos(1.0, 0.0, width.toDouble()).endVertex() + pos(1.0, progress.toDouble(), width.toDouble()).endVertex() + pos(1.0, progress.toDouble(), 0.0).endVertex() + pos(0.0, 0.0, 1.0).endVertex() + pos(width.toDouble(), 0.0, 1.0).endVertex() + pos(width.toDouble(), progress.toDouble(), 1.0).endVertex() + pos(0.0, progress.toDouble(), 1.0).endVertex() + pos(0.0, 0.0, 1.0).endVertex() + pos(0.0, 0.0, 1 - width.toDouble()).endVertex() + pos(0.0, progress.toDouble(), 1 - width.toDouble()).endVertex() + pos(0.0, progress.toDouble(), 1.0).endVertex() + pos(1.0, 0.0, 1.0).endVertex() + pos(1 - width.toDouble(), 0.0, 1.0).endVertex() + pos(1 - width.toDouble(), progress.toDouble(), 1.0).endVertex() + pos(1.0, progress.toDouble(), 1.0).endVertex() + pos(1.0, 0.0, 1.0).endVertex() + pos(1.0, 0.0, 1 - width.toDouble()).endVertex() + pos(1.0, progress.toDouble(), 1 - width.toDouble()).endVertex() + pos(1.0, progress.toDouble(), 1.0).endVertex() + } + + private fun renderBottomCap(builder: BufferBuilder, progress: Float) = with(builder) { + pos(0.0, 0.0, 0.0).endVertex() + pos(width.toDouble(), 0.0, 0.0).endVertex() + pos(width.toDouble(), 0.0, progress.toDouble()).endVertex() + pos(0.0, 0.0, progress.toDouble()).endVertex() + pos(0.0, 0.0, 0.0).endVertex() + pos(0.0, width.toDouble(), 0.0).endVertex() + pos(0.0, width.toDouble(), progress.toDouble()).endVertex() + pos(0.0, 0.0, progress.toDouble()).endVertex() + pos(1.0, 0.0, 1.0).endVertex() + pos(1 - width.toDouble(), 0.0, 1.0).endVertex() + pos(1 - width.toDouble(), 0.0, 1 - progress.toDouble()).endVertex() + pos(1.0, 0.0, 1 - progress.toDouble()).endVertex() + pos(1.0, 0.0, 1.0).endVertex() + pos(1.0, width.toDouble(), 1.0).endVertex() + pos(1.0, width.toDouble(), 1 - progress.toDouble()).endVertex() + pos(1.0, 0.0, 1 - progress.toDouble()).endVertex() + pos(0.0, 0.0, 1.0).endVertex() + pos(0.0, width.toDouble(), 1.0).endVertex() + pos(progress.toDouble(), width.toDouble(), 1.0).endVertex() + pos(progress.toDouble(), 0.0, 1.0).endVertex() + pos(0.0, 0.0, 1.0).endVertex() + pos(0.0, 0.0, 1 - width.toDouble()).endVertex() + pos(progress.toDouble(), 0.0, 1 - width.toDouble()).endVertex() + pos(progress.toDouble(), 0.0, 1.0).endVertex() + pos(1.0, 0.0, 0.0).endVertex() + pos(1.0, width.toDouble(), 0.0).endVertex() + pos(1 - progress.toDouble(), width.toDouble(), 0.0).endVertex() + pos(1 - progress.toDouble(), 0.0, 0.0).endVertex() + pos(1.0, 0.0, 0.0).endVertex() + pos(1.0, 0.0, width.toDouble()).endVertex() + pos(1 - progress.toDouble(), 0.0, width.toDouble()).endVertex() + pos(1 - progress.toDouble(), 0.0, 0.0).endVertex() + } + + private fun renderTopCap(builder: BufferBuilder, progress: Float) = with(builder) { + pos(0.0, 1.0, 0.0).endVertex() + pos(width.toDouble(), 1.0, 0.0).endVertex() + pos(width.toDouble(), 1.0, progress.toDouble()).endVertex() + pos(0.0, 1.0, progress.toDouble()).endVertex() + pos(0.0, 1.0, 0.0).endVertex() + pos(0.0, 1 - width.toDouble(), 0.0).endVertex() + pos(0.0, 1 - width.toDouble(), progress.toDouble()).endVertex() + pos(0.0, 1.0, progress.toDouble()).endVertex() + pos(1.0, 1.0, 1.0).endVertex() + pos(1 - width.toDouble(), 1.0, 1.0).endVertex() + pos(1 - width.toDouble(), 1.0, 1 - progress.toDouble()).endVertex() + pos(1.0, 1.0, 1 - progress.toDouble()).endVertex() + pos(1.0, 1.0, 1.0).endVertex() + pos(1.0, 1 - width.toDouble(), 1.0).endVertex() + pos(1.0, 1 - width.toDouble(), 1 - progress.toDouble()).endVertex() + pos(1.0, 1.0, 1 - progress.toDouble()).endVertex() + pos(0.0, 1.0, 1.0).endVertex() + pos(0.0, 1 - width.toDouble(), 1.0).endVertex() + pos(progress.toDouble(), 1 - width.toDouble(), 1.0).endVertex() + pos(progress.toDouble(), 1.0, 1.0).endVertex() + pos(0.0, 1.0, 1.0).endVertex() + pos(0.0, 1.0, 1 - width.toDouble()).endVertex() + pos(progress.toDouble(), 1.0, 1 - width.toDouble()).endVertex() + pos(progress.toDouble(), 1.0, 1.0).endVertex() + pos(1.0, 1.0, 0.0).endVertex() + pos(1.0, 1 - width.toDouble(), 0.0).endVertex() + pos(1 - progress.toDouble(), 1 - width.toDouble(), 0.0).endVertex() + pos(1 - progress.toDouble(), 1.0, 0.0).endVertex() + pos(1.0, 1.0, 0.0).endVertex() + pos(1.0, 1.0, width.toDouble()).endVertex() + pos(1 - progress.toDouble(), 1.0, width.toDouble()).endVertex() + pos(1 - progress.toDouble(), 1.0, 0.0).endVertex() + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/client/render/tile/TESRs.kt b/src/main/kotlin/co/q64/stars/client/render/tile/TESRs.kt new file mode 100644 index 0000000..9db50a4 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/client/render/tile/TESRs.kt @@ -0,0 +1,14 @@ +package co.q64.stars.client.render.tile + +import co.q64.stars.tile.FormingTile +import net.minecraft.client.renderer.tileentity.TileEntityRenderer +import net.minecraft.tileentity.TileEntity +import kotlin.reflect.KClass + +data class TESRDefinition(val type: KClass, val render: TileEntityRenderer) + +val tesrs by lazy { + listOf( + TESRDefinition(FormingTile::class, FormingBlockRender) + ) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/command/StarsCommand.kt b/src/main/kotlin/co/q64/stars/command/StarsCommand.kt new file mode 100644 index 0000000..413d1bf --- /dev/null +++ b/src/main/kotlin/co/q64/stars/command/StarsCommand.kt @@ -0,0 +1,13 @@ +package co.q64.stars.command + +import com.mojang.brigadier.CommandDispatcher +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import net.minecraft.command.CommandSource + +fun CommandDispatcher.stars() { + register(LiteralArgumentBuilder.literal("stars") + .then(tpxCommand) + .then(enterCommand.register()) + .then(hubCommand.register()) + .then(challengeCommand.register())) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/command/TpxCommand.kt b/src/main/kotlin/co/q64/stars/command/TpxCommand.kt new file mode 100644 index 0000000..1b9e241 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/command/TpxCommand.kt @@ -0,0 +1,21 @@ +package co.q64.stars.command + +import com.mojang.brigadier.context.CommandContext +import com.mojang.brigadier.exceptions.CommandSyntaxException +import net.minecraft.command.CommandSource +import net.minecraft.command.Commands +import net.minecraft.command.arguments.DimensionArgument +import net.minecraftforge.common.DimensionManager + +val tpxCommand = Commands.literal("tpx") + .requires { it.hasPermissionLevel(2) } + .then(Commands.argument("dim", DimensionArgument.getDimension()).executes(::execute)); + +@Throws(CommandSyntaxException::class) +private fun execute(context: CommandContext): Int { + val dim = DimensionArgument.func_212592_a(context, "dim") + val player = context.source.asPlayer() + val pos = player.position + player.teleport(DimensionManager.getWorld(player.getServer(), dim, false, true), pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), player.getYaw(1.0f), player.getPitch(1.0f)) + return 0 +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/Biomes.kt b/src/main/kotlin/co/q64/stars/dimension/Biomes.kt deleted file mode 100644 index bf36ec3..0000000 --- a/src/main/kotlin/co/q64/stars/dimension/Biomes.kt +++ /dev/null @@ -1,15 +0,0 @@ -package co.q64.stars.dimension - -import co.q64.stars.dimension.fleeting.ChallengeBiome -import co.q64.stars.dimension.fleeting.FleetingBiome -import co.q64.stars.dimension.fleeting.FleetingSolidBiome -import co.q64.stars.dimension.hub.HubBiome - -val biomes by lazy { - listOf( - FleetingBiome, - FleetingSolidBiome, - ChallengeBiome, - HubBiome - ) -} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/Dimensions.kt b/src/main/kotlin/co/q64/stars/dimension/Dimensions.kt deleted file mode 100644 index aab2a25..0000000 --- a/src/main/kotlin/co/q64/stars/dimension/Dimensions.kt +++ /dev/null @@ -1,15 +0,0 @@ -package co.q64.stars.dimension - -import co.q64.stars.dimension.fleeting.ChallengeDimensionTemplate -import co.q64.stars.dimension.fleeting.FleetingDimensionTemplate -import co.q64.stars.dimension.fleeting.FleetingSolidDimensionTemplate -import co.q64.stars.dimension.hub.HubDimensionTemplate - -val dimensions by lazy { - listOf( - HubDimensionTemplate, - FleetingDimensionTemplate, - FleetingSolidDimensionTemplate, - ChallengeDimensionTemplate - ) -} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/ModDimensionExtensions.kt b/src/main/kotlin/co/q64/stars/dimension/ModDimensionExtensions.kt new file mode 100644 index 0000000..ad728b2 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/dimension/ModDimensionExtensions.kt @@ -0,0 +1,7 @@ +package co.q64.stars.dimension + +import net.minecraft.world.dimension.DimensionType +import net.minecraftforge.common.ModDimension + +val ModDimension.type: DimensionType + get() = DimensionType.byName(registryName!!)!! // TODO lol \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/Registries.kt b/src/main/kotlin/co/q64/stars/dimension/Registries.kt new file mode 100644 index 0000000..c027ce1 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/dimension/Registries.kt @@ -0,0 +1,39 @@ +package co.q64.stars.dimension + +import co.q64.stars.dimension.fleeting.* +import co.q64.stars.dimension.fleeting.feature.DecayBlobFeature +import co.q64.stars.dimension.fleeting.feature.SolidDecayBlobFeature +import co.q64.stars.dimension.fleeting.placement.DecayBlobPlacement +import co.q64.stars.dimension.hub.HubBiome +import co.q64.stars.dimension.hub.HubDimensionTemplate + +val biomes by lazy { + listOf( + FleetingBiome, + FleetingSolidBiome, + ChallengeBiome, + HubBiome + ) +} + +val dimensions by lazy { + listOf( + HubDimensionTemplate, + FleetingDimensionTemplate, + FleetingSolidDimensionTemplate, + ChallengeDimensionTemplate + ) +} + +val features by lazy { + listOf( + DecayBlobFeature, + SolidDecayBlobFeature + ) +} + +val placements by lazy { + listOf( + DecayBlobPlacement + ) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/fleeting/feature/DecayBlobFeature.kt b/src/main/kotlin/co/q64/stars/dimension/fleeting/feature/DecayBlobFeature.kt index d5051f9..e9ed1f0 100644 --- a/src/main/kotlin/co/q64/stars/dimension/fleeting/feature/DecayBlobFeature.kt +++ b/src/main/kotlin/co/q64/stars/dimension/fleeting/feature/DecayBlobFeature.kt @@ -1,6 +1,7 @@ package co.q64.stars.dimension.fleeting.feature import co.q64.stars.block.DecayBlock +import co.q64.stars.block.DecaySolidBlock import co.q64.stars.block.SpecialDecayBlock import co.q64.stars.id import co.q64.stars.util.SPREAD_DISTANCE @@ -71,4 +72,10 @@ object DecayBlobFeature : DecayBlobFeatureBase(DecayBlock) { init { id = "decay_blob" } +} + +object SolidDecayBlobFeature : DecayBlobFeatureBase(DecaySolidBlock) { + init { + id = "solid_decay_blob" + } } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/dimension/fleeting/placement/DecayBlobPlacement.kt b/src/main/kotlin/co/q64/stars/dimension/fleeting/placement/DecayBlobPlacement.kt new file mode 100644 index 0000000..b898b3b --- /dev/null +++ b/src/main/kotlin/co/q64/stars/dimension/fleeting/placement/DecayBlobPlacement.kt @@ -0,0 +1,38 @@ +package co.q64.stars.dimension.fleeting.placement + +import co.q64.stars.id +import co.q64.stars.util.SPREAD_DISTANCE +import net.minecraft.util.math.BlockPos +import net.minecraft.world.gen.placement.NoPlacementConfig +import net.minecraft.world.gen.placement.SimplePlacement +import java.util.* +import java.util.stream.Stream +import kotlin.math.roundToInt + + +object DecayBlobPlacement : SimplePlacement(NoPlacementConfig::deserialize) { + private const val MIN_SPAWN_DIST = 16 + + init { + id = "decay_blob" + } + + override fun getPositions(random: Random, config: NoPlacementConfig?, pos: BlockPos): Stream? { + val nearestIsland = BlockPos( + SPREAD_DISTANCE * (pos.x / SPREAD_DISTANCE.toDouble()).roundToInt(), + pos.y, + SPREAD_DISTANCE * (pos.z / SPREAD_DISTANCE.toDouble()).roundToInt() + ) + val high: Boolean = pos.distanceSq(nearestIsland) < MIN_SPAWN_DIST * MIN_SPAWN_DIST + //val dist: Int = sqrt(pos.distanceSq(nearestIsland)).toInt() - MIN_SPAWN_DIST + var stream: Stream = Stream.empty() + for (i in 0..29) { + stream = generate(stream, pos, random, high) + } + return stream + } + + private fun generate(stream: Stream, pos: BlockPos, random: Random, high: Boolean): Stream { + return Stream.concat(stream, Stream.of(pos.add(random.nextInt(16), if (high) 130 + random.nextInt(100) else 20 + random.nextInt(180), random.nextInt(16)))) + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/entity/EntityTypes.kt b/src/main/kotlin/co/q64/stars/entity/EntityTypes.kt new file mode 100644 index 0000000..382ea21 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/entity/EntityTypes.kt @@ -0,0 +1,19 @@ +package co.q64.stars.entity + +import co.q64.stars.id +import net.minecraft.entity.EntityClassification +import net.minecraft.entity.EntityType + +val pickupEntityType = EntityType.Builder.create({ _: EntityType, world -> PickupEntity(world) }, EntityClassification.MISC).apply { + disableSerialization() + size(0.5f, 0.5f) + setCustomClientFactory { _, world -> PickupEntity(world) } +}.build("pickup").apply { + id = "pickup" +} + +val entityTypes by lazy { + listOf( + pickupEntityType + ) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/entity/PickupEntity.kt b/src/main/kotlin/co/q64/stars/entity/PickupEntity.kt new file mode 100644 index 0000000..af26207 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/entity/PickupEntity.kt @@ -0,0 +1,52 @@ +package co.q64.stars.entity + +import co.q64.stars.util.load +import co.q64.stars.util.toNBT +import kotlinx.serialization.Serializable +import net.minecraft.entity.Entity +import net.minecraft.nbt.CompoundNBT +import net.minecraft.network.IPacket +import net.minecraft.network.datasync.DataSerializers +import net.minecraft.network.datasync.EntityDataManager +import net.minecraft.world.World +import net.minecraftforge.fml.network.NetworkHooks + +class PickupEntity(world: World) : Entity(pickupEntityType, world) { + var variant: Variant + get() = Variant.values()[dataManager[variantProp]] + set(value) = dataManager.set(variantProp, value.ordinal) + var age: Int = 0 + var location: Long = 0L + + override fun tick() { + age++ + super.tick() + } + + override fun canTriggerWalking() = false + override fun createSpawnPacket(): IPacket<*> = NetworkHooks.getEntitySpawningPacket(this) + override fun isGlowing() = true + override fun registerData() = dataManager.register(variantProp, 0) + + override fun readAdditional(compound: CompoundNBT) { + compound.load(Data.serializer()).let { + variant = it.variant + location = it.location + } + } + + override fun writeAdditional(compound: CompoundNBT) { + Data.serializer().toNBT(Data(variant, location), compound) + } + + enum class Variant { + HEART, KEY, STAR, ARROW, CHALLENGE + } + + @Serializable + private data class Data(val variant: Variant, val location: Long) + + companion object { + private val variantProp = EntityDataManager.createKey(PickupEntity::class.java, DataSerializers.VARINT) + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/listener/CapabilityListener.kt b/src/main/kotlin/co/q64/stars/listener/CapabilityListener.kt new file mode 100644 index 0000000..bf6d50b --- /dev/null +++ b/src/main/kotlin/co/q64/stars/listener/CapabilityListener.kt @@ -0,0 +1,19 @@ +package co.q64.stars.listener + +import co.q64.stars.capability.Gardener +import co.q64.stars.id +import co.q64.stars.util.CapabilityBase +import co.q64.stars.util.gardenerCapability +import net.minecraft.entity.Entity +import net.minecraft.entity.player.ServerPlayerEntity +import net.minecraftforge.event.AttachCapabilitiesEvent +import net.minecraftforge.eventbus.api.SubscribeEvent + +object CapabilityListener { + @SubscribeEvent + fun onCapabilityAttachEntity(event: AttachCapabilitiesEvent) { + if (event.getObject() is ServerPlayerEntity) { + event.addCapability("gardener".id, CapabilityBase(gardenerCapability, Gardener.serializer())) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/listener/InitializationListener.kt b/src/main/kotlin/co/q64/stars/listener/InitializationListener.kt new file mode 100644 index 0000000..cb61a2d --- /dev/null +++ b/src/main/kotlin/co/q64/stars/listener/InitializationListener.kt @@ -0,0 +1,24 @@ +package co.q64.stars.listener + +import co.q64.stars.capability.Gardener +import co.q64.stars.command.stars +import co.q64.stars.net.ChannelHolder +import co.q64.stars.util.NoopStorage +import net.minecraftforge.common.capabilities.CapabilityManager +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent +import net.minecraftforge.fml.event.server.FMLServerStartingEvent + +object InitializationListener { + + @SubscribeEvent + fun onInitialize(event: FMLCommonSetupEvent) { + with(CapabilityManager.INSTANCE) { + register(Gardener::class.java, NoopStorage()) { Gardener() } + } + ChannelHolder.register() + } + + @SubscribeEvent + fun onServerStars(event: FMLServerStartingEvent) = event.commandDispatcher.stars() +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/listener/Listeners.kt b/src/main/kotlin/co/q64/stars/listener/Listeners.kt index 4632a6e..7650108 100644 --- a/src/main/kotlin/co/q64/stars/listener/Listeners.kt +++ b/src/main/kotlin/co/q64/stars/listener/Listeners.kt @@ -3,6 +3,8 @@ package co.q64.stars.listener val listeners by lazy { listOf( RegistryListener, - PlayerListener + PlayerListener, + CapabilityListener, + InitializationListener ) } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/listener/PlayerListener.kt b/src/main/kotlin/co/q64/stars/listener/PlayerListener.kt index 475dfa8..9c9e055 100644 --- a/src/main/kotlin/co/q64/stars/listener/PlayerListener.kt +++ b/src/main/kotlin/co/q64/stars/listener/PlayerListener.kt @@ -3,13 +3,6 @@ package co.q64.stars.listener object PlayerListener { /* - @SubscribeEvent - fun onCapabilityAttachEntity(event: AttachCapabilitiesEvent) { - if (event.getObject() is ServerPlayerEntity) { - event.addCapability("gardener".id, gardenerCapabilityProvider.get()) - } - } - @SubscribeEvent fun onCapabilityAttachWorld(event: AttachCapabilitiesEvent) { if (event.getObject().getDimension() is HubDimension) { diff --git a/src/main/kotlin/co/q64/stars/listener/RegistryListener.kt b/src/main/kotlin/co/q64/stars/listener/RegistryListener.kt index 983a4cc..7260a11 100644 --- a/src/main/kotlin/co/q64/stars/listener/RegistryListener.kt +++ b/src/main/kotlin/co/q64/stars/listener/RegistryListener.kt @@ -3,14 +3,24 @@ package co.q64.stars.listener import co.q64.stars.block.blocks import co.q64.stars.dimension.biomes import co.q64.stars.dimension.dimensions +import co.q64.stars.dimension.features +import co.q64.stars.dimension.placements +import co.q64.stars.entity.entityTypes +import co.q64.stars.id import co.q64.stars.item.items import co.q64.stars.tile.tileTypes import net.minecraft.block.Block +import net.minecraft.entity.EntityType import net.minecraft.item.Item import net.minecraft.tileentity.TileEntityType import net.minecraft.world.biome.Biome +import net.minecraft.world.dimension.DimensionType +import net.minecraft.world.gen.feature.Feature +import net.minecraft.world.gen.placement.Placement +import net.minecraftforge.common.DimensionManager import net.minecraftforge.common.ModDimension import net.minecraftforge.event.RegistryEvent.Register +import net.minecraftforge.event.world.RegisterDimensionsEvent import net.minecraftforge.eventbus.api.SubscribeEvent object RegistryListener { @@ -28,4 +38,20 @@ object RegistryListener { @SubscribeEvent fun onDimensionRegistry(event: Register) = dimensions.forEach { event.registry.register(it) } + + @SubscribeEvent + fun onFeatureRegistry(event: Register>) = features.forEach { event.registry.register(it) } + + @SubscribeEvent + fun onPlacementRegistry(event: Register>) = placements.forEach { event.registry.register(it) } + + @SubscribeEvent + fun onEntityTypeRegistry(event: Register>) = entityTypes.forEach { event.registry.register(it) } + + @SubscribeEvent + fun onRegisterDimensions(event: RegisterDimensionsEvent) = dimensions.forEach { + if (DimensionType.byName(it.registryName ?: "invalid".id) == null) { + DimensionManager.registerDimension(it.registryName, it, null, false) + } + } } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/net/ChannelHolder.kt b/src/main/kotlin/co/q64/stars/net/ChannelHolder.kt new file mode 100644 index 0000000..18bef02 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/net/ChannelHolder.kt @@ -0,0 +1,31 @@ +package co.q64.stars.net + +import co.q64.stars.id +import net.minecraft.entity.player.ServerPlayerEntity +import net.minecraftforge.fml.network.NetworkRegistry +import net.minecraftforge.fml.network.PacketDistributor + +private const val protocolVersion = "2" +private val channel = NetworkRegistry.ChannelBuilder.named("main".id) + .clientAcceptedVersions { it == ChannelHolder.protocolVersion || it == NetworkRegistry.ABSENT } + .serverAcceptedVersions { it == ChannelHolder.protocolVersion || it == NetworkRegistry.ABSENT } + .networkProtocolVersion { ChannelHolder.protocolVersion } + .simpleChannel() + +object ChannelHolder { + fun register() { + channel.registerMessage(0, PacketContainer::class.java, { packet, buffer -> + packet.encode(buffer) + }, { buffer -> + PacketContainer(buffer) + }, { packet, context -> + packet.handle(context) + }) + } + + +} + +fun ServerPlayerEntity.sendPacket(packet: Packet) { + channel.send(PacketDistributor.PLAYER.with { this }, packet) +} diff --git a/src/main/kotlin/co/q64/stars/net/Handlers.kt b/src/main/kotlin/co/q64/stars/net/Handlers.kt new file mode 100644 index 0000000..e74a1ec --- /dev/null +++ b/src/main/kotlin/co/q64/stars/net/Handlers.kt @@ -0,0 +1,43 @@ +package co.q64.stars.net + +import co.q64.stars.util.load +import co.q64.stars.util.toNBT +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import net.minecraft.network.PacketBuffer +import net.minecraftforge.fml.network.NetworkEvent +import java.util.function.Supplier + +@Serializable +open class Packet(val type: PacketType) + +class PacketContainer { + private val data: T? + private val serializer: KSerializer? + + constructor(data: T, serializer: KSerializer) { + this.data = data + this.serializer = serializer + } + + constructor(buffer: PacketBuffer) { + val tag = buffer.readCompoundTag() + this.serializer = tag?.load(Packet.serializer())?.type?.serializer as? KSerializer + this.data = serializer?.let { + tag?.load(serializer) + } + } + + fun encode(buffer: PacketBuffer) { + serializer?.let { + buffer.writeCompoundTag(serializer.toNBT(data ?: return)) + } + } + + fun handle(context: Supplier) { + context.get().enqueueWork { + data?.type?.handler?.invoke(data) + } + context.get().packetHandled = true + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/net/Packets.kt b/src/main/kotlin/co/q64/stars/net/Packets.kt new file mode 100644 index 0000000..1171082 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/net/Packets.kt @@ -0,0 +1,16 @@ +package co.q64.stars.net + +import co.q64.stars.net.packets.* +import kotlinx.serialization.KSerializer + + +enum class PacketType(val serializer: KSerializer<*>, val handler: (Any) -> Unit) { + // Client -> Server + PLANT_SEED(PlantSeedPacket.serializer(), { if (it is PlantSeedPacket) PlantSeedPacket.handle(it) }), + LOST(LostPacket.serializer(), { if (it is LostPacket) LostPacket.handle(it) }), + UPDATE_JUMP(UpdateJumpPacket.serializer(), { if (it is UpdateJumpPacket) UpdateJumpPacket.handle(it) }), + + // Server -> Client + FADE_SCREEN(FadeScreenPacket.serializer(), { if (it is FadeScreenPacket) FadeScreenPacket.handle(it) }), + SYNC_CAPABILITY(SyncCapabilityPacket.serializer(), { if (it is SyncCapabilityPacket) SyncCapabilityPacket.handle(it) }) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/net/packets/ClientPackets.kt b/src/main/kotlin/co/q64/stars/net/packets/ClientPackets.kt new file mode 100644 index 0000000..7b06872 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/net/packets/ClientPackets.kt @@ -0,0 +1,29 @@ +package co.q64.stars.net.packets + +import co.q64.stars.capability.Gardener +import co.q64.stars.net.Packet +import co.q64.stars.net.PacketType +import co.q64.stars.util.gardenerClient +import kotlinx.serialization.Serializable + +@Serializable +data class SyncCapabilityPacket(val capability: Gardener) : Packet(PacketType.SYNC_CAPABILITY) { + companion object { + fun handle(packet: SyncCapabilityPacket) { + gardenerClient = packet.capability + } + } +} + +@Serializable +data class FadeScreenPacket(val mode: FadeMode, val time: Long) : Packet(PacketType.FADE_SCREEN) { + enum class FadeMode { // TODO Move + TO_WHITE, FROM_WHITE, TO_BLACK, FROM_BLACK + } + + companion object { + fun handle(packet: FadeScreenPacket) { + + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/net/packets/ServerPackets.kt b/src/main/kotlin/co/q64/stars/net/packets/ServerPackets.kt new file mode 100644 index 0000000..e2d013b --- /dev/null +++ b/src/main/kotlin/co/q64/stars/net/packets/ServerPackets.kt @@ -0,0 +1,32 @@ +package co.q64.stars.net.packets + +import co.q64.stars.net.Packet +import co.q64.stars.net.PacketType +import kotlinx.serialization.Serializable + +@Serializable +class PlantSeedPacket : Packet(PacketType.PLANT_SEED) { + companion object { + fun handle(packet: PlantSeedPacket) { + + } + } +} + +@Serializable +class LostPacket : Packet(PacketType.LOST) { + companion object { + fun handle(packet: LostPacket) { + + } + } +} + +@Serializable +data class UpdateJumpPacket(val jumping: Boolean) : Packet(PacketType.UPDATE_JUMP) { + companion object { + fun handle(packet: UpdateJumpPacket) { + + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/tile/DecayTile.kt b/src/main/kotlin/co/q64/stars/tile/DecayTile.kt index 78ac512..f49bc89 100644 --- a/src/main/kotlin/co/q64/stars/tile/DecayTile.kt +++ b/src/main/kotlin/co/q64/stars/tile/DecayTile.kt @@ -1,5 +1,6 @@ package co.q64.stars.tile +import kotlinx.serialization.Serializable import net.minecraft.tileentity.ITickableTileEntity import net.minecraft.util.Direction import net.minecraft.world.server.ServerWorld @@ -7,19 +8,30 @@ import net.minecraft.world.server.ServerWorld private val directions = Direction.values() class DecayTile : SyncTileEntity(decayTileType), ITickableTileEntity { - var ticks = 0 - var active = false + var data: Data = Data() + + @Serializable + data class Data( + var multiplier: Double = 1.0, + var active: Boolean = false + ) + + init { + sync(::data, Data.serializer()) + } override fun tick() { - world?.let { world -> - if (world.isRemote && !active) return - if (ticks == 0) { - (world as? ServerWorld)?.getClosestPlayer(pos.x.toDouble(), pos.z.toDouble(), 1000.0)?.let { - // TODO level type + with(data) { + world?.let { world -> + if (world.isRemote && !active) return + if (ticks == 0) { + (world as? ServerWorld)?.getClosestPlayer(pos.x.toDouble(), pos.z.toDouble(), 1000.0)?.let { + // TODO level type + } } - } - var count = 0 + var count = 0 + } } } diff --git a/src/main/kotlin/co/q64/stars/tile/FormingTile.kt b/src/main/kotlin/co/q64/stars/tile/FormingTile.kt index d4c8d5a..c850d3c 100644 --- a/src/main/kotlin/co/q64/stars/tile/FormingTile.kt +++ b/src/main/kotlin/co/q64/stars/tile/FormingTile.kt @@ -2,7 +2,7 @@ package co.q64.stars.tile import co.q64.stars.type.BlueFormingBlockType import co.q64.stars.type.FormingBlockType -import net.minecraft.nbt.CompoundNBT +import kotlinx.serialization.Serializable import net.minecraft.particles.ParticleTypes import net.minecraft.tileentity.ITickableTileEntity import net.minecraft.util.Direction @@ -15,36 +15,49 @@ private const val fruitChance = 3 private val directions = Direction.values() class FormingTile : SyncTileEntity(formingTileType), ITickableTileEntity { - var first: Boolean = true - var hard: Boolean = false - var multiplier: Double = 1.0 - var iterations: Int = 5 - var direction: Direction = Direction.UP - var formTicks: Int = 0 - var ready: Boolean = false - var buildTime: Int = 0 - var placed: Long = System.currentTimeMillis() - var ticks = 0 + var data = Data() + + @Serializable + data class Data( + var first: Boolean = true, + var hard: Boolean = false, + var multiplier: Double = 1.0, + var iterations: Int = 5, + var direction: Direction = Direction.UP, + var formTicks: Int = 0, + var ready: Boolean = false, + var buildTime: Int = 0, + var placed: Long = System.currentTimeMillis(), + var ticks: Int = 0, + var type: FormingBlockType = BlueFormingBlockType + ) + + init { + sync(::data, Data.serializer()) + } var type: FormingBlockType = BlueFormingBlockType set(type) { - field = type - buildTime = type.buildTime - if (type.buildTimeOffset > 0) { - buildTime += Random.nextInt(-type.buildTimeOffset, type.buildTimeOffset) - } - /* + with(data) { + field = type + buildTime = type.buildTime + if (type.buildTimeOffset > 0) { + buildTime += Random.nextInt(-type.buildTimeOffset, type.buildTimeOffset) + } + /* if (formType == brownFormingBlockType && direction == Direction.DOWN) { buildTime = 250; } */ - buildTime = (buildTime * multiplier).toInt() - formTicks = buildTime / 50 - if (first) { - iterations = type.iterations(MathHelper.getPositionRandom(getPos())) + buildTime = (buildTime * multiplier).toInt() + formTicks = buildTime / 50 + if (first) { + iterations = type.iterations(MathHelper.getPositionRandom(getPos())) + } } } + /* override fun read(compound: CompoundNBT) { with(compound) { direction = Direction.valueOf(getString("direction")) @@ -67,16 +80,19 @@ class FormingTile : SyncTileEntity(formingTileType), ITickableTileEntity { putInt("buildTime", buildTime) } } + */ override fun tick() { - world?.let { world -> - if (first && !ready) { - direction = type.firstDirection(world, pos) ?: Direction.UP - ready = true - world.notifyBlockUpdate(pos, blockState, blockState, 2) + with(data) { + world?.let { world -> + if (first && !ready) { + direction = type.firstDirection(world, pos) ?: Direction.UP + ready = true + world.notifyBlockUpdate(pos, blockState, blockState, 2) + } + if (ticks == formTicks) form(world) + ticks++ } - if (ticks == formTicks) form(world) - ticks++ } } diff --git a/src/main/kotlin/co/q64/stars/tile/SeedTile.kt b/src/main/kotlin/co/q64/stars/tile/SeedTile.kt index aac0966..31d1c0b 100644 --- a/src/main/kotlin/co/q64/stars/tile/SeedTile.kt +++ b/src/main/kotlin/co/q64/stars/tile/SeedTile.kt @@ -7,7 +7,7 @@ import co.q64.stars.block.RedFormedBlockHard import co.q64.stars.type.BlueFormingBlockType import co.q64.stars.type.FormingBlockType import co.q64.stars.type.RedFormingBlockType -import net.minecraft.nbt.CompoundNBT +import kotlinx.serialization.Serializable import net.minecraft.tileentity.ITickableTileEntity import net.minecraft.tileentity.TileEntityType import net.minecraft.util.Direction @@ -15,6 +15,9 @@ import net.minecraft.world.World import net.minecraft.world.server.ServerWorld open class SeedTile(type: TileEntityType<*> = seedTileType) : SyncTileEntity(type), ITickableTileEntity { + var data = Data() + + /* var direction: Direction? = null var ticks = 20 var active = false @@ -24,7 +27,22 @@ open class SeedTile(type: TileEntityType<*> = seedTileType) : SyncTileEntity(typ var primed = false var fruit = false var multiplier = 1.0 + */ + + @Serializable + data class Data( + var direction: Direction? = null, + var ticks: Int = 20, + var active: Boolean = false, + var ready: Boolean = false, + var type: FormingBlockType = BlueFormingBlockType, + var seed: FormingBlockType = BlueFormingBlockType, + var primed: Boolean = false, + var fruit: Boolean = false, + var multiplier: Double = 1.0 + ) + /* override fun read(compound: CompoundNBT) = with(compound) { super.read(this) type = FormingBlockType.fromId(getString("type")) @@ -45,54 +63,66 @@ open class SeedTile(type: TileEntityType<*> = seedTileType) : SyncTileEntity(typ putBoolean("active", active) return super.write(compound) } + */ + init { + sync(::data, Data.serializer()) + } override fun tick() { - world?.let { world -> - if (world.isRemote && !active) return - if (ticks == 0) { - (world as? ServerWorld)?.getClosestPlayer(pos.x.toDouble(), pos.z.toDouble(), 1000.0)?.let { - // TODO level type + with(data) { + world?.let { world -> + if (world.isRemote && !active) return + if (ticks == 0) { + (world as? ServerWorld)?.getClosestPlayer(pos.x.toDouble(), pos.z.toDouble(), 1000.0)?.let { + // TODO level type + } } + var count = 0 + if (ticks == 0) { + grow(world) + } else if (ticks < 0) { + check(world) + } + ticks-- } - var count = 0 - if (ticks == 0) { - grow(world) - } else if (ticks < 0) { - check(world) - } - ticks-- } } private fun grow(world: World) { - if (primed) { - RedFormingBlockType.explode(world as ServerWorld, pos, false) - return - } - direction = seed.firstDirection(world, pos) - direction?.let { - val target = pos.offset(it) - world.setBlockState(target, FormingBlock.defaultState) - (world.getTileEntity(target) as? FormingTile)?.apply { - first = true - direction = it - multiplier = this@SeedTile.multiplier - hard = blockState.block is HardBlock - type = seed - ready = true + with(data) { + if (primed) { + RedFormingBlockType.explode(world as ServerWorld, pos, false) + return + } + direction = seed.firstDirection(world, pos) + direction?.let { + val target = pos.offset(it) + world.setBlockState(target, FormingBlock.defaultState) + (world.getTileEntity(target) as? FormingTile)?.apply { + with(data) { + first = true + direction = it + multiplier = this@with.multiplier + hard = blockState.block is HardBlock + type = seed + ready = true + } + } } } } private fun check(world: World) { - direction?.let { - val hard = blockState.block is HardBlock - if (world.getBlockState(pos.offset(it)).block != FormingBlock) { - if (type is RedFormingBlockType) { - world.setBlockState(pos, if (hard) RedFormedBlockHard.defaultState else RedFormedBlock.defaultState) - } else { - world.setBlockState(pos, if (hard) type.formedHard.defaultState else type.formed.defaultState) + with(data) { + direction?.let { + val hard = blockState.block is HardBlock + if (world.getBlockState(pos.offset(it)).block != FormingBlock) { + if (type is RedFormingBlockType) { + world.setBlockState(pos, if (hard) RedFormedBlockHard.defaultState else RedFormedBlock.defaultState) + } else { + world.setBlockState(pos, if (hard) type.formedHard.defaultState else type.formed.defaultState) + } } } } diff --git a/src/main/kotlin/co/q64/stars/tile/SyncTileEntity.kt b/src/main/kotlin/co/q64/stars/tile/SyncTileEntity.kt index aacb5b8..8e37388 100644 --- a/src/main/kotlin/co/q64/stars/tile/SyncTileEntity.kt +++ b/src/main/kotlin/co/q64/stars/tile/SyncTileEntity.kt @@ -1,20 +1,43 @@ package co.q64.stars.tile +import co.q64.stars.util.load +import kotlinx.serialization.KSerializer import net.minecraft.nbt.CompoundNBT import net.minecraft.network.NetworkManager import net.minecraft.network.play.server.SUpdateTileEntityPacket import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntityType +import kotlin.reflect.KMutableProperty0 abstract class SyncTileEntity(type: TileEntityType<*>) : TileEntity(type) { - override fun getUpdateTag(): CompoundNBT = super.getUpdateTag().apply { write(this) } - override fun handleUpdateTag(tag: CompoundNBT) = run { super.handleUpdateTag(tag) }.run { read(tag) } - override fun onDataPacket(net: NetworkManager, packet: SUpdateTileEntityPacket) = read(packet.nbtCompound) + private val synced = mutableListOf>() - override fun getUpdatePacket(): SUpdateTileEntityPacket? { + fun sync(prop: KMutableProperty0, serializer: KSerializer) { + synced.add(SyncedProperty(prop, serializer)) + } + + final override fun getUpdateTag(): CompoundNBT = super.getUpdateTag().apply { write(this) } + final override fun handleUpdateTag(tag: CompoundNBT) = run { super.handleUpdateTag(tag) }.run { read(tag) } + final override fun onDataPacket(net: NetworkManager, packet: SUpdateTileEntityPacket) = read(packet.nbtCompound) + + final override fun getUpdatePacket(): SUpdateTileEntityPacket? { with(CompoundNBT()) { write(this) return SUpdateTileEntityPacket(getPos(), 1, this) } } + + final override fun read(compound: CompoundNBT) { + super.read(compound) + synced.forEach { + val thing = compound.getCompound(it.prop.name).load(it.serializer) + (it.prop as KMutableProperty0).set(thing) + } + } + + final override fun write(compound: CompoundNBT): CompoundNBT { + return super.write(compound) + } + + private data class SyncedProperty(val prop: KMutableProperty0, val serializer: KSerializer) } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/type/FormingBlockType.kt b/src/main/kotlin/co/q64/stars/type/FormingBlockType.kt index 8000bc5..0829bfc 100644 --- a/src/main/kotlin/co/q64/stars/type/FormingBlockType.kt +++ b/src/main/kotlin/co/q64/stars/type/FormingBlockType.kt @@ -5,6 +5,8 @@ import co.q64.stars.block.BlueFormedBlockHard import co.q64.stars.block.DarkAirBlock import co.q64.stars.item.BlueRobustSeedItem import co.q64.stars.item.BlueSeedItem +import kotlinx.serialization.* +import kotlinx.serialization.internal.StringDescriptor import net.minecraft.block.Block import net.minecraft.block.Blocks import net.minecraft.item.Item @@ -39,8 +41,13 @@ sealed class FormingBlockType( open fun firstDirection(world: World, position: BlockPos): Direction? = Direction.UP open fun nextDirections(world: World, position: BlockPos, last: Direction, iterations: Int): List = listOf() - companion object { - fun fromId(id: String) = types.find { it.id == id } ?: BlueFormingBlockType + @Serializer(FormingBlockType::class) + companion object : KSerializer { + override val descriptor: SerialDescriptor = StringDescriptor.withName("FormingBlockType") + override fun serialize(encoder: Encoder, obj: FormingBlockType) = encoder.encodeString(obj.id) + override fun deserialize(decoder: Decoder): FormingBlockType = fromId(decoder.decodeString()) + + fun fromId(id: String) = formingTypes.find { it.id == id } ?: BlueFormingBlockType } } @@ -73,8 +80,67 @@ object RedFormingBlockType : FormingBlockType( } } -val types by lazy { +object PinkFormingBlockType : FormingBlockType( + id = "pink", + buildTime = 4500, + green = 114, + blue = 255, + formed = BlueFormedBlock, + formedHard = BlueFormedBlockHard, + seed = BlueSeedItem, + seedRobust = BlueRobustSeedItem +) { +} + +object CyanFormingBlockType : FormingBlockType( + id = "cyan", + buildTime = 4500, + green = 114, + blue = 255, + formed = BlueFormedBlock, + formedHard = BlueFormedBlockHard, + seed = BlueSeedItem, + seedRobust = BlueRobustSeedItem +) { + +} + +object YellowFormingBlockType : FormingBlockType( + id = "cyan", + buildTime = 4500, + green = 114, + blue = 255, + formed = BlueFormedBlock, + formedHard = BlueFormedBlockHard, + seed = BlueSeedItem, + seedRobust = BlueRobustSeedItem +) { + +} + +object GreenFormingBlockType : FormingBlockType( + id = "cyan", + buildTime = 4500, + green = 114, + blue = 255, + formed = BlueFormedBlock, + formedHard = BlueFormedBlockHard, + seed = BlueSeedItem, + seedRobust = BlueRobustSeedItem +) { + +} + +val formingTypes: List by lazy { listOf( BlueFormingBlockType ) +} + +val fleetingFormingTypes by lazy { + formingTypes.filter { it.canGrow() } +} + +val hubFormingTypes by lazy { + fleetingFormingTypes.filter { it !is PinkFormingBlockType } } \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/type/Level.kt b/src/main/kotlin/co/q64/stars/type/Level.kt index 16444ed..58ade0f 100644 --- a/src/main/kotlin/co/q64/stars/type/Level.kt +++ b/src/main/kotlin/co/q64/stars/type/Level.kt @@ -1,4 +1,14 @@ package co.q64.stars.type -sealed class Level -object RedLevel : Level() \ No newline at end of file +import net.minecraft.util.IStringSerializable + +enum class Level(val id: String) : IStringSerializable { + RED("red"), + PURPLE("purple"), + WHITE("white"), + ORANGE("orange"), + TEAL("teal"), + CYAN("cyan"); + + override fun getName(): String = id +} diff --git a/src/main/kotlin/co/q64/stars/util/Capabilities.kt b/src/main/kotlin/co/q64/stars/util/Capabilities.kt new file mode 100644 index 0000000..f4d7b86 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/util/Capabilities.kt @@ -0,0 +1,72 @@ +package co.q64.stars.util + +import co.q64.stars.capability.Gardener +import co.q64.stars.capability.Hub +import kotlinx.serialization.KSerializer +import net.minecraft.entity.player.ServerPlayerEntity +import net.minecraft.nbt.CompoundNBT +import net.minecraft.nbt.INBT +import net.minecraft.util.Direction +import net.minecraft.world.World +import net.minecraftforge.common.capabilities.Capability +import net.minecraftforge.common.capabilities.CapabilityInject +import net.minecraftforge.common.capabilities.ICapabilitySerializable +import net.minecraftforge.common.util.LazyOptional + +object ForgeBlackMagic { + @JvmField + @CapabilityInject(Gardener::class) + var gardener: Capability? = null + + @JvmField + @CapabilityInject(Hub::class) + var hub: Capability? = null +} + +val gardenerCapability by lazy { ForgeBlackMagic.gardener ?: error("Gardener capability not injected") } +val hubCapability by lazy { ForgeBlackMagic.hub ?: error("Hub capability not injected") } + +var gardenerClient = Gardener() + +val ServerPlayerEntity.gardener: Gardener + get() { + if (!getCapability(gardenerCapability).isPresent) + error("Could not find capability!") + return getCapability(gardenerCapability).orElse(Gardener()) + } + +val World.hub: Hub + get() { + if (!getCapability(hubCapability).isPresent) + error("Could not find capability!") + return getCapability(hubCapability).orElse(Hub()) + } + +class CapabilityBase(private val capability: Capability, private val serializer: KSerializer) : ICapabilitySerializable { + private var instance: T = capability.defaultInstance!! + + override fun getCapability(cap: Capability, side: Direction?): LazyOptional { + if (cap != capability) return LazyOptional.empty() + return LazyOptional.of { instance } as LazyOptional + } + + override fun deserializeNBT(nbt: CompoundNBT?) { + val bytes = nbt?.getByteArray("data") ?: byteArrayOf() + if (bytes.isEmpty()) return + instance = cbor.load(serializer, bytes) + } + + override fun serializeNBT(): CompoundNBT { + return CompoundNBT().apply { + putByteArray("data", cbor.dump(serializer, instance)) + } + } +} + +class NoopStorage : Capability.IStorage { + override fun readNBT(capability: Capability?, instance: T, side: Direction?, nbt: INBT?) = + error("This capability does not support storage") + + override fun writeNBT(capability: Capability?, instance: T, side: Direction?): INBT = + error("This capability does not support storage") +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/util/Decay.kt b/src/main/kotlin/co/q64/stars/util/Decay.kt index dd42a78..80d43d7 100644 --- a/src/main/kotlin/co/q64/stars/util/Decay.kt +++ b/src/main/kotlin/co/q64/stars/util/Decay.kt @@ -10,7 +10,7 @@ import net.minecraft.world.World import net.minecraft.world.server.ServerWorld -fun activateDecay(world: ServerWorld, pos: BlockPos) { +fun ServerWorld.activateDecay(pos: BlockPos) { for (direction in directions) { val target = pos.offset(direction) val state = world.getBlockState(target) @@ -20,10 +20,10 @@ fun activateDecay(world: ServerWorld, pos: BlockPos) { } } -fun isDecayBlock(world: World, pos: BlockPos) = world.getBlockState(pos) is BaseDecayBlock +fun World.isDecayBlock(pos: BlockPos) = getBlockState(pos) is BaseDecayBlock -fun createSpecialDecay(world: IWorld, pos: BlockPos, type: SpecialDecayType, notify: Boolean = true) = - world.setBlockState(pos, SpecialDecayBlock.defaultState.with(BaseDecayBlock.type, type), if (notify) 3 else 2) +fun IWorld.createSpecialDecay(pos: BlockPos, type: SpecialDecayType, notify: Boolean = true) = + setBlockState(pos, SpecialDecayBlock.defaultState.with(BaseDecayBlock.type, type), if (notify) 3 else 2) enum class SpecialDecayType : IStringSerializable { HEART, DOOR, CHALLENGE_DOOR, KEY; diff --git a/src/main/kotlin/co/q64/stars/util/Fleeting.kt b/src/main/kotlin/co/q64/stars/util/Fleeting.kt new file mode 100644 index 0000000..1646ee7 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/util/Fleeting.kt @@ -0,0 +1,79 @@ +package co.q64.stars.util + +import co.q64.stars.block.DecayBlock +import co.q64.stars.block.OrangeFormedBlock +import co.q64.stars.block.OrangeFormedBlockHard +import co.q64.stars.dimension.fleeting.ChallengeDimensionTemplate +import co.q64.stars.dimension.fleeting.FleetingDimensionTemplate +import co.q64.stars.dimension.fleeting.FleetingSolidDimensionTemplate +import co.q64.stars.dimension.type +import co.q64.stars.tile.DecayTile +import co.q64.stars.type.Level +import net.minecraft.entity.player.ServerPlayerEntity +import net.minecraft.potion.EffectInstance +import net.minecraft.potion.Effects +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World +import net.minecraftforge.common.DimensionManager +import sun.audio.AudioPlayer.player +import java.util.* + + +private val levitationQueue: MutableMap = mutableMapOf() + + +fun ServerPlayerEntity.starsTick() { + levitationQueue[uniqueID]?.let { ticks -> + if (ticks > 0) { + levitationQueue[uniqueID] = ticks + return + } + levitationQueue.remove(uniqueID) + playerManager.useSeed(player, { + addPotionEffect(EffectInstance(Effects.LEVITATION, 200, 1, true, false)) + //sounds.playSound(player.getServerWorld(), player.getPosition(), bubbleSound, 1f) + }) + } +} + +private val ServerPlayerEntity.fleetingWorld: World + get() = with(gardener) { + DimensionManager.getWorld(server, when { + openChallengeDoor -> ChallengeDimensionTemplate.type + level == Level.TEAL -> FleetingSolidDimensionTemplate.type + else -> FleetingDimensionTemplate.type + }, false, true)!! + } + + +private fun ServerPlayerEntity.setupFleeting(world: World, pos: BlockPos, level: Level) { + for (y in pos.y - 8 until pos.y) { + for (x in pos.x - 2..pos.x + 2) { + for (z in pos.z - 2..pos.z + 2) { + world.setBlockState(BlockPos(x, y, z), + if (gardener.level === Level.PURPLE) OrangeFormedBlockHard.defaultState + else OrangeFormedBlock.defaultState) + } + } + } + val door = BlockPos(pos.x, pos.y - 8, pos.z) + world.createSpecialDecay(door, SpecialDecayType.DOOR) + (world.getTileEntity(door) as? DecayTile)?.data?.let { tile -> + if (gardener.level == Level.WHITE) { + tile.multiplier = 1.25 + } else if (gardener.level == Level.ORANGE) { + tile.multiplier = 0.5 + } + } +} + +fun World.createKey(key: BlockPos) { + for (x in -3..2) { + for (y in -3..2) { + for (z in -3..2) { + world.setBlockState(key.add(x, y, z), DecayBlock.defaultState) + } + } + } + world.createSpecialDecay(key, SpecialDecayType.KEY) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/util/PlayerExtensions.kt b/src/main/kotlin/co/q64/stars/util/PlayerExtensions.kt new file mode 100644 index 0000000..faa9f5f --- /dev/null +++ b/src/main/kotlin/co/q64/stars/util/PlayerExtensions.kt @@ -0,0 +1,90 @@ +package co.q64.stars.util + +import co.q64.stars.dimension.hub.HubDimension +import co.q64.stars.net.packets.SyncCapabilityPacket +import co.q64.stars.net.sendPacket +import co.q64.stars.type.* +import net.minecraft.entity.player.ServerPlayerEntity +import java.util.* +import java.util.concurrent.ConcurrentLinkedQueue + +private val toSync: Queue = ConcurrentLinkedQueue() + +var ServerPlayerEntity.seeds: Int + get() = gardener.seeds + set(value) { + gardener.seeds = value + sync() + } + +fun ServerPlayerEntity.updateSeeds() = with(gardener) { + val hub = serverWorld.dimension is HubDimension || enteringHub || openChallengeDoor || openDoor + if (fleetingStage == FleetingStage.LIGHT || hub) { + val types = if (hub) hubFormingTypes else fleetingFormingTypes + while (nextSeeds.size < seedVisibility && seeds > 0) { + var offering: FormingBlockType = PinkFormingBlockType + if (hub || seedsSincePink < 5 + (0..1).random()) { + for (i in 0..50) { + offering = types.random() + if (offering != lastSeed) break + } + } + if (!hub && level == Level.CYAN) { + if ((0..3).random() == 0) { + offering = CyanFormingBlockType + } + } + if (!hub && fleetingStage == FleetingStage.LIGHT) { + if (level == Level.CYAN) { + when (totalSeeds) { + 0 -> offering = CyanFormingBlockType + 1 -> offering = PinkFormingBlockType + 2 -> { + offering = YellowFormingBlockType + seedsSincePink = 0 + } + } + } else { + when (totalSeeds) { + 0 -> offering = PinkFormingBlockType + 1 -> offering = YellowFormingBlockType + 2 -> offering = GreenFormingBlockType + } + } + } + seedsSincePink = if (offering == PinkFormingBlockType) 0 else seedsSincePink + 1 + lastSeed = offering + nextSeeds.add(offering) + totalSeeds++ + seeds-- + } + } + sync() +} + +fun ServerPlayerEntity.useSeed(callback: () -> Unit) { + if (seeds > 0) { + seeds-- + callback() + } +} + +fun ServerPlayerEntity.addSeed(sound: Boolean = false) { + seeds++ + updateSeeds() + if (sound) { + + } +} + +fun ServerPlayerEntity.sync() { + if (this in toSync) return + toSync.add(this) +} + +fun processCapabilitySync() { + while (true) { + val player = toSync.poll() ?: break + player.sendPacket(SyncCapabilityPacket(player.gardener)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/util/Sterilization.kt b/src/main/kotlin/co/q64/stars/util/Sterilization.kt new file mode 100644 index 0000000..f8e2475 --- /dev/null +++ b/src/main/kotlin/co/q64/stars/util/Sterilization.kt @@ -0,0 +1,39 @@ +package co.q64.stars.util + +import kotlinx.serialization.* +import kotlinx.serialization.cbor.Cbor +import kotlinx.serialization.internal.StringDescriptor +import net.minecraft.nbt.CompoundNBT +import net.minecraft.util.ResourceLocation +import net.minecraft.util.SoundEvent +import net.minecraft.util.math.BlockPos + +val cbor = Cbor() + +@Serializer(ResourceLocation::class) +object ResourceLocationSerializer : KSerializer { + override val descriptor: SerialDescriptor = StringDescriptor.withName("ResourceLocation") + override fun serialize(encoder: Encoder, obj: ResourceLocation) = encoder.encodeString(obj.toString()) + override fun deserialize(decoder: Decoder) = ResourceLocation(decoder.decodeString()) +} + +@Serializer(BlockPos::class) +object BlockPosSerializer : KSerializer { + override val descriptor: SerialDescriptor = StringDescriptor.withName("BlockPos") + override fun serialize(encoder: Encoder, obj: BlockPos) = encoder.encodeLong(obj.toLong()) + override fun deserialize(decoder: Decoder): BlockPos = BlockPos.fromLong(decoder.decodeLong()) +} + +@Serializer(SoundEvent::class) +object SoundEventSerializer : KSerializer { + override val descriptor: SerialDescriptor = StringDescriptor.withName("SoundEvent") + override fun serialize(encoder: Encoder, obj: SoundEvent) = encoder.encodeString(obj.name.toString()) + override fun deserialize(decoder: Decoder): SoundEvent = SoundEvent(ResourceLocation(decoder.decodeString())) +} + +fun CompoundNBT.load(serializer: KSerializer) = + cbor.load(serializer, getByteArray("data")) + +fun KSerializer.toNBT(data: T, tag: CompoundNBT = CompoundNBT()): CompoundNBT = tag.apply { + putByteArray("data", cbor.dump(this@toNBT, data)) +} \ No newline at end of file diff --git a/src/main/kotlin/co/q64/stars/util/Structures.kt b/src/main/kotlin/co/q64/stars/util/Structures.kt index 857799e..7199528 100644 --- a/src/main/kotlin/co/q64/stars/util/Structures.kt +++ b/src/main/kotlin/co/q64/stars/util/Structures.kt @@ -1,5 +1,27 @@ package co.q64.stars.util +import co.q64.stars.block.* +import co.q64.stars.id +import co.q64.stars.type.Level +import net.minecraft.block.BlockState +import net.minecraft.block.Blocks +import net.minecraft.nbt.CompressedStreamTools +import net.minecraft.profiler.IProfiler +import net.minecraft.resources.IFutureReloadListener +import net.minecraft.resources.IFutureReloadListener.IStage +import net.minecraft.resources.IResourceManager +import net.minecraft.util.math.BlockPos +import java.io.IOException +import java.util.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.function.Consumer +import java.util.function.Supplier +import kotlin.experimental.and + + +private var structures = mapOf() + enum class StructureType(val id: String) { HUB_WHITE("hub_white.dat"), HUB_GREEN("hub_green.dat"), @@ -22,4 +44,158 @@ enum class StructureType(val id: String) { CHALLENGE_RED("challenge_red.dat"), CHALLENGE_PINK("challenge_pink.dat"), CHALLENGE_CYAN("challenge_cyan.dat"); -} \ No newline at end of file + + val structure: Structure + get() = structures[this] ?: error("Invalid structure access") +} + +object StructureLoader : IFutureReloadListener { + override fun reload(stage: IStage, resourceManager: IResourceManager, backgroundProfiler: IProfiler?, gameProfiler: IProfiler?, backgroundExecutor: Executor, gameExecutor: Executor): CompletableFuture { + val future: CompletableFuture> = + CompletableFuture.supplyAsync(Supplier { + this.prepare(resourceManager, backgroundProfiler) + }, backgroundExecutor) + stage.javaClass // TODO ?? + return future.thenCompose { stage.markCompleteAwaitingOthers(it) } + .thenAcceptAsync(Consumer { map: Map -> + apply(map, resourceManager, gameProfiler) + }, gameExecutor) + } + + private fun prepare(resourceManager: IResourceManager, profiler: IProfiler?): Map { + val result: MutableMap = EnumMap(StructureType::class.java) + for (type in StructureType.values()) { + try { + resourceManager.getResource("world/${type.id}".id).use { resource -> + val tag = CompressedStreamTools.readCompressed(resource.inputStream) + val width = tag.getShort("Width").toInt() + val height = tag.getShort("Height").toInt() + val length = tag.getShort("Length").toInt() + val blocks = tag.getByteArray("Blocks") + val data = tag.getByteArray("Data") + result.put(type, Structure(blocks, data, width, length, height)) + } + } catch (e: IOException) { + e.printStackTrace() + } + } + return result + } + + fun apply(new: Map, resourceManager: IResourceManager, profiler: IProfiler?) { + structures = new + } +} + +data class Structure( + private val blocks: ByteArray, + private val data: ByteArray, + val width: Int, + val length: Int, + val height: Int, + val challengeStart: BlockPos? = null +) { + private fun index(pos: BlockPos): Int { + return (pos.y * length + pos.z) * width + pos.x + } + + private fun getBlock(pos: BlockPos): BlockState { + return ids.getOrDefault(index( + (blocks[index(pos)] and 0xff.toByte()).toInt(), + (data[index(pos)]).toInt()), + Blocks.BEDROCK.defaultState) + } + + fun forEachBlock(action: (BlockPos, BlockState) -> Unit, offset: BlockPos = BlockPos.ZERO) { + for (x in 0 until width) { + for (z in 0 until length) { + for (y in 0 until height) { + val pos = BlockPos(x, y, z) + action(pos.add(offset), getBlock(pos)) + } + } + } + } +} + +private fun index(block: Int, color: Int): Int { + return (block shl 4) + color +} + +private enum class Block(val id: Int) { + AIR(0), + STONE(1), + DIRT(3), + COBBLESTONE(4), + BEDROCK(7), + WOOL(35), + BARRIER(166), + LAPIS(22), + SPONGE(19), + STAINED_GLASS(95), + STAINED_CLAY(159); + + fun key(color: Color = Color.WHITE): Int = index(id, color.id) +} + +private enum class Color(val id: Int) { + WHITE(0), + ORANGE(1), + MAGENTA(2), + LIGHT_BLUE(3), + YELLOW(4), + LIME(5), + PINK(6), + GRAY(7), + LIGHT_GRAY(8), + CYAN(9), + PURPLE(10), + BLUE(11), + BROWN(12), + GREEN(13), + RED(14), + BLACK(15); +} + +val ids = mapOf( + Block.STAINED_CLAY.key(Color.PINK) to PinkFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.RED) to RedFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.MAGENTA) to RedPrimedBlock.defaultState, + Block.STAINED_CLAY.key(Color.BLUE) to BlueFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.ORANGE) to OrangeFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.PURPLE) to PurpleFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.BROWN) to BrownFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.GREEN) to GreenFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.YELLOW) to YellowFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.CYAN) to CyanFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.GRAY) to GreyFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.LIGHT_BLUE) to TealFormedBlock.defaultState, + Block.STAINED_CLAY.key(Color.WHITE) to WhiteFormedBlock.defaultState, + + Block.WOOL.key(Color.RED) to RedFormedBlockHard.defaultState, + Block.WOOL.key(Color.MAGENTA) to RedPrimedBlockHard.defaultState, + Block.WOOL.key(Color.BLUE) to BlueFormedBlockHard.defaultState, + Block.WOOL.key(Color.ORANGE) to OrangeFormedBlockHard.defaultState, + Block.WOOL.key(Color.PURPLE) to PurpleFormedBlockHard.defaultState, + Block.WOOL.key(Color.BROWN) to BrownFormedBlockHard.defaultState, + Block.WOOL.key(Color.GREEN) to GreenFormedBlockHard.defaultState, + Block.WOOL.key(Color.YELLOW) to YellowFormedBlockHard.defaultState, + Block.WOOL.key(Color.CYAN) to CyanFormedBlockHard.defaultState, + + Block.STAINED_GLASS.key(Color.WHITE) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.RED) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.ORANGE) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.BLUE) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.CYAN) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.GREEN) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.PINK) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.PURPLE) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.YELLOW) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + Block.STAINED_GLASS.key(Color.LIGHT_BLUE) to GatewayBlock.defaultState.with(GatewayBlock.type, Level.RED), + + Block.BARRIER.key() to Blocks.BARRIER.defaultState, + Block.STONE.key() to DecayBlock.defaultState, + Block.DIRT.key() to DarknessBlock.defaultState, + Block.BEDROCK.key() to DecaySolidBlock.defaultState, + Block.COBBLESTONE.key() to DecayBlock.defaultState.with(BaseDecayBlock.active, true) +) \ No newline at end of file