1
0
mirror of https://github.com/chylex/Hardcore-Ender-Expansion-2.git synced 2025-09-15 14:32:09 +02:00

4 Commits

145 changed files with 1555 additions and 2533 deletions

View File

@@ -16,7 +16,7 @@ buildscript {
ext {
forge_gradle_version = "4.1.+"
mixin_gradle_version = "0.7-SNAPSHOT"
kotlin_version = "1.5.20"
kotlin_version = "1.7.0"
}
repositories {
@@ -83,16 +83,13 @@ allprojects {
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
kotlinOptions {
jvmTarget = "1.8"
apiVersion = "1.5"
languageVersion = "1.5"
useIR = true
apiVersion = "1.7"
languageVersion = "1.7"
freeCompilerArgs = [
"-Xno-call-assertions",
"-Xno-param-assertions",
"-Xno-receiver-assertions",
"-Xjvm-default=all",
"-Xuse-experimental=kotlin.contracts.ExperimentalContracts",
"-XXLanguage:+InlineClasses"
"-XXLanguage:+InlineClasses",
]
}
}

View File

@@ -580,8 +580,6 @@ e66091a13a6e7593eb5bd971978d24a5a0e375b3 data/hee/loot_tables/blocks/whitebark.j
9bd3a9e24162d2c81047b834f8f79d6cabec86be data/hee/loot_tables/blocks/whitebark_planks.json
7d84dc443a052e349593b71d2c0a523e75396cdf data/hee/loot_tables/blocks/whitebark_slab.json
83e0b81adb3f9dd488397e8459b95f7b0ce19927 data/hee/loot_tables/blocks/whitebark_stairs.json
37f3c55266db3db8dc6d22fdbaf3d53243016b77 data/hee/tags/blocks/gloomrock_particles.json
1a70c674d979a59cea18d92f2227ab8a5ed2ccc7 data/hee/tags/blocks/void_portal_frame_crafted.json
f5996244831ab38fe1fae2f304bbd7825d6ad98b data/minecraft/tags/blocks/bamboo_plantable_on.json
479189f9b35a3c8f795539daf6a1809130242c5b data/minecraft/tags/blocks/flower_pots.json
424e2e03cf62f23f4496468a97b9f0df060df9fe data/minecraft/tags/blocks/impermeable.json

View File

@@ -1,17 +0,0 @@
{
"replace": false,
"values": [
"hee:gloomrock",
"hee:gloomrock_bricks",
"hee:gloomrock_smooth",
"hee:gloomrock_smooth_red",
"hee:gloomrock_smooth_orange",
"hee:gloomrock_smooth_yellow",
"hee:gloomrock_smooth_green",
"hee:gloomrock_smooth_cyan",
"hee:gloomrock_smooth_blue",
"hee:gloomrock_smooth_purple",
"hee:gloomrock_smooth_magenta",
"hee:gloomrock_smooth_white"
]
}

View File

@@ -1,7 +0,0 @@
{
"replace": false,
"values": [
"hee:void_portal_frame_crafted",
"hee:void_portal_storage_crafted"
]
}

View File

@@ -37,7 +37,7 @@ import net.minecraftforge.common.data.ExistingFileHelper
class BlockModels(generator: DataGenerator, modid: String, existingFileHelper: ExistingFileHelper) : BlockModelProvider(generator, modid, existingFileHelper) {
override fun registerModels() {
for (block in ModBlocks.ALL) {
(block as? IHeeBlock)?.let { registerModel(block, it.model.generate(block).blockModel) { builder -> builder } }
(block as? IHeeBlock)?.model?.let { registerModel(block, it.blockModel) { builder -> builder } }
}
}

View File

@@ -32,7 +32,7 @@ import net.minecraftforge.common.data.ExistingFileHelper
class BlockStates(generator: DataGenerator, modid: String, existingFileHelper: ExistingFileHelper) : BlockStateProvider(generator, modid, existingFileHelper) {
override fun registerStatesAndModels() {
for (block in ModBlocks.ALL) {
(block as? IHeeBlock)?.let { registerState(block, it.model.generate(block).blockState) }
(block as? IHeeBlock)?.model?.let { registerState(block, it.blockState) }
}
}

View File

@@ -39,13 +39,15 @@ import net.minecraftforge.common.data.ExistingFileHelper
class ItemModels(generator: DataGenerator, modid: String, existingFileHelper: ExistingFileHelper) : ItemModelProvider(generator, modid, existingFileHelper) {
override fun registerModels() {
for (item in ModItems.ALL) {
(item as? IHeeItem)?.let { registerModel(item, it.model) }
(item as? IHeeItem)?.model?.let {
registerModel(item, it)
}
}
for (block in ModBlocks.ALL) {
(block as? IHeeBlock)
?.let { it.model.generate(block).itemModel }
?.let { registerModel(if (it.asItem) block.asItem() else block, it.model) }
(block as? IHeeBlock)?.model?.itemModel?.let {
registerModel(if (it.asItem) block.asItem() else block, it.model)
}
}
}

View File

@@ -6,6 +6,8 @@ import chylex.hee.client.DebugMenu
import chylex.hee.client.GameModeToggle
import chylex.hee.client.TerritoryVoidDebug
import chylex.hee.game.block.BlockScaffoldingDebug
import chylex.hee.game.block.HeeBlock
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.client.CommandClientDebugToggles
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.command.server.CommandServerInstability
@@ -43,8 +45,9 @@ internal object Debug : IDebugModule {
CommandServerTestWorld
)
override val scaffoldingBlockBehavior
get() = BlockScaffoldingDebug
override fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock {
return BlockScaffoldingDebug(builder)
}
@SubscribeEvent
fun onClientSetup(@Suppress("UNUSED_PARAMETER") e: FMLClientSetupEvent) {

View File

@@ -2,7 +2,7 @@ package chylex.hee.game.block
import chylex.hee.debug.PowerShell
import chylex.hee.game.Environment
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.world.generation.structure.file.StructureFile
import chylex.hee.game.world.generation.util.WorldToStructureWorldAdapter
@@ -27,13 +27,14 @@ import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand
import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TextFormatting
import net.minecraft.world.World
import java.nio.file.Files
object BlockScaffoldingDebug : IPlayerUseBlockComponent {
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType {
class BlockScaffoldingDebug(builder: BlockBuilder) : BlockScaffolding(builder) {
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (world.isRemote && player.isSneaking && !player.abilities.isFlying) {
val palette = CommandClientScaffolding.currentPalette
@@ -53,7 +54,7 @@ object BlockScaffoldingDebug : IPlayerUseBlockComponent {
val box = BoundingBox(minPos, maxPos)
val serverWorld = Environment.getDimension(world.dimensionKey)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, state.block)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, this)
val structureFile = Files.createTempDirectory("HardcoreEnderExpansion_Structure_").resolve(CommandClientScaffolding.currentFile).toFile()
CompressedStreamTools.write(structureTag, structureFile)

View File

@@ -5,7 +5,7 @@ import chylex.hee.game.block.properties.BlockDrop
import net.minecraft.block.Block
import net.minecraft.loot.LootTables
open class HeeBlock(builder: BlockBuilder) : Block(builder.p), IHeeBlock { // TODO abstract
open class HeeBlock(builder: BlockBuilder) : Block(builder.p), IHeeBlock {
override val drop
get() = if (lootTable == LootTables.EMPTY) BlockDrop.Nothing else BlockDrop.Self
}

View File

@@ -1,5 +0,0 @@
package chylex.hee.game.block
import net.minecraft.block.Block
abstract class HeeBlock2(properties: Properties) : Block(properties), IHeeBlock

View File

@@ -1,229 +0,0 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockComponents
import chylex.hee.game.world.util.getBlock
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.forge.asBool
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.BlockItemUseContext
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootContext
import net.minecraft.state.StateContainer.Builder
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.Direction
import net.minecraft.util.Hand
import net.minecraft.util.Mirror
import net.minecraft.util.Rotation
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.RayTraceResult
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.text.ITextComponent
import net.minecraft.world.Explosion
import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
import net.minecraft.world.server.ServerWorld
import java.util.Random
abstract class HeeBlockWithComponents(properties: Properties, components: HeeBlockComponents) : HeeBlock2(properties) {
private companion object {
private val RAND = Random()
}
private val states = components.states.build()
private val name = components.name
private val tooltip = components.tooltip
private val shape = components.shape
private val renderType = components.renderType
private val ambientOcclusionValue = components.ambientOcclusionValue
private val clientEffects = components.clientEffects
private val drops = components.drops
private val harvestability = components.harvestability
private val experience = components.experience
private val flammability = components.flammability
private val entity = components.entity
private val placement = components.placement
private val onAdded = components.onAdded
private val onNeighborChanged = components.onNeighborChanged
private val setStateFromNeighbor = components.setStateFromNeighbor
private val scheduledTick = components.scheduledTick
private val randomTick = components.randomTick
private val playerUse = components.playerUse
private val onExploded = components.onExploded
private val onCreatureSpawning = components.onCreatureSpawning
private val collideWithEntity = components.collideWithEntity
private var isAir = components.isAir
init {
defaultState = states.applyDefaults(stateContainer.baseState)
}
abstract override fun fillStateContainer(builder: Builder<Block, BlockState>)
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
return states.getRotatedState(state, rotation)
}
override fun mirror(state: BlockState, mirror: Mirror): BlockState {
return states.getMirroredState(state, mirror)
}
override fun getTranslationKey(): String {
return name?.translationKey ?: super.getTranslationKey()
}
@Sided(Side.CLIENT)
override fun addInformation(stack: ItemStack, world: IBlockReader?, lines: MutableList<ITextComponent>, flags: ITooltipFlag) {
tooltip?.add(lines, stack, flags.isAdvanced, world)
}
@Suppress("DEPRECATION")
override fun getShape(state: BlockState, worldIn: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
return shape?.getShape(state) ?: super.getShape(state, worldIn, pos, context)
}
@Suppress("DEPRECATION")
override fun getCollisionShape(state: BlockState, worldIn: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
return shape?.getCollisionShape(state) ?: super.getCollisionShape(state, worldIn, pos, context)
}
override fun getRaytraceShape(state: BlockState, worldIn: IBlockReader, pos: BlockPos): VoxelShape {
return super.getRaytraceShape(state, worldIn, pos)
}
@Suppress("DEPRECATION")
override fun getRenderType(state: BlockState): BlockRenderType {
return renderType ?: super.getRenderType(state)
}
@Sided(Side.CLIENT)
@Suppress("DEPRECATION")
override fun getAmbientOcclusionLightValue(state: BlockState, worldIn: IBlockReader, pos: BlockPos): Float {
return ambientOcclusionValue ?: super.getAmbientOcclusionLightValue(state, worldIn, pos)
}
@Sided(Side.CLIENT)
override fun animateTick(state: BlockState, world: World, pos: BlockPos, rand: Random) {
clientEffects?.randomTick(state, world, pos, rand)
}
@Suppress("DEPRECATION")
override fun getDrops(state: BlockState, context: LootContext.Builder): MutableList<ItemStack> {
return drops?.getDrops(state, context) ?: super.getDrops(state, context)
}
override fun getPickBlock(state: BlockState, target: RayTraceResult, world: IBlockReader, pos: BlockPos, player: PlayerEntity): ItemStack {
return drops?.getPickBlock(state, world, pos) ?: super.getPickBlock(state, target, world, pos, player)
}
override fun canHarvestBlock(state: BlockState, world: IBlockReader, pos: BlockPos, player: PlayerEntity): Boolean {
return harvestability?.canHarvest(player)?.asBool ?: super.canHarvestBlock(state, world, pos, player)
}
override fun getExpDrop(state: BlockState, world: IWorldReader, pos: BlockPos, fortune: Int, silktouch: Int): Int {
return experience?.getExperience((world as? World)?.rand ?: RAND) ?: 0
}
override fun getFlammability(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return flammability?.takeIfFlammable(state)?.flammability ?: 0
}
override fun getFireSpreadSpeed(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return flammability?.takeIfFlammable(state)?.fireSpread ?: 0
}
override fun hasTileEntity(state: BlockState): Boolean {
return entity != null
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity? {
return entity?.create()
}
@Suppress("DEPRECATION")
override fun isValidPosition(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return placement?.isPositionValid(state, world, pos) ?: super.isValidPosition(state, world, pos)
}
override fun getStateForPlacement(context: BlockItemUseContext): BlockState? {
return placement?.getPlacedState(defaultState, context.world, context.pos, context) ?: super.getStateForPlacement(context)
}
override fun onBlockPlacedBy(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
placement?.onPlacedBy(state, world, pos, placer, stack)
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
onAdded?.onAdded(state, world, pos)
scheduledTick?.onAdded(state, world, pos, world.rand)
}
@Suppress("DEPRECATION")
override fun neighborChanged(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, isMoving: Boolean) {
super.neighborChanged(state, world, pos, neighborBlock, neighborPos, isMoving)
onNeighborChanged?.onNeighborChanged(state, world, pos, neighborBlock, neighborPos.getBlock(world), neighborPos)
}
@Suppress("DEPRECATION")
override fun updatePostPlacement(state: BlockState, neighborFacing: Direction, neighborState: BlockState, world: IWorld, currentPos: BlockPos, neighborPos: BlockPos): BlockState {
return setStateFromNeighbor?.getNewState(state, world, currentPos, neighborFacing, neighborPos) ?: super.updatePostPlacement(state, neighborFacing, neighborState, world, currentPos, neighborPos)
}
override fun tick(state: BlockState, world: ServerWorld, pos: BlockPos, rand: Random) {
scheduledTick?.onTick(state, world, pos, rand)
}
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, rand: Random) {
randomTick?.onTick(state, world, pos, rand)
}
@Suppress("DEPRECATION")
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
return playerUse?.use(state, world, pos, player, hand) ?: super.onBlockActivated(state, world, pos, player, hand, hit)
}
override fun canDropFromExplosion(state: BlockState, world: IBlockReader, pos: BlockPos, explosion: Explosion): Boolean {
return onExploded?.canDrop(explosion) ?: super.canDropFromExplosion(state, world, pos, explosion)
}
override fun onBlockExploded(state: BlockState, world: World, pos: BlockPos, explosion: Explosion) {
onExploded?.onExploded(state, world, pos, explosion)
super.onBlockExploded(state, world, pos, explosion)
}
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, type: PlacementType?, entityType: EntityType<*>?): Boolean {
return onCreatureSpawning?.canSpawn(world, pos, type, entityType)?.asBool ?: super.canCreatureSpawn(state, world, pos, type, entityType)
}
override fun onEntityCollision(state: BlockState, world: World, pos: BlockPos, entity: Entity) {
collideWithEntity?.collide(state, world, pos, entity)
}
override fun isAir(state: BlockState, world: IBlockReader, pos: BlockPos): Boolean {
return isAir ?: super.isAir(state, world, pos)
}
override fun propagatesSkylightDown(state: BlockState, world: IBlockReader, pos: BlockPos): Boolean {
return isAir == true || super.propagatesSkylightDown(state, world, pos)
}
}

View File

@@ -1,13 +1,12 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.AbstractHeeBlockBuilder
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer
import chylex.hee.game.block.properties.BlockRenderLayer.SOLID
import chylex.hee.game.block.properties.BlockTint
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import chylex.hee.game.block.properties.IBlockStateModel
import net.minecraft.block.Block
import net.minecraft.tags.ITag.INamedTag
@@ -18,7 +17,7 @@ interface IHeeBlock {
val localizationExtra: Map<String, String>
get() = emptyMap()
val model: IBlockStateModelSupplier
val model: IBlockStateModel
get() = BlockModel.Cube
val renderLayer: BlockRenderLayer
@@ -32,14 +31,4 @@ interface IHeeBlock {
val tags: List<INamedTag<Block>>
get() = emptyList()
class FromBuilder(builder: AbstractHeeBlockBuilder<*>) : IHeeBlock {
override val localization = builder.localization ?: super.localization
override val localizationExtra = builder.localizationExtra.toMap()
override val model = builder.model ?: super.model
override val renderLayer = builder.renderLayer ?: super.renderLayer
override val tint = builder.tint
override val drop = builder.drop ?: super.drop
override val tags = builder.tags.toList()
}
}

View File

@@ -1,149 +0,0 @@
package chylex.hee.game.block.builder
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.IHeeBlock
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockRenderLayer
import chylex.hee.game.block.properties.BlockTint
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import net.minecraft.block.AbstractBlock.IPositionPredicate
import net.minecraft.block.AbstractBlock.Properties
import net.minecraft.block.Block
import net.minecraft.block.SoundType
import net.minecraft.block.material.Material
import net.minecraft.block.material.MaterialColor
import net.minecraft.tags.ITag.INamedTag
abstract class AbstractHeeBlockBuilder<T : Block> {
private companion object {
private val DEFAULT_MATERIAL = Material.Builder(MaterialColor.AIR).build()
private fun always(value: Boolean): IPositionPredicate {
return IPositionPredicate { _, _, _ -> value }
}
}
var localization: LocalizationStrategy? = null
val localizationExtra = mutableMapOf<String, String>()
var model: IBlockStateModelSupplier? = null
var renderLayer: BlockRenderLayer? = null
var material: Material? = null
var color: MaterialColor? = null
var sound: SoundType? = null
var tint: BlockTint? = null
var light: Int? = null
var isSolid: Boolean? = null
var isOpaque: Boolean? = null
var suffocates: Boolean? = null
var blocksVision: Boolean? = null
var drop: BlockDrop? = null
var tool: BlockHarvestTool? = null
var hardness: BlockHardness? = null
private val lazyComponents = lazy(::HeeBlockComponents)
val components
get() = lazyComponents.value
val tags = mutableListOf<INamedTag<Block>>()
val interfaces = HeeBlockInterfaces()
fun includeFrom(source: AbstractHeeBlockBuilder<*>) {
source.localization?.let { this.localization = it }
this.localizationExtra.putAll(source.localizationExtra)
source.model?.let { this.model = it }
source.renderLayer?.let { this.renderLayer = it }
source.material?.let { this.material = it }
source.color?.let { this.color = it }
source.sound?.let { this.sound = it }
source.tint?.let { this.tint = it }
source.light?.let { this.light = it }
source.isSolid?.let { this.isSolid = it }
source.isOpaque?.let { this.isOpaque = it }
source.suffocates?.let { this.suffocates = it }
source.blocksVision?.let { this.blocksVision = it }
source.drop?.let { this.drop = it }
source.tool?.let { this.tool = it }
source.hardness?.let { this.hardness = it }
if (source.lazyComponents.isInitialized()) {
this.components.includeFrom(source.components)
}
this.tags.addAll(source.tags)
this.interfaces.includeFrom(source.interfaces)
}
protected val heeDelegate
get() = object : IHeeBlock {
override val localization = this@AbstractHeeBlockBuilder.localization ?: super.localization
override val localizationExtra = this@AbstractHeeBlockBuilder.localizationExtra.toMap()
override val model = this@AbstractHeeBlockBuilder.model ?: super.model
override val renderLayer = this@AbstractHeeBlockBuilder.renderLayer ?: super.renderLayer
override val tint = this@AbstractHeeBlockBuilder.tint
override val drop = this@AbstractHeeBlockBuilder.drop ?: super.drop
override val tags = this@AbstractHeeBlockBuilder.tags.toList()
}
private fun buildProperties(setup: ((Properties) -> Properties)?): Properties {
val material = material ?: DEFAULT_MATERIAL
val color = color ?: material.color
val tool = tool ?: BlockHarvestTool.NONE
var properties = Properties.create(material, color)
if (setup != null) {
properties = setup(properties)
}
properties = tool.applyTo(properties)
properties = properties.apply(sound, Properties::sound)
properties = properties.apply(light) { level -> setLightLevel { level } }
properties = properties.apply(isOpaque) { setOpaque(always(it)) }
properties = properties.apply(suffocates) { setSuffocates(always(it)) }
properties = properties.apply(blocksVision) { setBlocksVision(always(it)) }
properties = properties.apply(hardness) { it.applyTo(this) }
if (isSolid == false) {
properties = properties.notSolid()
}
if (!material.blocksMovement()) {
if (isSolid == true) {
throw UnsupportedOperationException("[AbstractHeeBlockBuilder] cannot create a block that does not block movement and is solid at the same time")
}
properties = properties.doesNotBlockMovement()
}
if (drop === BlockDrop.Nothing) {
properties = properties.noDrops()
}
if (lazyComponents.isInitialized() && components.randomTick != null) {
properties = properties.tickRandomly()
}
return properties
}
private inline fun <T> Properties.apply(value: T?, function: Properties.(T) -> Properties): Properties {
return if (value == null) this else function(value)
}
fun build(propertiesSetup: (Properties.() -> Properties)? = null): T {
val components = if (lazyComponents.isInitialized()) components else null
return buildBlock(buildProperties(propertiesSetup), components)
}
internal abstract fun buildBlock(properties: Properties, components: HeeBlockComponents?): T
}

View File

@@ -1,26 +0,0 @@
package chylex.hee.game.block.builder
import chylex.hee.game.block.HeeBlock2
import chylex.hee.game.block.HeeBlockWithComponents
import chylex.hee.game.block.IHeeBlock
import chylex.hee.game.block.interfaces.IBlockWithInterfaces
import net.minecraft.block.AbstractBlock.Properties
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.state.StateContainer.Builder
open class HeeBlockBuilder : AbstractHeeBlockBuilder<HeeBlock2>() {
override fun buildBlock(properties: Properties, components: HeeBlockComponents?): HeeBlock2 {
if (components != null) {
return object : HeeBlockWithComponents(properties, components), IHeeBlock by IHeeBlock.FromBuilder(this@HeeBlockBuilder), IBlockWithInterfaces by interfaces.delegate {
override fun fillStateContainer(builder: Builder<Block, BlockState>) {
components.states.fillContainer(builder)
}
}
}
return object : HeeBlock2(properties), IHeeBlock by IHeeBlock.FromBuilder(this), IBlockWithInterfaces by interfaces.delegate {}
}
}
inline fun HeeBlockBuilder(setup: HeeBlockBuilder.() -> Unit) = HeeBlockBuilder().apply(setup)

View File

@@ -1,86 +0,0 @@
package chylex.hee.game.block.builder
import chylex.hee.game.block.components.IBlockAddedComponent
import chylex.hee.game.block.components.IBlockClientEffectsComponent
import chylex.hee.game.block.components.IBlockCollideWithEntityComponent
import chylex.hee.game.block.components.IBlockDropsComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IBlockExperienceComponent
import chylex.hee.game.block.components.IBlockExplodedComponent
import chylex.hee.game.block.components.IBlockHarvestabilityComponent
import chylex.hee.game.block.components.IBlockNameComponent
import chylex.hee.game.block.components.IBlockNeighborChanged
import chylex.hee.game.block.components.IBlockPlacementComponent
import chylex.hee.game.block.components.IBlockRandomTickComponent
import chylex.hee.game.block.components.IBlockScheduledTickComponent
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.components.ICreatureSpawningOnBlockComponent
import chylex.hee.game.block.components.IFlammableBlockComponent
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.components.ISetBlockStateFromNeighbor
import chylex.hee.game.item.components.ITooltipComponent
import net.minecraft.block.BlockRenderType
class HeeBlockComponents {
val states = HeeBlockStates.Builder()
var name: IBlockNameComponent? = null
var tooltip: ITooltipComponent? = null
var shape: IBlockShapeComponent? = null
var renderType: BlockRenderType? = null
var ambientOcclusionValue: Float? = null
var clientEffects: IBlockClientEffectsComponent? = null
var drops: IBlockDropsComponent? = null
var harvestability: IBlockHarvestabilityComponent? = null
var experience: IBlockExperienceComponent? = null
var flammability: IFlammableBlockComponent? = null
var entity: IBlockEntityComponent? = null
var placement: IBlockPlacementComponent? = null
var onAdded: IBlockAddedComponent? = null
var onNeighborChanged: IBlockNeighborChanged? = null
var setStateFromNeighbor: ISetBlockStateFromNeighbor? = null
var scheduledTick: IBlockScheduledTickComponent? = null
var randomTick: IBlockRandomTickComponent? = null
var playerUse: IPlayerUseBlockComponent? = null
var onExploded: IBlockExplodedComponent? = null
var onCreatureSpawning: ICreatureSpawningOnBlockComponent? = null
var collideWithEntity: IBlockCollideWithEntityComponent? = null
var isAir: Boolean? = null
fun includeFrom(source: HeeBlockComponents) {
source.name?.let { this.name = it }
source.tooltip?.let { this.tooltip = it }
source.shape?.let { this.shape = it }
source.renderType?.let { this.renderType = it }
source.ambientOcclusionValue?.let { this.ambientOcclusionValue = it }
source.clientEffects?.let { this.clientEffects = it }
source.drops?.let { this.drops = it }
source.harvestability?.let { this.harvestability = it }
source.experience?.let { this.experience = it }
source.flammability?.let { this.flammability = it }
source.entity?.let { this.entity = it }
source.placement?.let { this.placement = it }
source.onAdded?.let { this.onAdded = it }
source.onNeighborChanged?.let { this.onNeighborChanged = it }
source.setStateFromNeighbor?.let { this.setStateFromNeighbor = it }
source.scheduledTick?.let { this.scheduledTick = it }
source.randomTick?.let { this.randomTick = it }
source.playerUse?.let { this.playerUse = it }
source.onExploded?.let { this.onExploded = it }
source.onCreatureSpawning?.let { this.onCreatureSpawning = it }
source.collideWithEntity?.let { this.collideWithEntity = it }
source.isAir?.let { this.isAir = it }
}
}

View File

@@ -1,23 +0,0 @@
package chylex.hee.game.block.builder
import chylex.hee.game.block.interfaces.BlockInterfaceContainer
import chylex.hee.game.block.interfaces.IBlockInterface
import chylex.hee.game.block.interfaces.NoBlockInterfaces
class HeeBlockInterfaces {
private val interfaces = mutableMapOf<Class<out IBlockInterface>, Any>()
internal val delegate
get() = if (interfaces.isEmpty())
NoBlockInterfaces
else
BlockInterfaceContainer(interfaces)
operator fun <T : IBlockInterface> set(type: Class<T>, impl: T) {
interfaces[type] = impl
}
fun includeFrom(source: HeeBlockInterfaces) {
this.interfaces.putAll(source.interfaces)
}
}

View File

@@ -1,50 +0,0 @@
package chylex.hee.game.block.builder
import chylex.hee.game.block.util.BlockStateGenerics
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.state.Property
import net.minecraft.state.StateContainer
import net.minecraft.util.Direction
import net.minecraft.util.Mirror
import net.minecraft.util.Rotation
class HeeBlockStates private constructor(private val statesWithDefaults: Map<Property<*>, Comparable<*>>, private val facingProperty: Property<Direction>?) {
fun applyDefaults(state: BlockState): BlockState {
if (statesWithDefaults.isEmpty()) {
return state
}
return statesWithDefaults.entries.fold(state) { acc, entry ->
BlockStateGenerics.withProperty(acc, entry.key, entry.value)
}
}
fun getRotatedState(state: BlockState, rotation: Rotation): BlockState {
return facingProperty?.let { state.with(it, rotation.rotate(state[it])) } ?: state
}
fun getMirroredState(state: BlockState, mirror: Mirror): BlockState {
return facingProperty?.let { state.with(it, mirror.mirror(state[it])) } ?: state
}
class Builder {
private val statesWithDefaults = mutableMapOf<Property<*>, Comparable<*>>()
var facingProperty: Property<Direction>? = null
fun <T : Comparable<T>> set(state: Property<T>, default: T) {
statesWithDefaults[state] = default
}
fun fillContainer(builder: StateContainer.Builder<Block, BlockState>) {
for (property in statesWithDefaults.keys) {
builder.add(property)
}
}
fun build(): HeeBlockStates {
return HeeBlockStates(statesWithDefaults.toMap(), facingProperty)
}
}
}

View File

@@ -1,9 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
fun interface IBlockAddedComponent {
fun onAdded(state: BlockState, world: World, pos: BlockPos)
}

View File

@@ -1,10 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.util.Random
interface IBlockClientEffectsComponent {
fun randomTick(state: BlockState, world: World, pos: BlockPos, rand: Random) {}
}

View File

@@ -1,10 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
fun interface IBlockCollideWithEntityComponent {
fun collide(state: BlockState, world: World, pos: BlockPos, entity: Entity)
}

View File

@@ -1,15 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootContext
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
interface IBlockDropsComponent {
fun getDrops(state: BlockState, context: LootContext.Builder): MutableList<ItemStack>
fun getPickBlock(state: BlockState, world: IBlockReader, pos: BlockPos): ItemStack? {
return null
}
}

View File

@@ -1,7 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.tileentity.TileEntity
fun interface IBlockEntityComponent {
fun create(): TileEntity
}

View File

@@ -1,7 +0,0 @@
package chylex.hee.game.block.components
import java.util.Random
fun interface IBlockExperienceComponent {
fun getExperience(rand: Random): Int
}

View File

@@ -1,11 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.Explosion
import net.minecraft.world.World
interface IBlockExplodedComponent {
fun canDrop(explosion: Explosion): Boolean
fun onExploded(state: BlockState, world: World, pos: BlockPos, explosion: Explosion)
}

View File

@@ -1,8 +0,0 @@
package chylex.hee.game.block.components
import chylex.hee.util.forge.EventResult
import net.minecraft.entity.player.PlayerEntity
fun interface IBlockHarvestabilityComponent {
fun canHarvest(player: PlayerEntity): EventResult
}

View File

@@ -1,19 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.Block
interface IBlockNameComponent {
val translationKey: String
companion object {
fun of(translationKey: String) = object : IBlockNameComponent {
override val translationKey
get() = translationKey
}
fun of(block: Block) = object : IBlockNameComponent {
override val translationKey
get() = block.translationKey
}
}
}

View File

@@ -1,10 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
fun interface IBlockNeighborChanged {
fun onNeighborChanged(state: BlockState, world: World, pos: BlockPos, oldNeighborBlock: Block, newNeighborBlock: Block, neighborPos: BlockPos)
}

View File

@@ -1,21 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.entity.LivingEntity
import net.minecraft.item.BlockItemUseContext
import net.minecraft.item.ItemStack
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
interface IBlockPlacementComponent {
fun isPositionValid(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return true
}
fun getPlacedState(defaultState: BlockState, world: World, pos: BlockPos, context: BlockItemUseContext): BlockState {
return defaultState
}
fun onPlacedBy(state: BlockState, world: World, pos: BlockPos, placer: LivingEntity?, stack: ItemStack) {}
}

View File

@@ -1,10 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.util.Random
fun interface IBlockRandomTickComponent {
fun onTick(state: BlockState, world: World, pos: BlockPos, rand: Random)
}

View File

@@ -1,19 +0,0 @@
package chylex.hee.game.block.components
import chylex.hee.game.block.properties.TickSchedule
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.util.Random
interface IBlockScheduledTickComponent {
/**
* Return the amount of ticks before the first [onTick] call after the block is added to the world.
*/
fun onAdded(state: BlockState, world: World, pos: BlockPos, rand: Random): TickSchedule
/**
* Return the amount of ticks before the next [onTick] call.
*/
fun onTick(state: BlockState, world: World, pos: BlockPos, rand: Random): TickSchedule
}

View File

@@ -1,30 +0,0 @@
package chylex.hee.game.block.components
import chylex.hee.game.block.util.asVoxelShape
import net.minecraft.block.BlockState
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.shapes.VoxelShape
interface IBlockShapeComponent {
fun getShape(state: BlockState): VoxelShape
fun getCollisionShape(state: BlockState): VoxelShape? {
return null
}
fun getRaytraceShape(state: BlockState): VoxelShape? {
return null
}
companion object {
fun of(shape: VoxelShape) = object : IBlockShapeComponent {
override fun getShape(state: BlockState): VoxelShape {
return shape
}
}
fun of(aabb: AxisAlignedBB): IBlockShapeComponent {
return of(aabb.asVoxelShape)
}
}
}

View File

@@ -1,11 +0,0 @@
package chylex.hee.game.block.components
import chylex.hee.util.forge.EventResult
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
import net.minecraft.entity.EntityType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
fun interface ICreatureSpawningOnBlockComponent {
fun canSpawn(world: IBlockReader, pos: BlockPos, placementType: PlacementType?, entityType: EntityType<*>?): EventResult
}

View File

@@ -1,20 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.state.properties.BlockStateProperties
interface IFlammableBlockComponent {
val flammability: Int
val fireSpread: Int
fun takeIfFlammable(state: BlockState): IFlammableBlockComponent? {
return this.takeUnless { state.hasProperty(BlockStateProperties.WATERLOGGED) && state[BlockStateProperties.WATERLOGGED] }
}
companion object {
fun of(flammability: Int, fireSpread: Int) = object : IFlammableBlockComponent {
override val flammability = flammability
override val fireSpread = fireSpread
}
}
}

View File

@@ -1,12 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.Hand
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
fun interface IPlayerUseBlockComponent {
fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType
}

View File

@@ -1,10 +0,0 @@
package chylex.hee.game.block.components
import net.minecraft.block.BlockState
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IWorld
fun interface ISetBlockStateFromNeighbor {
fun getNewState(state: BlockState, world: IWorld, pos: BlockPos, neighborFacing: Direction, neighborPos: BlockPos): BlockState
}

View File

@@ -1,9 +0,0 @@
package chylex.hee.game.block.interfaces
internal class BlockInterfaceContainer(interfaces: Map<Class<out IBlockInterface>, Any>) : IBlockWithInterfaces {
private val interfaces = interfaces.toMap()
override fun getInterface(type: Class<out IBlockInterface>): Any? {
return interfaces[type]
}
}

View File

@@ -1,6 +0,0 @@
package chylex.hee.game.block.interfaces
/**
* Marks interfaces that can be attached to blocks.
*/
interface IBlockInterface

View File

@@ -1,15 +0,0 @@
package chylex.hee.game.block.interfaces
import net.minecraft.block.Block
interface IBlockWithInterfaces {
fun getInterface(type: Class<out IBlockInterface>): Any?
}
inline fun <reified T : IBlockInterface> IBlockWithInterfaces.getHeeInterface(): T? {
return this.getInterface(T::class.java) as? T
}
inline fun <reified T : IBlockInterface> Block.getHeeInterface(): T? {
return (this as? IBlockWithInterfaces)?.getHeeInterface()
}

View File

@@ -1,7 +0,0 @@
package chylex.hee.game.block.interfaces
internal object NoBlockInterfaces : IBlockWithInterfaces {
override fun getInterface(type: Class<out IBlockInterface>): Any? {
return null
}
}

View File

@@ -1,10 +1,9 @@
package chylex.hee.game.block.logic
import chylex.hee.game.block.interfaces.IBlockInterface
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
interface IBlockDynamicHardness : IBlockInterface {
interface IBlockDynamicHardness {
fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float
}

View File

@@ -1,11 +0,0 @@
package chylex.hee.game.block.properties
import net.minecraft.block.AbstractBlock.Properties
data class BlockHardness(val hardness: Float, val resistance: Float) {
constructor(hardnessAndResistance: Float) : this(hardnessAndResistance, hardnessAndResistance)
fun applyTo(properties: Properties): Properties {
return properties.hardnessAndResistance(hardness, resistance)
}
}

View File

@@ -1,21 +0,0 @@
package chylex.hee.game.block.properties
import net.minecraft.block.AbstractBlock.Properties
import net.minecraftforge.common.ToolType
@Suppress("DataClassPrivateConstructor")
data class BlockHarvestTool private constructor(val tier: Int, val toolType: ToolType?, val requiresTool: Boolean) {
fun applyTo(properties: Properties): Properties {
return properties
.harvestLevel(tier)
.let { if (toolType != null) it.harvestTool(toolType) else it }
.let { if (requiresTool) it.setRequiresTool() else it }
}
companion object {
val NONE = BlockHarvestTool(-1, null, requiresTool = false)
fun required(tier: Int, toolType: ToolType) = BlockHarvestTool(tier, toolType, requiresTool = true)
fun optional(tier: Int, toolType: ToolType) = BlockHarvestTool(tier, toolType, requiresTool = false)
}
}

View File

@@ -1,13 +1,7 @@
package chylex.hee.game.block.properties
import net.minecraft.block.Block
interface IBlockStateModel : IBlockStateModelSupplier {
interface IBlockStateModel {
val blockState: BlockStatePreset
val blockModel: BlockModel
val itemModel: BlockItemModel?
override fun generate(block: Block): IBlockStateModel {
return this
}
}

View File

@@ -1,7 +0,0 @@
package chylex.hee.game.block.properties
import net.minecraft.block.Block
fun interface IBlockStateModelSupplier {
fun generate(block: Block): IBlockStateModel
}

View File

@@ -1,19 +0,0 @@
package chylex.hee.game.block.properties
import net.minecraft.block.Block
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
sealed class TickSchedule {
abstract fun schedule(world: World, pos: BlockPos, block: Block)
object Never : TickSchedule() {
override fun schedule(world: World, pos: BlockPos, block: Block) {}
}
class InTicks(private val ticks: Int) : TickSchedule() {
override fun schedule(world: World, pos: BlockPos, block: Block) {
world.pendingBlockTicks.scheduleTick(pos, block, ticks)
}
}
}

View File

@@ -2,8 +2,8 @@ package chylex.hee.game.item.components
import net.minecraft.item.ItemStack
import net.minecraft.util.text.ITextComponent
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
fun interface ITooltipComponent {
fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?)
fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?)
}

View File

@@ -2,10 +2,10 @@ package chylex.hee.game.item.components
import net.minecraft.item.ItemStack
import net.minecraft.util.text.ITextComponent
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
class StaticTooltipComponent(private vararg val lines: ITextComponent) : ITooltipComponent {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?) {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?) {
lines.addAll(this.lines)
}
}

View File

@@ -1,8 +1,6 @@
package chylex.hee.game.world.generation.noise
import chylex.hee.util.math.FloatRange
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.remap
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.roundToInt
@@ -28,12 +26,12 @@ class NoiseValue(var value: Double) {
it.coerceIn(minimum, maximum)
}
fun remap(oldRange: FloatRange, newRange: FloatRange) = then {
remapRange(it, oldRange, newRange)
fun remap(fromMin: Double, fromMax: Double, toMin: Double, toMax: Double) = then {
it.remap(fromMin, fromMax, toMin, toMax)
}
fun remap(newRange: FloatRange) = then {
remapRange(it, range(0F, 1F), newRange)
fun remap(toMin: Double, toMax: Double) = then {
it.remap(fromMin = 0.0, fromMax = 1.0, toMin, toMax)
}
inline fun ifNonZero(block: NoiseValue.() -> Unit) {

View File

@@ -1,11 +1,13 @@
package chylex.hee.system
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.HeeBlock
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.IClientCommand
import chylex.hee.game.command.ICommand
interface IDebugModule {
val clientCommands: List<IClientCommand>
val serverCommands: List<ICommand>
val scaffoldingBlockBehavior: IPlayerUseBlockComponent?
fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock
}

View File

@@ -18,54 +18,65 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.vector.Vector3d
import org.apache.logging.log4j.Logger
inline fun <T : PacketBuffer> T.use(block: T.() -> Unit) {
block()
}
// BlockPos
inline fun PacketBuffer.writePos(pos: BlockPos) {
inline fun ByteBuf.writePos(pos: BlockPos) {
this.writeLong(pos.toLong())
}
inline fun PacketBuffer.readPos(): BlockPos {
inline fun ByteBuf.readPos(): BlockPos {
return Pos(this.readLong())
}
// Vec3d (Full)
fun PacketBuffer.writeVec(vec: Vector3d) {
fun ByteBuf.writeVec(vec: Vector3d) {
this.writeDouble(vec.x)
this.writeDouble(vec.y)
this.writeDouble(vec.z)
}
fun PacketBuffer.readVec(): Vector3d {
return Vec(readDouble(), readDouble(), readDouble())
fun ByteBuf.readVec(): Vector3d {
return Vec(this.readDouble(), this.readDouble(), this.readDouble())
}
// Vec3d (Float)
fun PacketBuffer.writeFloatVec(vec: Vector3d) {
fun ByteBuf.writeFloatVec(vec: Vector3d) {
this.writeFloat(vec.x.toFloat())
this.writeFloat(vec.y.toFloat())
this.writeFloat(vec.z.toFloat())
}
fun PacketBuffer.readFloatVec(): Vector3d {
return Vec(readFloat().toDouble(), readFloat().toDouble(), readFloat().toDouble())
fun ByteBuf.readFloatVec(): Vector3d {
return Vec(this.readFloat().toDouble(), this.readFloat().toDouble(), this.readFloat().toDouble())
}
// Vec3d (Compact)
fun PacketBuffer.writeCompactVec(vec: Vector3d) {
fun ByteBuf.writeCompactVec(vec: Vector3d) {
this.writeInt((vec.x * 8.0).floorToInt())
this.writeInt((vec.y * 8.0).floorToInt())
this.writeInt((vec.z * 8.0).floorToInt())
}
fun PacketBuffer.readCompactVec(): Vector3d {
return Vec(readInt() * 0.125, readInt() * 0.125, readInt() * 0.125)
fun ByteBuf.readCompactVec(): Vector3d {
return Vec(this.readInt() * 0.125, this.readInt() * 0.125, this.readInt() * 0.125)
}
// Enum
fun <T : Enum<T>> PacketBuffer.writeEnum(value: T?) {
this.writeVarInt(value?.ordinal ?: -1)
}
inline fun <reified T : Enum<T>> PacketBuffer.readEnum(): T? {
val ordinal = this.readVarInt()
return if (ordinal >= 0)
T::class.java.enumConstants.getOrNull(ordinal)
else
null
}
// NBT

View File

@@ -1,16 +0,0 @@
package chylex.hee.util.forge
import net.minecraftforge.eventbus.api.Event.Result.ALLOW
import net.minecraftforge.eventbus.api.Event.Result.DEFAULT
import net.minecraftforge.eventbus.api.Event.Result.DENY
val EventResult.asBool: Boolean?
get() = when (this) {
ALLOW -> true
DENY -> false
DEFAULT -> null
}
fun EventResult(allow: Boolean): EventResult {
return if (allow) ALLOW else DENY
}

View File

@@ -46,17 +46,17 @@ fun lerp(from: Double, to: Double, progress: Double): Double {
}
/**
* Maps a range of values in [from] range to values in [to] range using linear interpolation.
* Remaps a value from the range [[fromMin], [fromMax]] to a value in the range [[toMin], [toMax]] using linear interpolation.
*/
fun remapRange(value: Float, from: FloatRange, to: FloatRange): Float {
val remappedBetween0And1 = (value - from.start) / (from.end - from.start)
return to.start + remappedBetween0And1 * (to.end - to.start)
fun Float.remap(fromMin: Float, fromMax: Float, toMin: Float, toMax: Float): Float {
val remappedBetween0And1 = (this - fromMin) / (fromMax - fromMin)
return toMin + remappedBetween0And1 * (toMax - toMin)
}
/**
* Maps a range of values in [from] range to values in [to] range using linear interpolation.
* Remaps a value from the range [[fromMin], [fromMax]] to a value in the range [[toMin], [toMax]] using linear interpolation.
*/
fun remapRange(value: Double, from: FloatRange, to: FloatRange): Double {
val remappedBetween0And1 = (value - from.start) / (from.end - from.start)
return to.start + remappedBetween0And1 * (to.end - to.start)
fun Double.remap(fromMin: Double, fromMax: Double, toMin: Double, toMax: Double): Double {
val remappedBetween0And1 = (this - fromMin) / (fromMax - fromMin)
return toMin + remappedBetween0And1 * (toMax - toMin)
}

View File

@@ -1,14 +0,0 @@
package chylex.hee.util.math
@JvmInline
value class FloatRange(private val combined: Long) {
constructor(start: Float, end: Float) : this((start.toRawBits() shlong 32) or (end.toRawBits().toLong() and 0xFFFF_FFFFL))
val start
get() = Float.fromBits((combined ushr 32).toInt())
val end
get() = Float.fromBits((combined and 0xFFFF_FFFFL).toInt())
}
fun range(start: Float, end: Float) = FloatRange(start, end)

View File

@@ -15,6 +15,7 @@ import net.minecraftforge.common.util.Constants.NBT
import org.apache.logging.log4j.Logger
import java.util.Locale
import java.util.UUID
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
typealias NBTBase = net.minecraft.nbt.INBT
@@ -54,12 +55,14 @@ inline fun TagCompound.hasKey(key: String, type: Int): Boolean {
return this.contains(key, type)
}
@OptIn(ExperimentalContracts::class)
@JvmName("isNotNullAndHasKey")
inline fun TagCompound?.hasKey(key: String): Boolean {
contract { returns(true) implies (this@hasKey != null) }
return this != null && this.hasKey(key)
}
@OptIn(ExperimentalContracts::class)
@JvmName("isNotNullAndHasKey")
inline fun TagCompound?.hasKey(key: String, type: Int): Boolean {
contract { returns(true) implies (this@hasKey != null) }

View File

@@ -1,7 +1,6 @@
package chylex.hee.util.random
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.remap
import java.util.Random
import kotlin.math.pow
@@ -30,7 +29,7 @@ abstract class RandomDouble private constructor(val min: Double, val max: Double
fun Exp(min: Double, max: Double, exp: Double) = object : RandomDouble(min, max) {
override fun invoke(rand: Random): Double {
return remapRange(rand.nextDouble().pow(exp), range(0F, 1F), range(min.toFloat(), max.toFloat()))
return rand.nextDouble().pow(exp).remap(fromMin = 0.0, fromMax = 1.0, toMin = min, toMax = max)
}
}
}

View File

@@ -1,3 +1,5 @@
rootProject.name = "HEE"
include ":util"
include ":system"
include ":debug"

View File

@@ -10,7 +10,6 @@ import chylex.hee.client.util.MC
import chylex.hee.game.Resource
import chylex.hee.game.block.BlockAbstractPortal
import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.block.interfaces.getHeeInterface
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.mechanics.energy.IClusterOracleItem
import chylex.hee.game.mechanics.energy.IEnergyQuantity
@@ -36,7 +35,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.HELMET
@SubscribeAllEvents(Side.CLIENT, modid = HEE.ID)
object OverlayRenderer { // TODO move to appropriate block builders
object OverlayRenderer {
private const val BORDER_SIZE = 4
private const val LINE_SPACING = 7
@@ -148,7 +147,7 @@ object OverlayRenderer { // TODO move to appropriate block builders
clusterLookedAt = pos.getTile(world)
e.isCanceled = true
}
else if (block.getHeeInterface<BlockAbstractPortal.IInnerPortalBlock>() != null) {
else if (block is BlockAbstractPortal) {
e.isCanceled = true
}
}

View File

@@ -25,8 +25,7 @@ import chylex.hee.util.forge.SubscribeAllEvents
import chylex.hee.util.forge.SubscribeEvent
import chylex.hee.util.math.LerpedFloat
import chylex.hee.util.math.floorToInt
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.remap
import chylex.hee.util.math.scale
import com.mojang.blaze3d.matrix.MatrixStack
import com.mojang.blaze3d.platform.GlStateManager.FogMode.EXP2
@@ -118,7 +117,7 @@ object TerritoryRenderer {
// Fog rendering
private val currentFogDensityMp
get() = 1F + (9F * remapRange(currentVoidFactor, range(-0.5F, 1F), range(0F, 1F)).coerceIn(0F, 1F).pow(1.5F))
get() = 1F + (9F * currentVoidFactor.remap(fromMin = -0.5F, fromMax = 1F, toMin = 0F, toMax = 1F).coerceIn(0F, 1F).pow(1.5F))
private val currentRenderDistanceMp
get() = MC.settings.renderDistanceChunks.let { if (it > 12) 0F else (1F - (it / 16.5F)).pow((it - 1) * 0.25F) }
@@ -148,7 +147,7 @@ object TerritoryRenderer {
get() = Void.voidFactor.get(MC.partialTicks)
val currentSkyAlpha
get() = remapRange(currentVoidFactor, range(-1F, 0.5F), range(1F, 0F)).coerceIn(0F, 1F)
get() = currentVoidFactor.remap(fromMin = -1F, fromMax = 0.5F, toMin = 1F, toMax = 0F).coerceIn(0F, 1F)
private object Void {
private val VOID_PARTICLE = ParticleSpawnerCustom(

View File

@@ -1,9 +1,9 @@
package chylex.hee.client.render.block
import chylex.hee.game.block.BlockAbstractPortal
import chylex.hee.game.block.BlockVoidPortalInner.Companion.TYPE
import chylex.hee.game.block.BlockVoidPortalInner.ITerritoryInstanceFactory
import chylex.hee.game.block.BlockVoidPortalInner.IVoidPortalController
import chylex.hee.game.block.BlockVoidPortalInner.TYPE
import chylex.hee.game.block.BlockVoidPortalInner.Type.HUB
import chylex.hee.game.block.BlockVoidPortalInner.Type.RETURN_ACTIVE
import chylex.hee.game.block.entity.TileEntityPortalInner

View File

@@ -49,13 +49,13 @@ class RenderEntityTokenHolder(manager: EntityRendererManager) : EntityRenderer<E
matrix.rotateX(55F)
matrix.rotateZ(55F)
ModelEntityTokenHolder.render(matrix, buffer.getBuffer(RenderType.getEntityTranslucent(getEntityTexture(entity) ?: textures.getValue(NORMAL))), combinedLight, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, alpha)
ModelEntityTokenHolder.render(matrix, buffer.getBuffer(RenderType.getEntityTranslucent(getEntityTexture(entity))), combinedLight, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, alpha)
matrix.pop()
matrix.pop()
}
override fun getEntityTexture(entity: EntityTokenHolder): ResourceLocation? {
return textures[entity.tokenType]
override fun getEntityTexture(entity: EntityTokenHolder): ResourceLocation {
return textures.getValue(entity.tokenType)
}
}

View File

@@ -1,51 +0,0 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import chylex.hee.game.block.properties.Materials
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.util.math.AxisAlignedBB
import net.minecraftforge.common.Tags
val BlockIndestructible
get() = HeeBlockBuilder {
drop = BlockDrop.Nothing
tool = BlockHarvestTool.NONE
hardness = BlockHardness(hardness = -1F, resistance = 3600000F)
}
val BlockEndStoneBase
get() = HeeBlockBuilder {
material = Materials.SOLID
color = MaterialColor.SAND
sound = SoundType.STONE
}
val BlockEndOre
get() = HeeBlockBuilder {
includeFrom(BlockEndStoneBase)
tags.add(Tags.Blocks.ORES)
}
val BlockPortalFrameBase
get() = HeeBlockBuilder {
model = IBlockStateModelSupplier { BlockModel.PortalFrame(it, "plain") }
material = Materials.SOLID
color = MaterialColor.SAND
sound = SoundType.STONE
components.shape = IBlockShapeComponent.of(AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.8125, 1.0))
}
val BlockPortalFrameIndestructible
get() = HeeBlockBuilder {
includeFrom(BlockPortalFrameBase)
includeFrom(BlockIndestructible)
}

View File

@@ -1,15 +1,11 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockCollideWithEntityComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.interfaces.IBlockInterface
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.entity.util.EntityPortalContact
import chylex.hee.game.block.util.asVoxelShape
import chylex.hee.game.world.util.Facing4
import chylex.hee.game.world.util.allInBox
import chylex.hee.game.world.util.allInBoxMutable
@@ -28,27 +24,25 @@ import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType.INVISIBLE
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.SoundType
import net.minecraft.block.material.Material
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.Entity
import net.minecraft.tags.BlockTags
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
class BlockAbstractPortal(impl: IInnerPortalBlock) : HeeBlockBuilder() {
abstract class BlockAbstractPortal(builder: BlockBuilder) : BlockSimpleShaped(builder, AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.75, 1.0)) {
companion object {
const val MAX_DISTANCE_FROM_FRAME = 6.0
const val MAX_SIZE = 5
private const val TRANSLATION_SPEED_LONG = 600000L
const val TRANSLATION_SPEED_LONG = 600000L
const val TRANSLATION_SPEED_INV = 1.0 / TRANSLATION_SPEED_LONG
private val SHAPE = VoxelShapes.create(0.0, 0.0, 0.0, 1.0, 0.75, 1.0)
private val COLLISION_SHAPE = VoxelShapes.create(0.0, 0.0, 0.0, 1.0, 0.025, 1.0)
private val COLLISION_AABB = AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.025, 1.0).asVoxelShape
fun findInnerArea(world: World, controllerPos: BlockPos, frameBlock: Block): Pair<BlockPos, BlockPos>? {
val mirrorRange = 1..(MAX_SIZE + 1)
@@ -100,52 +94,36 @@ class BlockAbstractPortal(impl: IInnerPortalBlock) : HeeBlockBuilder() {
}
}
init {
includeFrom(BlockIndestructible)
localization = LocalizationStrategy.DeleteWords("Inner")
model = BlockStateModel(BlockStatePreset.SimpleFrom(Blocks.END_PORTAL), BlockModel.Manual)
material = Material.PORTAL
color = MaterialColor.BLACK
sound = SoundType.STONE
light = 15
isSolid = false
tags.add(BlockTags.PORTALS)
components.shape = object : IBlockShapeComponent {
override fun getShape(state: BlockState): VoxelShape {
return SHAPE
}
override fun getCollisionShape(state: BlockState): VoxelShape? {
return COLLISION_SHAPE
}
}
components.renderType = INVISIBLE
components.entity = IBlockEntityComponent(impl::createTileEntity)
components.collideWithEntity = IBlockCollideWithEntityComponent { _, world, pos, entity ->
if (!world.isRemote && !entity.isPassenger && !entity.isBeingRidden && entity.canChangeDimension() && entity.posY <= pos.y + 0.05 && EntityPortalContact.shouldTeleport(entity)) {
impl.teleportEntity(world, pos, entity)
}
}
interfaces[IInnerPortalBlock::class.java] = impl
}
interface IInnerPortalBlock : IBlockInterface {
fun createTileEntity(): TileEntity
fun teleportEntity(world: World, pos: BlockPos, entity: Entity)
}
interface IPortalController {
val clientAnimationProgress: LerpedFloat
val clientPortalOffset: LerpedFloat
}
final override val localization
get() = LocalizationStrategy.DeleteWords("Inner")
final override val model
get() = BlockStateModel(BlockStatePreset.SimpleFrom(Blocks.END_PORTAL), BlockModel.Manual)
final override val tags
get() = listOf(BlockTags.PORTALS)
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
abstract override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity
protected abstract fun onEntityInside(world: World, pos: BlockPos, entity: Entity)
final override fun onEntityCollision(state: BlockState, world: World, pos: BlockPos, entity: Entity) {
if (!world.isRemote && !entity.isPassenger && !entity.isBeingRidden && entity.canChangeDimension() && entity.posY <= pos.y + 0.05) {
onEntityInside(world, pos, entity)
}
}
override fun getCollisionShape(state: BlockState, world: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
return COLLISION_AABB
}
final override fun getRenderType(state: BlockState) = INVISIBLE
}

View File

@@ -5,18 +5,11 @@ import chylex.hee.game.Resource.location
import chylex.hee.game.block.BlockCorruptedEnergy.SpawnResult.FAIL
import chylex.hee.game.block.BlockCorruptedEnergy.SpawnResult.PASSTHROUGH
import chylex.hee.game.block.BlockCorruptedEnergy.SpawnResult.SUCCESS
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockClientEffectsComponent
import chylex.hee.game.block.components.IBlockCollideWithEntityComponent
import chylex.hee.game.block.components.IBlockRandomTickComponent
import chylex.hee.game.block.components.IBlockScheduledTickComponent
import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.block.properties.TickSchedule
import chylex.hee.game.block.util.Property
import chylex.hee.game.block.util.with
import chylex.hee.game.entity.CustomCreatureType
@@ -42,123 +35,60 @@ import chylex.hee.game.world.util.getTile
import chylex.hee.game.world.util.removeBlock
import chylex.hee.game.world.util.setState
import chylex.hee.init.ModBlocks
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.random.nextInt
import chylex.hee.util.random.removeItem
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType.INVISIBLE
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.state.StateContainer.Builder
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
import net.minecraft.world.server.ServerWorld
import java.util.Random
object BlockCorruptedEnergy : HeeBlockBuilder() {
private const val MIN_LEVEL = 0
private const val MAX_LEVEL = 20
private const val MAX_TICK_RATE = 5
private const val MIN_TICK_RATE = 1
val LEVEL = Property.int("level", MIN_LEVEL..MAX_LEVEL)
private val DAMAGE_PART_NORMAL = Damage(DIFFICULTY_SCALING, ARMOR_PROTECTION(false), ENCHANTMENT_PROTECTION)
private val DAMAGE_PART_MAGIC = Damage(MAGIC_TYPE, NUDITY_DANGER, RAPID_DAMAGE(2))
private val PARTICLE_CORRUPTION = ParticleSpawnerCustom(
type = ParticleCorruptedEnergy,
pos = InBox(0.75F),
mot = InBox(0.05F),
hideOnMinimalSetting = false
)
init {
localization = LocalizationStrategy.None
model = BlockStateModel(BlockStatePreset.Simple, BlockModel.NoAmbientOcclusion(BlockModel.Cross(Blocks.BARRIER.asItem().location)))
// renderLayer = CUTOUT // Debugging
class BlockCorruptedEnergy(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
private const val MIN_LEVEL = 0
private const val MAX_LEVEL = 20
material = Materials.CORRUPTED_ENERGY
color = MaterialColor.PURPLE
sound = SoundType.SAND
private const val MAX_TICK_RATE = 5
private const val MIN_TICK_RATE = 1
isSolid = false
val LEVEL = Property.int("level", MIN_LEVEL..MAX_LEVEL)
drop = BlockDrop.Nothing
private val DAMAGE_PART_NORMAL = Damage(DIFFICULTY_SCALING, ARMOR_PROTECTION(false), ENCHANTMENT_PROTECTION)
private val DAMAGE_PART_MAGIC = Damage(MAGIC_TYPE, NUDITY_DANGER, RAPID_DAMAGE(2))
components.states.set(LEVEL, MIN_LEVEL)
private val PARTICLE_CORRUPTION = ParticleSpawnerCustom(
type = ParticleCorruptedEnergy,
pos = InBox(0.75F),
mot = InBox(0.05F),
hideOnMinimalSetting = false
)
components.renderType = INVISIBLE
components.ambientOcclusionValue = 1F
components.clientEffects = object : IBlockClientEffectsComponent {
override fun randomTick(state: BlockState, world: World, pos: BlockPos, rand: Random) {
val amount = rand.nextInt(0, 2)
if (amount > 0) {
PARTICLE_CORRUPTION.spawn(Point(pos, amount), rand) // POLISH figure out how to show particles outside animateTick range
}
}
private fun tickRateForLevel(level: Int): Int {
return (MAX_TICK_RATE - (level / 2)).coerceAtLeast(MIN_TICK_RATE)
}
components.scheduledTick = object : IBlockScheduledTickComponent {
override fun onAdded(state: BlockState, world: World, pos: BlockPos, rand: Random): TickSchedule {
return tickScheduleForLevel(state[LEVEL])
}
override fun onTick(state: BlockState, world: World, pos: BlockPos, rand: Random): TickSchedule {
val level = state[LEVEL]
val remainingFacings = Facing6.toMutableList()
repeat(rand.nextInt(3, 5).coerceAtMost(level)) {
val facing = rand.removeItem(remainingFacings)
val adjacentPos = pos.offset(facing)
val spreadDecrease = if (rand.nextInt(3) == 0) 0 else 1
if (spawn(world, adjacentPos, level - spreadDecrease) == PASSTHROUGH) {
spawn(world, adjacentPos.offset(facing), level - spreadDecrease - 1)
}
}
if (rand.nextInt(4) != 0) {
val decreaseToLevel = level - rand.nextInt(1, 2)
if (decreaseToLevel < MIN_LEVEL) {
pos.removeBlock(world)
return TickSchedule.Never
}
pos.setState(world, state.with(LEVEL, decreaseToLevel), FLAG_NONE) // does not call onBlockAdded for the same Block instance
}
return tickScheduleForLevel(level)
}
private fun tickScheduleForLevel(level: Int): TickSchedule {
return TickSchedule.InTicks((MAX_TICK_RATE - (level / 2)).coerceAtLeast(MIN_TICK_RATE))
}
private fun isEntityTolerant(entity: LivingEntity): Boolean {
return CustomCreatureType.isDemon(entity) || CustomCreatureType.isShadow(entity) || entity is IImmuneToCorruptedEnergy
}
components.randomTick = IBlockRandomTickComponent { state, world, pos, _ ->
if (!world.pendingBlockTicks.isTickScheduled(pos, state.block)) {
pos.removeBlock(world)
}
}
components.collideWithEntity = IBlockCollideWithEntityComponent { state, world, pos, entity ->
if (!world.isRemote && entity is LivingEntity && !isEntityTolerant(entity)) {
CombinedDamage(
DAMAGE_PART_NORMAL to 0.75F,
DAMAGE_PART_MAGIC to (0.75F + state[LEVEL] / 10F)
).dealTo(entity, TITLE_MAGIC)
}
}
components.isAir = true
}
private fun isEntityTolerant(entity: LivingEntity): Boolean {
return CustomCreatureType.isDemon(entity) || CustomCreatureType.isShadow(entity) || entity is IImmuneToCorruptedEnergy
override val localization
get() = LocalizationStrategy.None
override val model
get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.NoAmbientOcclusion(BlockModel.Cross(Blocks.BARRIER.asItem().location)))
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(LEVEL)
}
// Utility methods
@@ -167,19 +97,19 @@ object BlockCorruptedEnergy : HeeBlockBuilder() {
SUCCESS, PASSTHROUGH, FAIL
}
fun spawn(world: World, pos: BlockPos, level: Int): SpawnResult {
fun spawnCorruptedEnergy(world: World, pos: BlockPos, level: Int): SpawnResult {
if (level < MIN_LEVEL) {
return FAIL
}
else if (level > MAX_LEVEL) {
return spawn(world, pos, MAX_LEVEL)
return spawnCorruptedEnergy(world, pos, MAX_LEVEL)
}
val currentState = pos.getState(world)
val currentBlock = currentState.block
var updateFlags = FLAG_SYNC_CLIENT
if (currentBlock === ModBlocks.CORRUPTED_ENERGY) {
if (currentBlock === this) {
if (level - currentState[LEVEL] < 3 || world.rand.nextBoolean()) {
return FAIL
}
@@ -200,7 +130,88 @@ object BlockCorruptedEnergy : HeeBlockBuilder() {
PASSTHROUGH
}
pos.setState(world, ModBlocks.CORRUPTED_ENERGY.with(LEVEL, level), updateFlags)
pos.setState(world, this.with(LEVEL, level), updateFlags)
return SUCCESS
}
// Tick handling
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
world.pendingBlockTicks.scheduleTick(pos, this, tickRateForLevel(state[LEVEL]))
}
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, rand: Random) {
if (!world.pendingBlockTicks.isTickScheduled(pos, this)) {
pos.removeBlock(world)
}
}
override fun tick(state: BlockState, world: ServerWorld, pos: BlockPos, rand: Random) {
val level = state[LEVEL]
val remainingFacings = Facing6.toMutableList()
repeat(rand.nextInt(3, 5).coerceAtMost(level)) {
val facing = rand.removeItem(remainingFacings)
val adjacentPos = pos.offset(facing)
val spreadDecrease = if (rand.nextInt(3) == 0) 0 else 1
if (spawnCorruptedEnergy(world, adjacentPos, level - spreadDecrease) == PASSTHROUGH) {
spawnCorruptedEnergy(world, adjacentPos.offset(facing), level - spreadDecrease - 1)
}
}
if (rand.nextInt(4) != 0) {
val decreaseToLevel = level - rand.nextInt(1, 2)
if (decreaseToLevel < MIN_LEVEL) {
pos.removeBlock(world)
return
}
pos.setState(world, state.with(LEVEL, decreaseToLevel), FLAG_NONE) // does not call onBlockAdded for the same Block instance
}
world.pendingBlockTicks.scheduleTick(pos, this, tickRateForLevel(level))
}
// Interactions
override fun isAir(state: BlockState, world: IBlockReader, pos: BlockPos): Boolean {
return true
}
override fun propagatesSkylightDown(state: BlockState, world: IBlockReader, pos: BlockPos): Boolean {
return true
}
override fun onEntityCollision(state: BlockState, world: World, pos: BlockPos, entity: Entity) {
if (!world.isRemote && entity is LivingEntity && !isEntityTolerant(entity)) {
CombinedDamage(
DAMAGE_PART_NORMAL to 0.75F,
DAMAGE_PART_MAGIC to (0.75F + state[LEVEL] / 10F)
).dealTo(entity, TITLE_MAGIC)
}
}
// Client side
@Sided(Side.CLIENT)
override fun animateTick(state: BlockState, world: World, pos: BlockPos, rand: Random) {
val amount = rand.nextInt(0, 2)
if (amount > 0) {
PARTICLE_CORRUPTION.spawn(Point(pos, amount), rand) // POLISH figure out how to show particles outside animateTick range
}
}
@Sided(Side.CLIENT)
override fun getAmbientOcclusionLightValue(state: BlockState, world: IBlockReader, pos: BlockPos): Float {
return 1F
}
override fun getRenderType(state: BlockState) = INVISIBLE
// Debugging
// override fun getRenderLayer() = CUTOUT
}

View File

@@ -1,53 +1,56 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockAddedComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.components.ISetBlockStateFromNeighbor
import chylex.hee.game.block.entity.TileEntityEndPortalAcceptor
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.world.util.getTile
import chylex.hee.init.ModBlocks
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.UP
import net.minecraft.util.Hand
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.World
object BlockEndPortalAcceptor : HeeBlockBuilder() {
init {
includeFrom(BlockPortalFrameIndestructible)
model = BlockModel.PortalFrame(ModBlocks.END_PORTAL_FRAME, "acceptor")
components.entity = IBlockEntityComponent(::TileEntityEndPortalAcceptor)
components.onAdded = IBlockAddedComponent { _, world, pos ->
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.END_PORTAL_FRAME, ModBlocks.END_PORTAL_INNER, minSize = 1)
class BlockEndPortalAcceptor(builder: BlockBuilder) : BlockPortalFrame(builder) {
override val model
get() = BlockModel.PortalFrame(ModBlocks.END_PORTAL_FRAME, "acceptor")
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityEndPortalAcceptor()
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.END_PORTAL_FRAME, ModBlocks.END_PORTAL_INNER, minSize = 1)
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (player.isCreative && player.isSneaking) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.toggleChargeFromCreativeMode()
return SUCCESS
}
components.setStateFromNeighbor = ISetBlockStateFromNeighbor { state, world, pos, neighborFacing, _ ->
if (!world.isRemote && neighborFacing == UP) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.refreshClusterState()
} // TODO neighbor changed?
state
return PASS
}
override fun updatePostPlacement(state: BlockState, facing: Direction, neighborState: BlockState, world: IWorld, pos: BlockPos, neighborPos: BlockPos): BlockState {
if (!world.isRemote && facing == UP) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.refreshClusterState()
}
components.playerUse = object : IPlayerUseBlockComponent {
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType {
if (player.isCreative && player.isSneaking) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.toggleChargeFromCreativeMode()
return SUCCESS
}
return PASS
}
}
@Suppress("DEPRECATION")
return super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
}
}

View File

@@ -1,10 +1,10 @@
package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.game.block.BlockAbstractPortal.IInnerPortalBlock
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.entity.TileEntityEndPortalAcceptor
import chylex.hee.game.block.entity.TileEntityPortalInner
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.entity.util.EntityPortalContact
import chylex.hee.game.mechanics.causatum.CausatumStage
import chylex.hee.game.mechanics.causatum.EnderCausatum
import chylex.hee.game.world.isEndDimension
@@ -12,39 +12,41 @@ import chylex.hee.game.world.server.DimensionTeleporter
import chylex.hee.game.world.util.closestTickingTile
import chylex.hee.init.ModBlocks
import chylex.hee.util.math.Pos
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
object BlockEndPortalInner : HeeBlockBuilder() {
init {
includeFrom(BlockAbstractPortal(object : IInnerPortalBlock {
override fun createTileEntity(): TileEntity {
return TileEntityPortalInner.End()
}
class BlockEndPortalInner(builder: BlockBuilder) : BlockAbstractPortal(builder) {
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityPortalInner.End()
}
override fun onEntityInside(world: World, pos: BlockPos, entity: Entity) {
if (!EntityPortalContact.shouldTeleport(entity)) {
return
}
if (world.isEndDimension) {
DimensionTeleporter.changeDimension(entity, World.OVERWORLD, DimensionTeleporter.LastEndPortal)
}
else {
val acceptor = pos.closestTickingTile<TileEntityEndPortalAcceptor>(world, MAX_DISTANCE_FROM_FRAME)
override fun teleportEntity(world: World, pos: BlockPos, entity: Entity) {
if (world.isEndDimension) {
DimensionTeleporter.changeDimension(entity, World.OVERWORLD, DimensionTeleporter.LastEndPortal)
if (acceptor != null && acceptor.isCharged) {
findInnerArea(world, acceptor.pos, ModBlocks.END_PORTAL_FRAME)?.let { (min, max) ->
DimensionTeleporter.LastEndPortal.updateForEntity(entity, Pos((min.x + max.x) / 2, pos.y, (min.z + max.z) / 2))
}
else {
val acceptor = pos.closestTickingTile<TileEntityEndPortalAcceptor>(world, BlockAbstractPortal.MAX_DISTANCE_FROM_FRAME)
if (acceptor != null && acceptor.isCharged) {
BlockAbstractPortal.findInnerArea(world, acceptor.pos, ModBlocks.END_PORTAL_FRAME)?.let { (min, max) ->
DimensionTeleporter.LastEndPortal.updateForEntity(entity, Pos((min.x + max.x) / 2, pos.y, (min.z + max.z) / 2))
}
if (entity is PlayerEntity) {
EnderCausatum.triggerStage(entity, CausatumStage.S2_ENTERED_END)
}
DimensionTeleporter.changeDimension(entity, HEE.dim, DimensionTeleporter.EndSpawnPortal)
}
if (entity is PlayerEntity) {
EnderCausatum.triggerStage(entity, CausatumStage.S2_ENTERED_END)
}
DimensionTeleporter.changeDimension(entity, HEE.dim, DimensionTeleporter.EndSpawnPortal)
}
}))
}
}
}

View File

@@ -1,23 +1,22 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockExperienceComponent
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.item.util.Tool.Level.STONE
import chylex.hee.util.random.nextInt
import net.minecraftforge.common.ToolType.PICKAXE
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
import net.minecraftforge.common.Tags
object BlockEndPowderOre : HeeBlockBuilder() {
init {
includeFrom(BlockEndOre)
drop = BlockDrop.Manual
tool = BlockHarvestTool.required(STONE, PICKAXE)
hardness = BlockHardness(hardness = 2F, resistance = 5.4F)
components.experience = IBlockExperienceComponent { rand -> rand.nextInt(1, 2) }
class BlockEndPowderOre(builder: BlockBuilder) : HeeBlock(builder) {
override val drop
get() = BlockDrop.Manual
override val tags
get() = listOf(Tags.Blocks.ORES)
override fun getExpDrop(state: BlockState, world: IWorldReader, pos: BlockPos, fortune: Int, silktouch: Int): Int {
return ((world as? World)?.rand ?: RANDOM).nextInt(1, 2)
}
}

View File

@@ -2,48 +2,22 @@ package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.Resource.location
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import chylex.hee.game.item.util.Tool.Level.WOOD
import net.minecraft.block.Blocks
import net.minecraft.block.material.MaterialColor
import net.minecraftforge.common.Tags
import net.minecraftforge.common.ToolType.PICKAXE
object BlockEndStoneCustom : HeeBlockBuilder() {
init {
includeFrom(BlockEndStoneBase)
localization = LocalizationStrategy.MoveToBeginning(wordCount = 1)
model = IBlockStateModelSupplier {
BlockModel.WithTextures(
BlockModel.CubeBottomTop(bottom = Blocks.END_STONE.location),
mapOf("particle" to it.location("_top"))
)
}
tags.add(Tags.Blocks.END_STONES)
tool = BlockHarvestTool.required(WOOD, PICKAXE)
hardness = BlockHardness(hardness = 3F, resistance = 9F)
}
class BlockEndStoneCustom(builder: BlockBuilder, mapColor: MaterialColor) : HeeBlock(builder.clone { color = mapColor }) {
override val localization
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1)
val INFESTED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.RED
}
override val model
get() = BlockModel.WithTextures(
BlockModel.CubeBottomTop(bottom = Blocks.END_STONE.location),
mapOf("particle" to this.location("_top"))
)
val BURNED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.ADOBE // RENAME ORANGE
}
val ENCHANTED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.PURPLE
}
override val tags
get() = listOf(Tags.Blocks.END_STONES)
}

View File

@@ -1,48 +1,26 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockHarvestabilityComponent
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.item.util.Tool.Level.IRON
import chylex.hee.util.forge.EventResult
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import chylex.hee.game.block.properties.BlockBuilder
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.Items
import net.minecraft.util.Hand.MAIN_HAND
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraftforge.common.Tags
import net.minecraftforge.common.ToolType.PICKAXE
abstract class BlockEndium : HeeBlockBuilder() {
init {
material = Materials.SOLID
tool = BlockHarvestTool.required(IRON, PICKAXE)
components.harvestability = IBlockHarvestabilityComponent {
if (it.getHeldItem(MAIN_HAND).item === Items.GOLDEN_PICKAXE)
EventResult.ALLOW
else
EventResult.DEFAULT
}
sealed class BlockEndium(builder: BlockBuilder) : HeeBlock(builder) {
override fun canHarvestBlock(state: BlockState, world: IBlockReader, pos: BlockPos, player: PlayerEntity): Boolean {
return super.canHarvestBlock(state, world, pos, player) || player.getHeldItem(MAIN_HAND).item === Items.GOLDEN_PICKAXE
}
object Ore : BlockEndium() {
init {
includeFrom(BlockEndOre)
hardness = BlockHardness(hardness = 5F, resistance = 9.9F)
}
class Ore(builder: BlockBuilder) : BlockEndium(builder) {
override val tags
get() = listOf(Tags.Blocks.ORES)
}
object Block : BlockEndium() {
init {
color = MaterialColor.LAPIS
sound = SoundType.METAL
tags.add(Tags.Blocks.STORAGE_BLOCKS)
hardness = BlockHardness(hardness = 6.2F, resistance = 12F)
}
class Block(builder: BlockBuilder) : BlockEndium(builder) {
override val tags
get() = listOf(Tags.Blocks.STORAGE_BLOCKS)
}
}

View File

@@ -9,6 +9,7 @@ import chylex.hee.game.mechanics.instability.Instability
import chylex.hee.game.world.util.allInCenteredSphereMutable
import chylex.hee.game.world.util.getTile
import chylex.hee.game.world.util.removeBlock
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModItems
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
@@ -42,7 +43,7 @@ class BlockEnergyCluster(builder: BlockBuilder) : BlockSimpleShaped(builder, Axi
val units = amount.units.value.toFloat()
val corruptedEnergyLevel = (2F + (units.pow(0.74F) / 9F)).ceilToInt()
BlockCorruptedEnergy.spawn(world, pos, corruptedEnergyLevel)
ModBlocks.CORRUPTED_ENERGY.spawnCorruptedEnergy(world, pos, corruptedEnergyLevel)
if (causeInstability) {
Instability.get(world).triggerAction((10 + 2 * corruptedEnergyLevel).toUShort(), pos)
@@ -56,7 +57,7 @@ class BlockEnergyCluster(builder: BlockBuilder) : BlockSimpleShaped(builder, Axi
val corruptedEnergyLevel = (2F + (units.pow(0.74F) / 9F)).ceilToInt()
for (testPos in pos.allInCenteredSphereMutable(corruptedEnergyRadius)) {
BlockCorruptedEnergy.spawn(world, testPos, corruptedEnergyLevel)
ModBlocks.CORRUPTED_ENERGY.spawnCorruptedEnergy(world, testPos, corruptedEnergyLevel)
}
}
}

View File

@@ -1,74 +1,35 @@
package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.ICreatureSpawningOnBlockComponent
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.entity.technical.EntityTechnicalTrigger
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.ENERGY_SHRINE_GLOBAL
import chylex.hee.game.entity.util.posVec
import chylex.hee.game.entity.util.selectEntities
import chylex.hee.game.item.util.Tool.Level.WOOD
import chylex.hee.game.item.util.Tool.Type.PICKAXE
import chylex.hee.game.world.generation.feature.energyshrine.EnergyShrinePieces
import chylex.hee.init.ModTags
import chylex.hee.util.forge.EventResult
import chylex.hee.util.math.center
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.block.BlockState
import net.minecraft.entity.EntitySpawnPlacementRegistry.PlacementType
import net.minecraft.entity.EntityType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.IEntityReader
object BlockGloomrock : HeeBlockBuilder() {
init {
material = Materials.SOLID
color = MaterialColor.BLACK
sound = SoundType.STONE
tool = BlockHarvestTool.required(WOOD, PICKAXE)
hardness = BlockHardness(hardness = 1.6F, resistance = 4.2F)
tags.add(ModTags.GLOOMROCK_PARTICLES)
components.onCreatureSpawning = object : ICreatureSpawningOnBlockComponent {
override fun canSpawn(world: IBlockReader, pos: BlockPos, placementType: PlacementType?, entityType: EntityType<*>?): EventResult {
if (world !is IEntityReader) {
HEE.log.warn("[BlockGloomrock] attempted to check spawn on a world != IEntityReader (${world.javaClass})")
return EventResult.DENY
}
val center = pos.center
val size = EnergyShrinePieces.STRUCTURE_SIZE
val trigger = world
.selectEntities
.inBox<EntityTechnicalTrigger>(size.toCenteredBoundingBox(center))
.find { it.triggerType == ENERGY_SHRINE_GLOBAL }
return EventResult(trigger == null || !size.toCenteredBoundingBox(trigger.posVec).contains(center))
}
open class BlockGloomrock(builder: BlockBuilder) : HeeBlock(builder) {
override fun canCreatureSpawn(state: BlockState, world: IBlockReader, pos: BlockPos, type: PlacementType?, entityType: EntityType<*>?): Boolean {
if (world !is IEntityReader) {
HEE.log.warn("[BlockGloomrock] attempted to check spawn on a world != IEntityReader (${world.javaClass})")
return false
}
}
val BRICKS = HeeBlockBuilder {
includeFrom(BlockGloomrock)
hardness = BlockHardness(hardness = 2.8F, resistance = 6F)
}
val SMOOTH = HeeBlockBuilder {
includeFrom(BlockGloomrock)
localization = LocalizationStrategy.MoveToBeginning(wordCount = 1)
hardness = BlockHardness(hardness = 2F, resistance = 4.8F)
}
val SMOOTH_COLORED = HeeBlockBuilder {
includeFrom(SMOOTH)
localization = LocalizationStrategy.MoveToBeginning(LocalizationStrategy.DeleteWords("Smooth"), wordCount = 1)
val center = pos.center
val size = EnergyShrinePieces.STRUCTURE_SIZE
val trigger = world
.selectEntities
.inBox<EntityTechnicalTrigger>(size.toCenteredBoundingBox(center))
.find { it.triggerType == ENERGY_SHRINE_GLOBAL }
return trigger == null || !size.toCenteredBoundingBox(trigger.posVec).contains(center)
}
}

View File

@@ -0,0 +1,9 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
class BlockGloomrockSmooth(builder: BlockBuilder) : BlockGloomrock(builder) {
override val localization
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1)
}

View File

@@ -0,0 +1,9 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
class BlockGloomrockSmoothColored(builder: BlockBuilder) : BlockGloomrock(builder) {
override val localization
get() = LocalizationStrategy.MoveToBeginning(LocalizationStrategy.DeleteWords("Smooth"), wordCount = 1)
}

View File

@@ -1,37 +1,31 @@
package chylex.hee.game.block
import chylex.hee.game.Resource.location
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockAddedComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IBlockPlacementComponent
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.components.ISetBlockStateFromNeighbor
import chylex.hee.game.block.entity.TileEntityIgneousPlate
import chylex.hee.game.block.logic.IBlockDynamicHardness
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.block.util.FURNACE_FACING
import chylex.hee.game.block.util.Property
import chylex.hee.game.block.util.asVoxelShape
import chylex.hee.game.entity.technical.EntityTechnicalIgneousPlateLogic
import chylex.hee.game.item.properties.ItemModel
import chylex.hee.game.world.util.Facing6
import chylex.hee.game.world.util.getState
import chylex.hee.game.world.util.getTile
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType.ENTITYBLOCK_ANIMATED
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.BlockItemUseContext
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.state.StateContainer.Builder
import net.minecraft.tileentity.FurnaceTileEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS
@@ -43,114 +37,139 @@ import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand
import net.minecraft.util.Mirror
import net.minecraft.util.Rotation
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
object BlockIgneousPlate : HeeBlockBuilder() {
val FACING_NOT_DOWN = Property.facing("facing", Facing6.minusElement(DOWN))
class BlockIgneousPlate(builder: BlockBuilder) : HeeBlock(builder), IBlockDynamicHardness {
companion object {
val FACING_NOT_DOWN = Property.facing("facing", Facing6.minusElement(DOWN))
private const val BB_SIDE_MIN = 0.125
private const val BB_SIDE_MAX = 0.875
private const val BB_TOP = 0.125
private val BOUNDING_BOX = mapOf(
UP to AxisAlignedBB(BB_SIDE_MIN, 0.0, BB_SIDE_MIN, BB_SIDE_MAX, BB_TOP, BB_SIDE_MAX).asVoxelShape,
NORTH to AxisAlignedBB(BB_SIDE_MIN, BB_SIDE_MIN, 1.0 - BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX, 1.0).asVoxelShape,
SOUTH to AxisAlignedBB(BB_SIDE_MIN, BB_SIDE_MIN, 0.0, BB_SIDE_MAX, BB_SIDE_MAX, BB_TOP).asVoxelShape,
EAST to AxisAlignedBB(0.0, BB_SIDE_MIN, BB_SIDE_MIN, BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX).asVoxelShape,
WEST to AxisAlignedBB(1.0 - BB_TOP, BB_SIDE_MIN, BB_SIDE_MIN, 1.0, BB_SIDE_MAX, BB_SIDE_MAX).asVoxelShape
)
private fun canPlacePlateAt(world: IWorldReader, pos: BlockPos, facing: Direction): Boolean {
val furnacePos = pos.offset(facing.opposite)
val state = furnacePos.getState(world)
return (
state.properties.contains(FURNACE_FACING) &&
state[FURNACE_FACING] != facing &&
furnacePos.getTile<FurnaceTileEntity>(world) != null
)
}
}
private const val BB_SIDE_MIN = 0.125
private const val BB_SIDE_MAX = 0.875
private const val BB_TOP = 0.125
private val BOUNDING_BOX = mapOf(
UP to VoxelShapes.create(BB_SIDE_MIN, 0.0, BB_SIDE_MIN, BB_SIDE_MAX, BB_TOP, BB_SIDE_MAX),
NORTH to VoxelShapes.create(BB_SIDE_MIN, BB_SIDE_MIN, 1.0 - BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX, 1.0),
SOUTH to VoxelShapes.create(BB_SIDE_MIN, BB_SIDE_MIN, 0.0, BB_SIDE_MAX, BB_SIDE_MAX, BB_TOP),
EAST to VoxelShapes.create(0.0, BB_SIDE_MIN, BB_SIDE_MIN, BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX),
WEST to VoxelShapes.create(1.0 - BB_TOP, BB_SIDE_MIN, BB_SIDE_MIN, 1.0, BB_SIDE_MAX, BB_SIDE_MAX)
)
override val model
get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(this.location), ItemModel.Simple)
init {
model = IBlockStateModelSupplier {
BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(it.location), ItemModel.Simple)
defaultState = stateContainer.baseState.with(FACING_NOT_DOWN, UP)
}
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(FACING_NOT_DOWN)
}
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityIgneousPlate()
}
// Placement rules
override fun isValidPosition(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return FACING_NOT_DOWN.allowedValues.any { canPlacePlateAt(world, pos, it) }
}
override fun getStateForPlacement(context: BlockItemUseContext): BlockState {
val world = context.world
val pos = context.pos
val facing = context.face
return if (canPlacePlateAt(world, pos, facing))
defaultState.with(FACING_NOT_DOWN, facing)
else
FACING_NOT_DOWN.allowedValues.firstOrNull { canPlacePlateAt(world, pos, it) }?.let { defaultState.with(FACING_NOT_DOWN, it) } ?: defaultState
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
pos.offset(state[FACING_NOT_DOWN].opposite).getTile<FurnaceTileEntity>(world)?.let(EntityTechnicalIgneousPlateLogic.Companion::createForFurnace)
}
override fun updatePostPlacement(state: BlockState, facing: Direction, neighborState: BlockState, world: IWorld, pos: BlockPos, neighborPos: BlockPos): BlockState {
@Suppress("DEPRECATION")
return if (!canPlacePlateAt(world, pos, state[FACING_NOT_DOWN]))
Blocks.AIR.defaultState
else
super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
}
// Interactions
override fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float {
val tile = pos.getTile<TileEntityIgneousPlate>(world) ?: return 0F
return when {
tile.isOverheating -> 10F
tile.isWorking -> 4F
else -> 0F
}
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
val heldItem = player.getHeldItem(hand)
material = Materials.IGNEOUS_ROCK_PLATE
color = MaterialColor.AIR
sound = SoundType.STONE
components.states.set(FACING_NOT_DOWN, default = UP)
components.states.facingProperty = FACING_NOT_DOWN
components.shape = object : IBlockShapeComponent {
override fun getShape(state: BlockState): VoxelShape {
return BOUNDING_BOX[state[FACING_NOT_DOWN]] ?: BOUNDING_BOX.getValue(UP)
}
}
components.renderType = ENTITYBLOCK_ANIMATED
components.entity = IBlockEntityComponent(::TileEntityIgneousPlate)
components.placement = object : IBlockPlacementComponent {
override fun isPositionValid(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return FACING_NOT_DOWN.allowedValues.any { canPlacePlateAt(world, pos, it) }
if (heldItem.item === Items.WATER_BUCKET) {
if (!world.isRemote && tryCoolPlate(world, pos, state) && !player.abilities.isCreativeMode) {
player.setHeldItem(hand, ItemStack(Items.BUCKET))
}
override fun getPlacedState(defaultState: BlockState, world: World, pos: BlockPos, context: BlockItemUseContext): BlockState {
return if (canPlacePlateAt(world, pos, context.face))
defaultState.with(FACING_NOT_DOWN, context.face)
else
FACING_NOT_DOWN.allowedValues.firstOrNull { canPlacePlateAt(world, pos, it) }?.let { defaultState.with(FACING_NOT_DOWN, it) } ?: defaultState
}
return SUCCESS
}
components.onAdded = IBlockAddedComponent { state, world, pos ->
pos.offset(state[FACING_NOT_DOWN].opposite).getTile<FurnaceTileEntity>(world)?.let(EntityTechnicalIgneousPlateLogic.Companion::createForFurnace)
}
components.setStateFromNeighbor = ISetBlockStateFromNeighbor { state, world, pos, _, _ ->
if (!canPlacePlateAt(world, pos, state[FACING_NOT_DOWN]))
Blocks.AIR.defaultState
else
state
}
components.playerUse = object : IPlayerUseBlockComponent {
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType {
val heldItem = player.getHeldItem(hand)
if (heldItem.item !== Items.WATER_BUCKET) {
return PASS
}
if (!world.isRemote && tryCoolPlate(world, pos, state) && !player.abilities.isCreativeMode) {
player.setHeldItem(hand, ItemStack(Items.BUCKET))
}
return SUCCESS
}
}
interfaces[IBlockDynamicHardness::class.java] = object : IBlockDynamicHardness {
override fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float {
val tile = pos.getTile<TileEntityIgneousPlate>(world) ?: return 0F
return when {
tile.isOverheating -> 10F
tile.isWorking -> 4F
else -> 0F
}
}
}
return PASS
}
fun tryCoolPlate(world: World, pos: BlockPos, state: BlockState): Boolean {
return pos.offset(state[FACING_NOT_DOWN].opposite).getTile<FurnaceTileEntity>(world)?.let(EntityTechnicalIgneousPlateLogic.Companion::triggerCooling) == true
}
private fun canPlacePlateAt(world: IWorldReader, pos: BlockPos, facing: Direction): Boolean {
val furnacePos = pos.offset(facing.opposite)
val state = furnacePos.getState(world)
return (
state.properties.contains(FURNACE_FACING) &&
state[FURNACE_FACING] != facing &&
furnacePos.getTile<FurnaceTileEntity>(world) != null
)
// State handling
override fun rotate(state: BlockState, rot: Rotation): BlockState {
return state.with(FACING_NOT_DOWN, rot.rotate(state[FACING_NOT_DOWN]))
}
override fun mirror(state: BlockState, mirror: Mirror): BlockState {
return state.with(FACING_NOT_DOWN, mirror.mirror(state[FACING_NOT_DOWN]))
}
// Rendering
override fun getShape(state: BlockState, world: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
return BOUNDING_BOX[state[FACING_NOT_DOWN]] ?: BOUNDING_BOX.getValue(UP)
}
override fun getRenderType(state: BlockState) = ENTITYBLOCK_ANIMATED
}

View File

@@ -1,24 +1,14 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockDropsComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IBlockExplodedComponent
import chylex.hee.game.block.components.IBlockPlacementComponent
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.components.ISetBlockStateFromNeighbor
import chylex.hee.game.block.entity.TileEntityJarODust
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.TRANSLUCENT
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.fx.util.playServer
import chylex.hee.game.item.components.ITooltipComponent
import chylex.hee.game.item.util.size
import chylex.hee.game.mechanics.dust.DustLayers
import chylex.hee.game.mechanics.dust.DustLayers.Side.BOTTOM
@@ -26,165 +16,164 @@ import chylex.hee.game.mechanics.dust.DustLayers.Side.TOP
import chylex.hee.game.mechanics.dust.DustType
import chylex.hee.game.world.util.getTile
import chylex.hee.game.world.util.isTopSolid
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModSounds
import chylex.hee.system.heeTag
import chylex.hee.system.heeTagOrNull
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.util.math.center
import chylex.hee.util.nbt.getListOfCompounds
import chylex.hee.util.nbt.putList
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootContext.Builder
import net.minecraft.loot.LootContext
import net.minecraft.loot.LootParameters
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Hand
import net.minecraft.util.SoundCategory
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.RayTraceResult
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.Explosion
import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
object BlockJarODust : HeeBlockBuilder() {
init {
localization = LocalizationStrategy.ReplaceWords("O", "o'")
localizationExtra["block.hee.jar_o_dust.tooltip.entry"] = "§7%sx %s"
model = BlockStateModel(BlockStatePreset.Simple, BlockModel.Manual)
renderLayer = TRANSLUCENT
material = Materials.JAR_O_DUST
color = MaterialColor.ORANGE_TERRACOTTA
sound = SoundType.METAL
drop = BlockDrop.Manual
hardness = BlockHardness(hardness = 0.4F, resistance = 0F)
components.tooltip = object : ITooltipComponent {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?) {
val contents = getLayersFromStack(stack)?.contents ?: return
val entries = contents
.groupingBy { it.first }
.fold(0) { acc, entry -> acc + entry.second }
.entries
.sortedWith(compareBy({ -it.value }, { it.key.key }))
for ((dustType, dustAmount) in entries) {
lines.add(TranslationTextComponent("block.hee.jar_o_dust.tooltip.entry", dustAmount, TranslationTextComponent(dustType.item.translationKey)))
}
}
}
components.shape = IBlockShapeComponent.of(VoxelShapes.create(0.1875, 0.0, 0.1875, 0.8125, 0.84375, 0.8125))
components.drops = object : IBlockDropsComponent {
override fun getDrops(state: BlockState, context: Builder): MutableList<ItemStack> {
val drop = (context.get(LootParameters.BLOCK_ENTITY) as? TileEntityJarODust)?.let(::getDrop)
return if (drop == null)
mutableListOf()
else
mutableListOf(drop)
}
override fun getPickBlock(state: BlockState, world: IBlockReader, pos: BlockPos): ItemStack? {
return pos.getTile<TileEntityJarODust>(world)?.let(::getDrop)
}
}
components.entity = IBlockEntityComponent(::TileEntityJarODust)
components.placement = object : IBlockPlacementComponent {
override fun isPositionValid(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return pos.down().isTopSolid(world)
}
override fun onPlacedBy(state: BlockState, world: World, pos: BlockPos, placer: LivingEntity?, stack: ItemStack) {
val list = stack.heeTagOrNull?.getListOfCompounds(TileEntityJarODust.LAYERS_TAG)
if (list != null) {
pos.getTile<TileEntityJarODust>(world)?.layers?.deserializeNBT(list)
}
}
}
components.setStateFromNeighbor = ISetBlockStateFromNeighbor { state, world, pos, neighborFacing, _ ->
if (neighborFacing == DOWN && !state.isValidPosition(world, pos))
Blocks.AIR.defaultState
else
state
}
components.playerUse = IPlayerUseBlockComponent { _, world, pos, player, hand ->
val heldItem = player.getHeldItem(hand)
val result = if (heldItem.isEmpty)
tryExtractDust(world, pos, player, hand)
else
tryInsertDust(world, pos, player, heldItem)
if (result) SUCCESS else PASS
}
components.onExploded = object : IBlockExplodedComponent {
override fun canDrop(explosion: Explosion): Boolean {
return false
}
override fun onExploded(state: BlockState, world: World, pos: BlockPos, explosion: Explosion) {
pos.getTile<TileEntityJarODust>(world)?.let {
val layers = it.layers
repeat(layers.contents.size) {
Block.spawnAsEntity(world, pos, layers.removeDust(BOTTOM))
}
}
ModSounds.BLOCK_JAR_O_DUST_SHATTER.playServer(world, pos.center, SoundCategory.BLOCKS)
}
}
class BlockJarODust(builder: BlockBuilder) : BlockSimpleShaped(builder, AABB) {
companion object {
val AABB = AxisAlignedBB(0.1875, 0.0, 0.1875, 0.8125, 0.84375, 0.8125)
}
// ItemStack
override val localization
get() = LocalizationStrategy.ReplaceWords("O", "o'")
override val localizationExtra
get() = mapOf("block.hee.jar_o_dust.tooltip.entry" to "§7%sx %s")
override val model
get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.Manual)
override val renderLayer
get() = TRANSLUCENT
override val drop
get() = BlockDrop.Manual
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityJarODust()
}
// ItemStack serialization
fun getLayersFromStack(stack: ItemStack): DustLayers? {
return if (stack.item === ModBlocks.JAR_O_DUST.asItem())
return if (stack.item === this.asItem())
stack.heeTagOrNull?.getListOfCompounds(TileEntityJarODust.LAYERS_TAG)?.let { list -> DustLayers(TileEntityJarODust.DUST_CAPACITY).apply { deserializeNBT(list) } }
else
null
}
fun setLayersInStack(stack: ItemStack, layers: DustLayers) {
if (stack.item === ModBlocks.JAR_O_DUST.asItem()) {
if (stack.item === this.asItem()) {
stack.heeTag.putList(TileEntityJarODust.LAYERS_TAG, layers.serializeNBT())
}
}
// Placement
override fun isValidPosition(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
@Suppress("DEPRECATION")
return super.isValidPosition(state, world, pos) && pos.down().isTopSolid(world)
}
override fun updatePostPlacement(state: BlockState, facing: Direction, neighborState: BlockState, world: IWorld, pos: BlockPos, neighborPos: BlockPos): BlockState {
@Suppress("DEPRECATION")
return if (facing == DOWN && !isValidPosition(state, world, pos))
Blocks.AIR.defaultState
else
super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
}
override fun onBlockPlacedBy(world: World, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
val list = stack.heeTagOrNull?.getListOfCompounds(TileEntityJarODust.LAYERS_TAG)
if (list != null) {
pos.getTile<TileEntityJarODust>(world)?.layers?.deserializeNBT(list)
}
}
// Drops
private fun getDrop(tile: TileEntityJarODust): ItemStack {
return ItemStack(ModBlocks.JAR_O_DUST).also { setLayersInStack(it, tile.layers) }
return ItemStack(this).also { setLayersInStack(it, tile.layers) }
}
override fun getDrops(state: BlockState, context: LootContext.Builder): MutableList<ItemStack> {
val drop = (context.get(LootParameters.BLOCK_ENTITY) as? TileEntityJarODust)?.let(::getDrop)
return if (drop != null)
mutableListOf(drop)
else
mutableListOf()
}
override fun getPickBlock(state: BlockState, target: RayTraceResult, world: IBlockReader, pos: BlockPos, player: PlayerEntity): ItemStack {
return pos.getTile<TileEntityJarODust>(world)?.let(::getDrop) ?: ItemStack(this)
}
override fun canDropFromExplosion(explosion: Explosion): Boolean {
return false
}
override fun onBlockExploded(state: BlockState, world: World, pos: BlockPos, explosion: Explosion) {
pos.getTile<TileEntityJarODust>(world)?.let {
val layers = it.layers
repeat(layers.contents.size) {
spawnAsEntity(world, pos, layers.removeDust(BOTTOM))
}
}
ModSounds.BLOCK_JAR_O_DUST_SHATTER.playServer(world, pos.center, SoundCategory.BLOCKS)
super.onBlockExploded(state, world, pos, explosion)
}
// Interaction
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
val heldItem = player.getHeldItem(hand)
val result = if (heldItem.isEmpty)
tryExtractDust(world, pos, player, hand)
else
tryInsertDust(world, pos, player, heldItem)
return if (result) SUCCESS else PASS
}
private fun tryExtractDust(world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): Boolean {
if (world.isRemote) {
return true
}
val removed = pos.getTile<TileEntityJarODust>(world)?.layers?.removeDust(if (player.isSneaking) BOTTOM else TOP)
if (removed != null) {
player.setHeldItem(hand, removed)
}
@@ -208,4 +197,23 @@ object BlockJarODust : HeeBlockBuilder() {
return true
}
// Client side
@Sided(Side.CLIENT)
override fun addInformation(stack: ItemStack, world: IBlockReader?, lines: MutableList<ITextComponent>, flags: ITooltipFlag) {
val contents = getLayersFromStack(stack)?.contents
if (contents != null) {
val entries = contents
.groupingBy { it.first }
.fold(0) { acc, entry -> acc + entry.second }
.entries
.sortedWith(compareBy({ -it.value }, { it.key.key }))
for ((dustType, dustAmount) in entries) {
lines.add(TranslationTextComponent("block.hee.jar_o_dust.tooltip.entry", dustAmount, TranslationTextComponent(dustType.item.translationKey)))
}
}
}
}

View File

@@ -1,18 +1,26 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.entity.TileEntityMinersBurialAltar
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import net.minecraft.block.BlockState
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.world.IBlockReader
object BlockMinersBurialAltar : HeeBlockBuilder() {
init {
includeFrom(BlockMinersBurialCube.INDESCRUCTIBLE)
localization = LocalizationStrategy.ReplaceWords("Miners", "Miner's")
model = BlockModel.Manual
components.entity = IBlockEntityComponent(::TileEntityMinersBurialAltar)
class BlockMinersBurialAltar(builder: BlockBuilder) : BlockSimpleShaped(builder, AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.75, 1.0)) {
override val localization
get() = LocalizationStrategy.ReplaceWords("Miners", "Miner's")
override val model
get() = BlockModel.Manual
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityMinersBurialAltar()
}
}

View File

@@ -1,29 +1,9 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.item.util.Tool.Level
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraftforge.common.ToolType
import chylex.hee.game.block.properties.BlockBuilder
object BlockMinersBurialCube : HeeBlockBuilder() {
init {
localization = LocalizationStrategy.Parenthesized(LocalizationStrategy.DeleteWords(LocalizationStrategy.ReplaceWords("Miners", "Miner's"), "Plain"), wordCount = 1, wordOffset = 3, fromStart = true)
material = Materials.SOLID
color = MaterialColor.RED
sound = SoundType.STONE
tool = BlockHarvestTool.required(Level.WOOD, ToolType.PICKAXE)
hardness = BlockHardness(hardness = 0.6F, resistance = 120F)
}
val INDESCRUCTIBLE = HeeBlockBuilder {
includeFrom(BlockIndestructible)
includeFrom(BlockMinersBurialCube)
}
class BlockMinersBurialCube(builder: BlockBuilder) : HeeBlock(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(LocalizationStrategy.DeleteWords(LocalizationStrategy.ReplaceWords("Miners", "Miner's"), "Plain"), wordCount = 1, wordOffset = 3, fromStart = true)
}

View File

@@ -1,50 +1,28 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockStateModels
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.item.util.Tool.Level.DIAMOND
import net.minecraft.block.Block
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraftforge.common.Tags
import net.minecraftforge.common.ToolType.PICKAXE
object BlockObsidianCube : HeeBlockBuilder() {
private val DEFAULT_LOCALIZATION = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true)
open class BlockObsidianCube(builder: BlockBuilder) : HeeBlock(builder) {
override val localization: LocalizationStrategy
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true)
init {
localization = DEFAULT_LOCALIZATION
final override val tags
get() = listOf(Tags.Blocks.OBSIDIAN)
open class Lit(builder: BlockBuilder, private val modelBlock: Block) : BlockObsidianCube(builder) {
override val localization: LocalizationStrategy
get() = LocalizationStrategy.Parenthesized(super.localization, wordCount = 1, fromStart = false)
tags.add(Tags.Blocks.OBSIDIAN)
material = Materials.SOLID
color = MaterialColor.BLACK
sound = SoundType.STONE
tool = BlockHarvestTool.required(DIAMOND, PICKAXE)
hardness = BlockHardness(hardness = 20F, resistance = 300F)
override val model
get() = BlockStateModels.Cube(modelBlock)
}
class Lit(modelBlock: Block) : HeeBlockBuilder() {
init {
includeFrom(BlockObsidianCube)
localization = LocalizationStrategy.Parenthesized(DEFAULT_LOCALIZATION, wordCount = 1, fromStart = false)
model = BlockStateModels.Cube(modelBlock)
light = 15
}
}
class TowerTop(modelBlock: Block) : HeeBlockBuilder() {
init {
includeFrom(BlockIndestructible)
includeFrom(Lit(modelBlock))
localization = LocalizationStrategy.Default
}
class TowerTop(builder: BlockBuilder, modelBlock: Block) : Lit(builder, modelBlock) {
override val localization
get() = LocalizationStrategy.Default
}
}

View File

@@ -0,0 +1,10 @@
package chylex.hee.game.block
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import net.minecraft.util.math.AxisAlignedBB
open class BlockPortalFrame(builder: BlockBuilder) : BlockSimpleShaped(builder, AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.8125, 1.0)) {
override val model
get() = BlockModel.PortalFrame(this, "plain")
}

View File

@@ -3,20 +3,16 @@ package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.client.util.MC
import chylex.hee.game.Resource
import chylex.hee.game.block.BlockPuzzleLogic.IPuzzleLogic
import chylex.hee.game.block.BlockPuzzleLogic.State.ACTIVE
import chylex.hee.game.block.BlockPuzzleLogic.State.DISABLED
import chylex.hee.game.block.BlockPuzzleLogic.State.INACTIVE
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockPlacementComponent
import chylex.hee.game.block.interfaces.IBlockInterface
import chylex.hee.game.block.interfaces.getHeeInterface
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.properties.BlockTint
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.block.properties.IBlockStateModel
import chylex.hee.game.block.util.Property
import chylex.hee.game.block.util.withFacing
import chylex.hee.game.entity.util.posVec
@@ -50,10 +46,9 @@ import chylex.hee.util.random.nextFloat
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.Entity
import net.minecraft.item.BlockItemUseContext
import net.minecraft.state.StateContainer.Builder
import net.minecraft.util.Direction
import net.minecraft.util.Direction.NORTH
import net.minecraft.util.Direction.SOUTH
@@ -65,7 +60,7 @@ import net.minecraft.world.IBlockDisplayReader
import net.minecraft.world.World
import java.util.Random
class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
val STATE = Property.enum<State>("state")
@@ -106,7 +101,7 @@ class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
var closest = pos
var closestDistSq = pos.distanceSqTo(player)
for (testPos in pos.floodFill(Facing4) { isPuzzleBlock(it.getBlock(world)) }) {
for (testPos in pos.floodFill(Facing4) { it.getBlock(world) is BlockPuzzleLogic }) {
PARTICLE_TOGGLE.spawn(Point(testPos, 3), rand)
val distSq = testPos.distanceSqTo(player)
@@ -128,12 +123,8 @@ class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
}
}
fun isPuzzleBlock(block: Block): Boolean {
return block.getHeeInterface<IPuzzleLogic>() != null
}
fun isPuzzleBlockEnabled(state: BlockState): Boolean {
return isPuzzleBlock(state.block) && state[STATE] != DISABLED
private fun isPuzzleBlockEnabled(state: BlockState): Boolean {
return state.block is BlockPuzzleLogic && state[STATE] != DISABLED
}
fun findAllBlocks(world: World, pos: BlockPos): List<BlockPos> {
@@ -213,66 +204,6 @@ class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
mapOf("top" to Resource.Custom("block/puzzle_overlay_$itemSuffix"))
)
)
fun onToggled(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
val state = pos.getState(world)
val logic = state.block.getHeeInterface<IPuzzleLogic>()
return if (logic != null && toggleState(world, pos, state))
logic.getNextChains(world, pos, facing)
else
emptyList()
}
private fun toggleState(world: World, pos: BlockPos, state: BlockState): Boolean {
val type = state[STATE]
if (type == DISABLED) {
return false
}
pos.setState(world, state.with(STATE, type.toggled))
PacketClientFX(FX_TOGGLE, FxBlockData(pos)).sendToAllAround(world, pos, 24.0)
return true
}
}
init {
includeFrom(BlockIndestructible)
renderLayer = CUTOUT
material = Materials.SOLID
color = MaterialColor.ADOBE /* RENAME ORANGE */
sound = SoundType.STONE
tint = object : BlockTint() {
@Sided(Side.CLIENT)
override fun tint(state: BlockState, world: IBlockDisplayReader?, pos: BlockPos?, tintIndex: Int): Int {
if (tintIndex != 1) {
return NO_TINT
}
if (world == null && pos == null) {
return RGB(104, 58, 16).i // make the color slightly more visible in inventory
}
return when (state[STATE]) {
ACTIVE -> RGB(117, 66, 19).i
INACTIVE -> RGB(212, 157, 102).i
DISABLED -> RGB( 58, 40, 23).i
else -> NO_TINT
}
}
}
components.states.set(STATE, ACTIVE)
interfaces[IPuzzleLogic::class.java] = impl
}
fun interface IPuzzleLogic : IBlockInterface {
fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>>
}
enum class State(private val serializableName: String) : IStringSerializable {
@@ -292,101 +223,159 @@ class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
}
}
object Plain : HeeBlockBuilder() {
internal val LOGIC = IPuzzleLogic { _, pos, facing -> listOf(makePair(pos, facing)) }
abstract override val model: IBlockStateModel
final override val renderLayer
get() = CUTOUT
init {
defaultState = stateContainer.baseState.with(STATE, ACTIVE)
}
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(STATE)
}
// Logic
fun onToggled(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
val state = pos.getState(world)
init {
includeFrom(BlockPuzzleLogic(LOGIC))
localization = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
model = createPlainModel()
return if (toggleState(world, pos, state))
getNextChains(world, pos, facing)
else
emptyList()
}
protected fun toggleState(world: World, pos: BlockPos, state: BlockState): Boolean {
val type = state[STATE]
if (type == DISABLED) {
return false
}
pos.setState(world, state.with(STATE, type.toggled))
PacketClientFX(FX_TOGGLE, FxBlockData(pos)).sendToAllAround(world, pos, 24.0)
return true
}
protected abstract fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>>
// Variations
class Plain(builder: BlockBuilder) : BlockPuzzleLogic(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
override val model
get() = createPlainModel()
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
return listOf(makePair(pos, facing))
}
}
class Burst(radius: Int) : HeeBlockBuilder() {
private val logic = IPuzzleLogic { world, pos, facing ->
pos.allInCenteredBox(radius, 0, radius).toList().flatMap { toggleAndChain(world, it, facing) }.distinct()
}
class Burst(builder: BlockBuilder, private val radius: Int) : BlockPuzzleLogic(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(LocalizationStrategy.ReplaceWords("$diameter", "${diameter}x${diameter}"), wordCount = 2, fromStart = false)
init {
includeFrom(BlockPuzzleLogic(logic))
val diameter = 1 + (radius * 2)
localization = LocalizationStrategy.Parenthesized(LocalizationStrategy.ReplaceWords("$diameter", "${diameter}x${diameter}"), wordCount = 2, fromStart = false)
model = createOverlayModel("burst_$diameter")
}
override val model
get() = createOverlayModel("burst_$diameter")
private val diameter
get() = 1 + (radius * 2)
private fun toggleAndChain(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
val state = pos.getState(world)
val logic = state.block.getHeeInterface<IPuzzleLogic>()
val block = state.block
return if (logic == null || !toggleState(world, pos, state) || logic === Plain.LOGIC || logic === this.logic)
return if (block !is BlockPuzzleLogic || !toggleState(world, pos, state) || block is Plain || block is Burst)
emptyList()
else
logic.getNextChains(world, pos, facing)
block.getNextChains(world, pos, facing)
}
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
return pos.allInCenteredBox(radius, 0, radius).toList().flatMap { toggleAndChain(world, it, facing) }.distinct()
}
}
private class RedirectSome(blockDirections: Array<String>, itemDirection: String, directions: Array<Direction>) : HeeBlockBuilder() {
private val logic = BlockPuzzleLogic { world, pos, facing ->
sealed class RedirectSome private constructor(builder: BlockBuilder, private val blockDirections: Array<String>, private val itemDirection: String, private val directions: Array<Direction>) : BlockPuzzleLogic(builder) {
class R1(builder: BlockBuilder) : RedirectSome(builder, arrayOf("n", "s", "e", "w"), "n", arrayOf(NORTH))
class R2(builder: BlockBuilder) : RedirectSome(builder, arrayOf("ns", "ew"), "ns", arrayOf(NORTH, SOUTH))
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 2, fromStart = false)
override val model
get() = createOverlayModel("redirect_" + directions.size + itemDirection, blockDirections.map { "redirect_" + directions.size + it })
init {
defaultState = stateContainer.baseState.with(STATE, ACTIVE).withFacing(NORTH)
}
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(STATE, HORIZONTAL_FACING)
}
override fun getStateForPlacement(context: BlockItemUseContext): BlockState {
return this.withFacing(context.placementHorizontalFacing)
}
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
val rotation = pos.getState(world)[HORIZONTAL_FACING].horizontalIndex + NORTH.horizontalIndex
val exclude = facing.opposite
directions.map { Direction.byHorizontalIndex(it.horizontalIndex + rotation) }.filter { it != exclude }.map { makePair(pos, it) }
return directions.map { Direction.byHorizontalIndex(it.horizontalIndex + rotation) }.filter { it != exclude }.map { makePair(pos, it) }
}
}
class RedirectAll(builder: BlockBuilder) : BlockPuzzleLogic(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 2, fromStart = false)
init {
includeFrom(logic)
localization = LocalizationStrategy.Parenthesized(wordCount = 2, fromStart = false)
model = createOverlayModel("redirect_" + directions.size + itemDirection, blockDirections.map { "redirect_" + directions.size + it })
components.states.set(HORIZONTAL_FACING, NORTH)
components.states.facingProperty = HORIZONTAL_FACING
components.placement = object : IBlockPlacementComponent {
override fun getPlacedState(defaultState: BlockState, world: World, pos: BlockPos, context: BlockItemUseContext): BlockState {
return defaultState.withFacing(context.placementHorizontalFacing)
}
}
}
}
object RedirectOne : HeeBlockBuilder() {
init {
includeFrom(RedirectSome(arrayOf("n", "s", "e", "w"), "n", arrayOf(NORTH)))
}
}
object RedirectTwo : HeeBlockBuilder() {
init {
includeFrom(RedirectSome(arrayOf("ns", "ew"), "ns", arrayOf(NORTH, SOUTH)))
}
}
object RedirectAll : HeeBlockBuilder() {
init {
includeFrom(BlockPuzzleLogic { _, pos, facing ->
Facing4.filter { it != facing.opposite }.map { makePair(pos, it) }
})
localization = LocalizationStrategy.Parenthesized(wordCount = 2, fromStart = false)
model = createOverlayModel("redirect_4")
}
}
object Teleport : HeeBlockBuilder() {
private val logic = object : IPuzzleLogic {
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
return findAllBlocks(world, pos).filter { it != pos && it.getBlock(world).getHeeInterface<IPuzzleLogic>() === this }.map { makePair(it, facing) }
}
}
override val model
get() = createOverlayModel("redirect_4")
init {
includeFrom(BlockPuzzleLogic(logic))
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
return Facing4.filter { it != facing.opposite }.map { makePair(pos, it) }
}
}
class Teleport(builder: BlockBuilder) : BlockPuzzleLogic(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
override val model
get() = createOverlayModel("teleport")
override fun getNextChains(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
return findAllBlocks(world, pos).filter { it != pos && it.getBlock(world) is Teleport }.map { makePair(it, facing) }
}
}
// Client side
override val tint: BlockTint
get() = Tint
private object Tint : BlockTint() {
@Sided(Side.CLIENT)
override fun tint(state: BlockState, world: IBlockDisplayReader?, pos: BlockPos?, tintIndex: Int): Int {
if (tintIndex != 1) {
return NO_TINT
}
localization = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
model = createOverlayModel("teleport")
if (world == null && pos == null) {
return RGB(104, 58, 16).i // make the color slightly more visible in inventory
}
return when (state[STATE]) {
ACTIVE -> RGB(117, 66, 19).i
INACTIVE -> RGB(212, 157, 102).i
DISABLED -> RGB( 58, 40, 23).i
else -> NO_TINT
}
}
}
}

View File

@@ -1,20 +1,9 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.properties.Materials
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import chylex.hee.game.block.properties.BlockBuilder
object BlockPuzzleWall : HeeBlockBuilder() {
init {
includeFrom(BlockIndestructible)
localization = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
material = Materials.SOLID
color = MaterialColor.ADOBE // RENAME ORANGE
sound = SoundType.STONE
light = 14
}
class BlockPuzzleWall(builder: BlockBuilder) : HeeBlock(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
}

View File

@@ -2,55 +2,62 @@ package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.game.Environment
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.game.block.properties.Materials
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import net.minecraft.block.BlockState
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
object BlockScaffolding : HeeBlockBuilder() {
var enableShape = true
init {
includeFrom(BlockIndestructible)
open class BlockScaffolding protected constructor(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
var enableShape = true
model = BlockModel.Manual
renderLayer = CUTOUT
material = Materials.SCAFFOLDING
color = MaterialColor.AIR
sound = SoundType.STONE
isSolid = false
isOpaque = false
suffocates = false
blocksVision = false
components.shape = object : IBlockShapeComponent {
override fun getShape(state: BlockState): VoxelShape {
return fullCubeIf(enableShape)
}
override fun getCollisionShape(state: BlockState): VoxelShape {
return fullCubeIf(enableShape && Environment.getClientSidePlayer().let { it == null || !it.abilities.isFlying })
}
override fun getRaytraceShape(state: BlockState): VoxelShape {
return fullCubeIf(enableShape && Environment.getClientSidePlayer().let { it == null || it.isSneaking || it.abilities.isFlying })
}
private fun fullCubeIf(condition: Boolean): VoxelShape {
return if (condition) VoxelShapes.fullCube() else VoxelShapes.empty()
}
fun create(builder: BlockBuilder): HeeBlock {
return HEE.debugModule?.createScaffoldingBlock(builder) ?: BlockScaffolding(builder)
}
}
override val model
get() = BlockModel.Manual
override val renderLayer
get() = CUTOUT
// Visuals and physics
override fun getShape(state: BlockState, world: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
return if (enableShape)
VoxelShapes.fullCube()
else
VoxelShapes.empty()
}
override fun getCollisionShape(state: BlockState, world: IBlockReader, pos: BlockPos, context: ISelectionContext): VoxelShape {
val player = Environment.getClientSidePlayer()
components.ambientOcclusionValue = 1F
return if ((player == null || !player.abilities.isFlying) && enableShape)
VoxelShapes.fullCube()
else
VoxelShapes.empty()
}
override fun getRaytraceShape(state: BlockState, world: IBlockReader, pos: BlockPos): VoxelShape {
val player = Environment.getClientSidePlayer()
components.playerUse = HEE.debugModule?.scaffoldingBlockBehavior
return if ((player == null || player.isSneaking || player.abilities.isFlying) && enableShape)
VoxelShapes.fullCube()
else
VoxelShapes.empty()
}
@Sided(Side.CLIENT)
override fun getAmbientOcclusionLightValue(state: BlockState, world: IBlockReader, pos: BlockPos): Float {
return 1F
}
}

View File

@@ -2,43 +2,42 @@ package chylex.hee.game.block
import chylex.hee.game.Resource
import chylex.hee.game.Resource.location
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockExperienceComponent
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockDrop
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import chylex.hee.game.item.util.Tool.Level.STONE
import chylex.hee.game.item.util.Tool.Type.PICKAXE
import chylex.hee.init.ModBlocks
import chylex.hee.util.math.ceilToInt
import chylex.hee.util.random.nextBiasedFloat
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
import net.minecraftforge.common.Tags
object BlockStardustOre : HeeBlockBuilder() {
init {
includeFrom(BlockEndOre)
model = IBlockStateModelSupplier {
BlockStateModel(
BlockStatePreset.None,
BlockModel.WithTextures(BlockModel.FromParent(Resource.Custom("block/cube_overlay")), mapOf(
"particle" to it.location("_particle"),
"base" to Blocks.END_STONE.location,
))
)
}
renderLayer = CUTOUT
drop = BlockDrop.Manual
tool = BlockHarvestTool.required(STONE, PICKAXE)
hardness = BlockHardness(hardness = 2.8F, resistance = 8.4F)
components.experience = IBlockExperienceComponent { rand -> (rand.nextBiasedFloat(4F) * 6F).ceilToInt() }
class BlockStardustOre(builder: BlockBuilder) : HeeBlock(builder) {
override val model
get() = BlockStateModel(
BlockStatePreset.None,
BlockModel.WithTextures(BlockModel.FromParent(Resource.Custom("block/cube_overlay")), mapOf(
"particle" to ModBlocks.STARDUST_ORE.location("_particle"),
"base" to Blocks.END_STONE.location,
))
)
override val renderLayer
get() = CUTOUT
override val drop
get() = BlockDrop.Manual
override val tags
get() = listOf(Tags.Blocks.ORES)
override fun getExpDrop(state: BlockState, world: IWorldReader, pos: BlockPos, fortune: Int, silktouch: Int): Int {
return (((world as? World)?.rand ?: RANDOM).nextBiasedFloat(4F) * 6F).ceilToInt()
}
}

View File

@@ -0,0 +1,26 @@
package chylex.hee.game.block
import chylex.hee.game.block.logic.IBlockDynamicHardness
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.world.util.Facing4
import chylex.hee.game.world.util.getBlock
import chylex.hee.init.ModBlocks
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
open class BlockVoidPortalCrafted(builder: BlockBuilder) : BlockPortalFrame(builder), IBlockDynamicHardness {
override val model
get() = ModBlocks.VOID_PORTAL_FRAME.model
override fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float {
return if (Facing4.any { pos.offset(it).getBlock(world) === ModBlocks.VOID_PORTAL_INNER })
originalHardness * 20F
else
originalHardness
}
override fun getTranslationKey(): String {
return ModBlocks.VOID_PORTAL_FRAME.translationKey
}
}

View File

@@ -1,48 +0,0 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockNameComponent
import chylex.hee.game.block.logic.IBlockDynamicHardness
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.item.util.Tool.Level.DIAMOND
import chylex.hee.game.world.util.Facing4
import chylex.hee.game.world.util.getBlock
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModTags
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraftforge.common.ToolType.PICKAXE
object BlockVoidPortalFrame {
object Indestructible : HeeBlockBuilder() {
init {
includeFrom(BlockPortalFrameIndestructible)
}
}
object Crafted : HeeBlockBuilder() {
init {
includeFrom(BlockPortalFrameBase)
model = ModBlocks.VOID_PORTAL_FRAME.model.generate(ModBlocks.VOID_PORTAL_FRAME)
tags.add(ModTags.VOID_PORTAL_FRAME_CRAFTED)
tool = BlockHarvestTool.required(DIAMOND, PICKAXE)
hardness = BlockHardness(hardnessAndResistance = 1.7F)
components.name = IBlockNameComponent.of(ModBlocks.VOID_PORTAL_FRAME)
interfaces[IBlockDynamicHardness::class.java] = object : IBlockDynamicHardness {
override fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float {
return if (Facing4.any { pos.offset(it).getBlock(world) === ModBlocks.VOID_PORTAL_INNER })
originalHardness * 20F
else
originalHardness
}
}
}
}
}

View File

@@ -1,16 +1,14 @@
package chylex.hee.game.block
import chylex.hee.game.block.BlockAbstractPortal.IInnerPortalBlock
import chylex.hee.game.block.BlockAbstractPortal.IPortalController
import chylex.hee.game.block.BlockVoidPortalInner.Type.HUB
import chylex.hee.game.block.BlockVoidPortalInner.Type.RETURN_ACTIVE
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockNeighborChanged
import chylex.hee.game.block.entity.TileEntityPortalInner
import chylex.hee.game.block.entity.TileEntityVoidPortalStorage
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.util.Property
import chylex.hee.game.entity.Teleporter
import chylex.hee.game.entity.Teleporter.FxRange.Silent
import chylex.hee.game.entity.util.EntityPortalContact
import chylex.hee.game.mechanics.causatum.EnderCausatum
import chylex.hee.game.territory.TerritoryType
import chylex.hee.game.territory.system.TerritoryInstance
@@ -26,67 +24,44 @@ import chylex.hee.game.world.util.max
import chylex.hee.game.world.util.min
import chylex.hee.game.world.util.offsetUntil
import chylex.hee.game.world.util.setAir
import chylex.hee.init.ModTags
import chylex.hee.util.math.Pos
import chylex.hee.util.math.Vec3
import chylex.hee.util.math.center
import chylex.hee.util.math.subtractY
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.state.StateContainer.Builder
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.IStringSerializable
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
object BlockVoidPortalInner : HeeBlockBuilder() {
val TYPE = Property.enum<Type>("type")
private val TELEPORTER = Teleporter(postEvent = false, effectRange = Silent)
init {
includeFrom(BlockAbstractPortal(object : IInnerPortalBlock {
override fun createTileEntity(): TileEntity {
return TileEntityPortalInner.Void()
}
class BlockVoidPortalInner(builder: BlockBuilder) : BlockAbstractPortal(builder) {
companion object {
val TYPE = Property.enum<Type>("type")
private val TELEPORTER = Teleporter(postEvent = false, effectRange = Silent)
fun teleportEntity(entity: Entity, info: SpawnInfo) {
val targetVec = info.pos.center.subtractY(0.45)
override fun teleportEntity(world: World, pos: BlockPos, entity: Entity) {
when (pos.getState(world)[TYPE]) {
HUB -> {
val info = pos.closestTickingTile<TileEntityVoidPortalStorage>(world, BlockAbstractPortal.MAX_DISTANCE_FROM_FRAME)?.prepareSpawnPoint(entity)
if (info != null) {
if (entity.isInEndDimension) {
DimensionTeleporter.LastHubPortal.updateForEntity(entity, null)
updateSpawnPortal(entity, pos)
teleportEntity(entity, info)
}
else {
DimensionTeleporter.LastHubPortal.updateForEntity(entity, pos)
DimensionTeleporter.changeDimension(entity, World.THE_END, DimensionTeleporter.EndTerritoryPortal(info))
}
}
}
RETURN_ACTIVE -> {
if (!DimensionTeleporter.LastHubPortal.tryOverrideTeleport(entity)) {
updateSpawnPortal(entity, pos)
teleportEntity(entity, TerritoryInstance.THE_HUB_INSTANCE.prepareSpawnPoint(entity as? PlayerEntity, clearanceRadius = 2))
}
}
else -> {}
if (entity is LivingEntity) {
if (entity is PlayerEntity) {
TerritoryType.fromPos(info.pos)?.let { EnderCausatum.triggerStage(entity, it.stage) }
}
info.yaw?.let { entity.rotationYaw = it }
entity.rotationPitch = 0F
TELEPORTER.toLocation(entity, targetVec)
}
}))
components.states.set(TYPE, HUB)
components.onNeighborChanged = IBlockNeighborChanged { state, world, pos, oldNeighborBlock, newNeighborBlock, _ ->
if (ModTags.VOID_PORTAL_FRAME_CRAFTED.contains(oldNeighborBlock) && !ModTags.VOID_PORTAL_FRAME_CRAFTED.contains(newNeighborBlock)) {
for (portalPos in pos.floodFill(Facing4) { it.getBlock(world) === state.block }) {
portalPos.setAir(world)
}
else {
entity.setPositionAndUpdate(targetVec.x, targetVec.y, targetVec.z)
entity.motion = Vec3.ZERO
}
}
}
@@ -110,29 +85,38 @@ object BlockVoidPortalInner : HeeBlockBuilder() {
fun create(entity: Entity): TerritoryInstance?
}
fun teleportEntity(entity: Entity, info: SpawnInfo) {
val targetVec = info.pos.center.subtractY(0.45)
if (entity is LivingEntity) {
if (entity is PlayerEntity) {
TerritoryType.fromPos(info.pos)?.let { EnderCausatum.triggerStage(entity, it.stage) }
}
info.yaw?.let { entity.rotationYaw = it }
entity.rotationPitch = 0F
TELEPORTER.toLocation(entity, targetVec)
}
else {
entity.setPositionAndUpdate(targetVec.x, targetVec.y, targetVec.z)
entity.motion = Vec3.ZERO
}
// Instance
init {
defaultState = stateContainer.baseState.with(TYPE, HUB)
}
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(TYPE)
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityPortalInner.Void()
}
// Breaking
override fun neighborChanged(state: BlockState, world: World, pos: BlockPos, neighborBlock: Block, neighborPos: BlockPos, isMoving: Boolean) {
if (neighborBlock is BlockVoidPortalCrafted && neighborPos.getBlock(world) !is BlockVoidPortalCrafted) {
for (portalPos in pos.floodFill(Facing4) { it.getBlock(world) === this }) {
portalPos.setAir(world)
}
}
@Suppress("DEPRECATION")
super.neighborChanged(state, world, pos, neighborBlock, neighborPos, isMoving)
}
// Interaction
private fun findSpawnPortalCenter(entity: Entity, pos: BlockPos): BlockPos? {
val world = entity.world
val block = pos.getBlock(world)
val offsets = Facing4.map { facing -> pos.offsetUntil(facing, 1..BlockAbstractPortal.MAX_SIZE) { it.getBlock(world) !== block } ?: return null }
val offsets = Facing4.map { facing -> pos.offsetUntil(facing, 1..MAX_SIZE) { it.getBlock(world) !== this } ?: return null }
val minPos = offsets.reduce(BlockPos::min)
val maxPos = offsets.reduce(BlockPos::max)
@@ -150,4 +134,37 @@ object BlockVoidPortalInner : HeeBlockBuilder() {
instance.updateSpawnPoint(entity, centerPos)
}
override fun onEntityInside(world: World, pos: BlockPos, entity: Entity) {
if (!EntityPortalContact.shouldTeleport(entity)) {
return
}
when(pos.getState(world)[TYPE]) {
HUB -> {
val info = pos.closestTickingTile<TileEntityVoidPortalStorage>(world, MAX_DISTANCE_FROM_FRAME)?.prepareSpawnPoint(entity)
if (info != null) {
if (entity.isInEndDimension) {
DimensionTeleporter.LastHubPortal.updateForEntity(entity, null)
updateSpawnPortal(entity, pos)
teleportEntity(entity, info)
}
else {
DimensionTeleporter.LastHubPortal.updateForEntity(entity, pos)
DimensionTeleporter.changeDimension(entity, World.THE_END, DimensionTeleporter.EndTerritoryPortal(info))
}
}
}
RETURN_ACTIVE -> {
if (!DimensionTeleporter.LastHubPortal.tryOverrideTeleport(entity)) {
updateSpawnPortal(entity, pos)
teleportEntity(entity, TerritoryInstance.THE_HUB_INSTANCE.prepareSpawnPoint(entity as? PlayerEntity, clearanceRadius = 2))
}
}
else -> {}
}
}
}

View File

@@ -1,40 +1,47 @@
package chylex.hee.game.block
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockAddedComponent
import chylex.hee.game.block.components.IBlockEntityComponent
import chylex.hee.game.block.components.IBlockNameComponent
import chylex.hee.game.block.components.IPlayerUseBlockComponent
import chylex.hee.game.block.entity.TileEntityVoidPortalStorage
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.world.util.getTile
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModContainers
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Hand
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
abstract class BlockVoidPortalStorage(base: HeeBlockBuilder, minPortalSize: Int) : HeeBlockBuilder() {
init {
includeFrom(base)
model = BlockModel.PortalFrame(ModBlocks.VOID_PORTAL_FRAME, "storage")
components.entity = IBlockEntityComponent(::TileEntityVoidPortalStorage)
components.onAdded = IBlockAddedComponent { _, world, pos ->
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.VOID_PORTAL_FRAME, ModBlocks.VOID_PORTAL_INNER, minSize = minPortalSize)
}
components.playerUse = IPlayerUseBlockComponent { _, world, pos, player, _ ->
pos.getTile<TileEntityVoidPortalStorage>(world)?.let { ModContainers.open(player, it, pos) }
SUCCESS
}
class BlockVoidPortalStorage(builder: BlockBuilder) : BlockPortalFrame(builder) {
override val model
get() = BlockModel.PortalFrame(ModBlocks.VOID_PORTAL_FRAME, "storage")
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
object Indestructible : BlockVoidPortalStorage(BlockVoidPortalFrame.Indestructible, minPortalSize = 1)
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityVoidPortalStorage()
}
object Crafted : BlockVoidPortalStorage(BlockVoidPortalFrame.Crafted, minPortalSize = 3) {
init {
components.name = IBlockNameComponent.of(ModBlocks.VOID_PORTAL_STORAGE)
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.VOID_PORTAL_FRAME, ModBlocks.VOID_PORTAL_INNER, minSize = 1)
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (world.isRemote) {
return SUCCESS
}
pos.getTile<TileEntityVoidPortalStorage>(world)?.let {
ModContainers.open(player, it, pos)
}
return SUCCESS
}
}

View File

@@ -0,0 +1,39 @@
package chylex.hee.game.block
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.init.ModBlocks
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType
import net.minecraft.util.Hand
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.world.IBlockReader
import net.minecraft.world.World
class BlockVoidPortalStorageCrafted(builder: BlockBuilder) : BlockVoidPortalCrafted(builder) {
override val model
get() = ModBlocks.VOID_PORTAL_STORAGE.model
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return ModBlocks.VOID_PORTAL_STORAGE.createTileEntity(state, world)
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.VOID_PORTAL_FRAME_CRAFTED, ModBlocks.VOID_PORTAL_INNER, minSize = 3)
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
@Suppress("DEPRECATION")
return ModBlocks.VOID_PORTAL_STORAGE.onBlockActivated(state, world, pos, player, hand, hit)
}
override fun getTranslationKey(): String {
return ModBlocks.VOID_PORTAL_STORAGE.translationKey
}
}

View File

@@ -1,47 +1,27 @@
package chylex.hee.game.block
import chylex.hee.game.Resource.location
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IFlammableBlockComponent
import chylex.hee.game.block.properties.BlockHardness
import chylex.hee.game.block.properties.BlockHarvestTool
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.item.util.Tool.Level.WOOD
import chylex.hee.init.ModBlocks
import net.minecraft.block.SoundType
import net.minecraft.block.material.Material
import net.minecraft.block.material.MaterialColor
import net.minecraft.block.BlockState
import net.minecraft.tags.BlockTags
import net.minecraftforge.common.ToolType.AXE
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
object BlockWhitebark : HeeBlockBuilder() {
init {
material = Material.WOOD
color = MaterialColor.SNOW
sound = SoundType.WOOD
tool = BlockHarvestTool.optional(WOOD, AXE)
class BlockWhitebark(builder: BlockBuilder) : HeeBlock(builder) {
override val model
get() = BlockModel.Cube(ModBlocks.WHITEBARK_LOG.location)
override val tags
get() = listOf(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN)
override fun getFlammability(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return 5
}
val BARK = HeeBlockBuilder {
includeFrom(BlockWhitebark)
model = BlockModel.Cube(ModBlocks.WHITEBARK_LOG.location)
tags.add(BlockTags.LOGS)
tags.add(BlockTags.LOGS_THAT_BURN)
hardness = BlockHardness(hardnessAndResistance = 2F)
components.flammability = IFlammableBlockComponent.of(flammability = 5, fireSpread = 5)
}
val PLANKS = HeeBlockBuilder {
includeFrom(BlockWhitebark)
tags.add(BlockTags.PLANKS)
hardness = BlockHardness(hardness = 2F, resistance = 3F)
components.flammability = IFlammableBlockComponent.of(flammability = 20, fireSpread = 5)
override fun getFireSpreadSpeed(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return 5
}
}

View File

@@ -0,0 +1,21 @@
package chylex.hee.game.block
import chylex.hee.game.block.properties.BlockBuilder
import net.minecraft.block.BlockState
import net.minecraft.tags.BlockTags
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
class BlockWhitebarkPlanks(builder: BlockBuilder) : HeeBlock(builder) {
override val tags
get() = listOf(BlockTags.PLANKS)
override fun getFlammability(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return 20
}
override fun getFireSpreadSpeed(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return 5
}
}

View File

@@ -32,7 +32,6 @@ import chylex.hee.game.world.util.setState
import chylex.hee.init.ModSounds
import chylex.hee.network.client.PacketClientFX
import chylex.hee.util.buffer.readPos
import chylex.hee.util.buffer.use
import chylex.hee.util.buffer.writePos
import chylex.hee.util.math.center
import chylex.hee.util.nbt.TagCompound
@@ -174,9 +173,9 @@ interface IBlockDeathFlowerDecaying {
private val PARTICLE_MOT = Gaussian(0.02F)
class FxHealData(private val pos: BlockPos, private val newLevel: Int) : IFxData {
override fun write(buffer: PacketBuffer) = buffer.use {
writePos(pos)
writeByte(newLevel)
override fun write(buffer: PacketBuffer) {
buffer.writePos(pos)
buffer.writeByte(newLevel)
}
}

View File

@@ -1,6 +1,5 @@
package chylex.hee.game.block.dispenser
import chylex.hee.game.block.BlockIgneousPlate
import chylex.hee.game.block.util.DISPENSER_FACING
import chylex.hee.game.world.util.getState
import chylex.hee.init.ModBlocks
@@ -17,7 +16,7 @@ class DispenseWaterExtinguishIgneousPlate(private val originalBehavior: IDispens
val facingState = facingPos.getState(world)
if (facingState.block === ModBlocks.IGNEOUS_PLATE) {
return if (BlockIgneousPlate.tryCoolPlate(world, facingPos, facingState))
return if (ModBlocks.IGNEOUS_PLATE.tryCoolPlate(world, facingPos, facingState))
ItemStack(Items.BUCKET)
else
stack

View File

@@ -27,7 +27,6 @@ import chylex.hee.init.ModSounds
import chylex.hee.init.ModTileEntities
import chylex.hee.network.client.PacketClientFX
import chylex.hee.util.buffer.readCompactVec
import chylex.hee.util.buffer.use
import chylex.hee.util.buffer.writeCompactVec
import chylex.hee.util.collection.mutableWeightedListOf
import chylex.hee.util.collection.weightedListOf
@@ -119,17 +118,17 @@ class TileEntityMinersBurialAltar(type: TileEntityType<TileEntityMinersBurialAlt
)
class FxSpawnData(private val pos: Vector3d, private val type: Byte) : IFxData {
override fun write(buffer: PacketBuffer) = buffer.use {
writeCompactVec(pos)
writeByte(type.toInt())
override fun write(buffer: PacketBuffer) {
buffer.writeCompactVec(pos)
buffer.writeByte(type.toInt())
}
}
val FX_SPAWN = object : IFxHandler<FxSpawnData> {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
val pos = readCompactVec()
override fun handle(buffer: PacketBuffer, world: World, rand: Random) {
val pos = buffer.readCompactVec()
when (readByte()) {
when (buffer.readByte()) {
REDEEM_TYPE_TOKEN -> {
PARTICLE_SPAWN.spawn(Point(pos, 9), rand)
}

View File

@@ -36,6 +36,7 @@ abstract class TileEntityBasePortalController(type: TileEntityType<out TileEntit
when (clientRenderState) {
Invisible -> clientAnimationProgress.update(max(0F, clientAnimationProgress - clientAnimationFadeOutSpeed))
is Animating -> clientAnimationProgress.update(min(1F, clientAnimationProgress + clientAnimationFadeInSpeed))
else -> {}
}
}

View File

@@ -46,6 +46,13 @@ object BlockBuilders {
explosionResistance = 0.6F
}
val buildEndiumBlock = BlockBuilder(Materials.SOLID, MaterialColor.LAPIS, SoundType.METAL).apply {
requiresTool = true
harvestTool = Pair(IRON, PICKAXE)
harvestHardness = 6.2F
explosionResistance = 12.0F
}
val buildEnderSol = BlockBuilder(Materials.SOLID, MaterialColor.WOOD, SoundType.GROUND.clone(pitch = 0.85F)).apply {
requiresTool = true
harvestTool = Pair(WOOD, SHOVEL)
@@ -69,6 +76,16 @@ object BlockBuilders {
explosionResistance = 4.2F
}
val buildGloomrockBricks = buildGloomrock.clone {
harvestHardness = 2.8F
explosionResistance = 6.0F
}
val buildGloomrockSmooth = buildGloomrock.clone {
harvestHardness = 2.0F
explosionResistance = 4.8F
}
val buildGloomtorch = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.STONE).apply {
explosionResistance = 0.3F
lightLevel = 13
@@ -116,6 +133,19 @@ object BlockBuilders {
lightLevel = 15
}
val buildObsidianTowerTop = buildObsidianVariationLit.clone {
makeIndestructible()
}
// Building (End Stone)
val buildEndStone = BlockBuilder(Materials.SOLID, MaterialColor.SAND, SoundType.STONE).apply {
requiresTool = true
harvestTool = Pair(WOOD, PICKAXE)
harvestHardness = 3.0F
explosionResistance = 9.0F
}
// Building (Dark Loam)
val buildDarkLoam = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.GROUND).apply {
@@ -132,6 +162,10 @@ object BlockBuilders {
explosionResistance = 2.0F
}
val buildWhitebarkPlanks = buildWhitebark.clone {
explosionResistance = 3.0F
}
// Building (Miner's Burial)
val buildMinersBurial = BlockBuilder(Materials.SOLID, MaterialColor.RED, SoundType.STONE).apply {
@@ -141,6 +175,10 @@ object BlockBuilders {
explosionResistance = 120F
}
val buildMinersBurialIndestructible = buildMinersBurial.clone {
makeIndestructible()
}
// Fluids
val buildCauldron = BlockBuilder(Material.IRON, MaterialColor.STONE, SoundType.STONE).apply {
@@ -150,11 +188,26 @@ object BlockBuilders {
// Interactive (Storage)
val buildJarODust = BlockBuilder(Materials.JAR_O_DUST, MaterialColor.ORANGE_TERRACOTTA, SoundType.METAL).apply {
harvestHardness = 0.4F
explosionResistance = 0F
}
val buildLootChest = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.METAL).apply {
makeIndestructible()
lightLevel = 13
}
// Interactive (Puzzle)
val buildPuzzleLogic = BlockBuilder(Materials.SOLID, MaterialColor.ADOBE /* RENAME ORANGE */, SoundType.STONE).apply {
makeIndestructible()
}
val buildPuzzleWall = buildPuzzleLogic.clone {
lightLevel = 14
}
// Interactive (Gates)
val buildExperienceGate = BlockBuilder(Materials.SOLID, MaterialColor.GREEN, SoundType.METAL).apply {
@@ -164,6 +217,8 @@ object BlockBuilders {
// Interactive (Uncategorized)
val buildIgneousPlate = BlockBuilder(Materials.IGNEOUS_ROCK_PLATE, MaterialColor.AIR, SoundType.STONE)
val buildBrewingStand = BlockBuilder(Material.IRON, MaterialColor.YELLOW, SoundType.STONE).apply {
isSolid = false
harvestHardness = 0.5F
@@ -177,6 +232,24 @@ object BlockBuilders {
requiresTool = true
}
val buildEndPowderOre = buildEndOre.clone {
harvestTool = Pair(STONE, PICKAXE)
harvestHardness = 2.0F
explosionResistance = 5.4F
}
val buildEndiumOre = buildEndOre.clone {
harvestTool = Pair(IRON, PICKAXE)
harvestHardness = 5.0F
explosionResistance = 9.9F
}
val buildStardustOre = buildEndOre.clone {
harvestTool = Pair(STONE, PICKAXE)
harvestHardness = 2.8F
explosionResistance = 8.4F
}
val buildIgneousRockOre = buildEndOre.clone {
harvestTool = Pair(DIAMOND, PICKAXE)
harvestHardness = 1.6F
@@ -242,6 +315,25 @@ object BlockBuilders {
noDrops = true
}
// Portals
val buildPortalInner = BlockBuilder(Material.PORTAL, MaterialColor.BLACK, SoundType.STONE).apply {
makeIndestructible()
isSolid = false
lightLevel = 15
}
val buildPortalFrame = BlockBuilder(Materials.SOLID, MaterialColor.SAND, SoundType.STONE).apply {
makeIndestructible()
}
val buildPortalFrameCrafted = BlockBuilder(Materials.SOLID, MaterialColor.SAND, SoundType.STONE).apply {
requiresTool = true
harvestTool = Pair(DIAMOND, PICKAXE)
harvestHardness = 1.7F
explosionResistance = 1.7F
}
// Energy
val buildEnergyCluster = BlockBuilder(Materials.ENERGY_CLUSTER, MaterialColor.SNOW, SoundType.GLASS.clone(volume = 1.25F, pitch = 1.35F)).apply {
@@ -250,6 +342,12 @@ object BlockBuilders {
noDrops = true
}
val buildCorruptedEnergy = BlockBuilder(Materials.CORRUPTED_ENERGY, MaterialColor.PURPLE, SoundType.SAND).apply {
isSolid = false
randomTicks = true // just to be safe
noDrops = true
}
// Tables
val buildTablePedestal = buildGloomrock.clone {
@@ -274,6 +372,14 @@ object BlockBuilders {
lightLevel = 15
}
val buildScaffolding = BlockBuilder(Materials.SCAFFOLDING, MaterialColor.AIR, SoundType.STONE).apply {
makeIndestructible()
isSolid = false
isOpaque = false
suffocates = false
blocksVision = false
}
// Overrides
val buildEndPortalOverride = BlockBuilder(Material.PORTAL, MaterialColor.BLACK, SoundType.STONE).apply {

View File

@@ -23,8 +23,9 @@ import chylex.hee.network.client.PacketClientMoveYourAss
import chylex.hee.network.client.PacketClientRotateInstantly
import chylex.hee.network.client.PacketClientTeleportInstantly
import chylex.hee.util.buffer.readCompactVec
import chylex.hee.util.buffer.use
import chylex.hee.util.buffer.readEnum
import chylex.hee.util.buffer.writeCompactVec
import chylex.hee.util.buffer.writeEnum
import chylex.hee.util.math.Pos
import chylex.hee.util.math.Vec
import chylex.hee.util.math.addY
@@ -78,16 +79,16 @@ class Teleporter(
private val soundVolume: Float,
private val extraRange: Float = 0F,
) : IFxData {
override fun write(buffer: PacketBuffer) = buffer.use {
writeCompactVec(startPoint)
writeCompactVec(endPoint)
writeByte((width * 10F).floorToInt().coerceIn(0, 100))
writeByte((height * 10F).floorToInt().coerceIn(0, 100))
override fun write(buffer: PacketBuffer) {
buffer.writeCompactVec(startPoint)
buffer.writeCompactVec(endPoint)
buffer.writeByte((width * 10F).floorToInt().coerceIn(0, 100))
buffer.writeByte((height * 10F).floorToInt().coerceIn(0, 100))
writeRegistryId(soundEvent)
writeEnumValue(soundCategory)
writeByte((soundVolume * 10F).floorToInt().coerceIn(0, 250))
writeByte(extraRange.floorToInt().coerceIn(0, 255))
buffer.writeRegistryId(soundEvent)
buffer.writeEnum(soundCategory)
buffer.writeByte((soundVolume * 10F).floorToInt().coerceIn(0, 250))
buffer.writeByte(extraRange.floorToInt().coerceIn(0, 255))
}
fun send(world: World) {
@@ -99,20 +100,20 @@ class Teleporter(
}
val FX_TELEPORT = object : IFxHandler<FxTeleportData> {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) {
val player = MC.player ?: return
val playerPos = player.posVec
val startPoint = readCompactVec()
val endPoint = readCompactVec()
val startPoint = buffer.readCompactVec()
val endPoint = buffer.readCompactVec()
val halfWidth = (readByte() / 10F) * 0.5F
val halfHeight = (readByte() / 10F) * 0.5F
val halfWidth = (buffer.readByte() / 10F) * 0.5F
val halfHeight = (buffer.readByte() / 10F) * 0.5F
val soundEvent = readRegistryIdSafe(SoundEvent::class.java)
val soundCategory = readEnumValue(SoundCategory::class.java)
val soundVolume = readByte() / 10F
val soundRange = 16F + readByte()
val soundEvent = buffer.readRegistryIdSafe(SoundEvent::class.java)
val soundCategory = buffer.readEnum() ?: SoundCategory.NEUTRAL
val soundVolume = buffer.readByte() / 10F
val soundRange = 16F + buffer.readByte()
val soundPosition = if (playerPos.squareDistanceTo(startPoint) < playerPos.squareDistanceTo(endPoint))
startPoint

View File

@@ -16,7 +16,6 @@ import chylex.hee.game.world.util.getTile
import chylex.hee.game.world.util.removeBlock
import chylex.hee.game.world.util.setState
import chylex.hee.init.ModEntities
import chylex.hee.util.buffer.use
import chylex.hee.util.math.Pos
import chylex.hee.util.math.Vec3
import chylex.hee.util.math.subtractY
@@ -86,12 +85,12 @@ open class EntityFallingBlockHeavy(type: EntityType<out EntityFallingBlockHeavy>
return NetworkHooks.getEntitySpawningPacket(this)
}
override fun writeSpawnData(buffer: PacketBuffer) = buffer.use {
writeInt(fallTile?.let(Block::getStateId) ?: 0)
override fun writeSpawnData(buffer: PacketBuffer) {
buffer.writeInt(fallTile?.let(Block::getStateId) ?: 0)
}
override fun readSpawnData(buffer: PacketBuffer) = buffer.use {
fallTile = Block.getStateById(readInt())
override fun readSpawnData(buffer: PacketBuffer) {
fallTile = Block.getStateById(buffer.readInt())
}
override fun tick() {

View File

@@ -18,7 +18,6 @@ import chylex.hee.init.ModEntities
import chylex.hee.init.ModSounds
import chylex.hee.network.client.PacketClientFX
import chylex.hee.util.buffer.readPos
import chylex.hee.util.buffer.use
import chylex.hee.util.buffer.writePos
import chylex.hee.util.math.Pos
import chylex.hee.util.random.nextFloat
@@ -45,16 +44,16 @@ class EntityFallingObsidian : EntityFallingBlockHeavy {
private val DAMAGE = Damage(PEACEFUL_EXCLUSION, ARMOR_PROTECTION(false), ENCHANTMENT_PROTECTION)
class FxFallData(private val pos: BlockPos, private val volume: Float) : IFxData {
override fun write(buffer: PacketBuffer) = buffer.use {
writePos(pos)
writeFloat(volume)
override fun write(buffer: PacketBuffer) {
buffer.writePos(pos)
buffer.writeFloat(volume)
}
}
val FX_FALL = object : IFxHandler<FxFallData> {
override fun handle(buffer: PacketBuffer, world: World, rand: Random) = buffer.use {
val pos = readPos()
val volume = readFloat()
override fun handle(buffer: PacketBuffer, world: World, rand: Random) {
val pos = buffer.readPos()
val volume = buffer.readFloat()
repeat(2) {
ModSounds.BLOCK_OBSIDIAN_LAND.playClient(pos, SoundCategory.BLOCKS, volume = volume, pitch = rand.nextFloat(0.8F, 1.2F))

View File

@@ -24,8 +24,7 @@ import chylex.hee.init.ModEntities
import chylex.hee.system.heeTag
import chylex.hee.util.math.Vec
import chylex.hee.util.math.center
import chylex.hee.util.math.range
import chylex.hee.util.math.remapRange
import chylex.hee.util.math.remap
import chylex.hee.util.nbt.TagCompound
import chylex.hee.util.nbt.use
import chylex.hee.util.random.nextFloat
@@ -269,9 +268,9 @@ class EntityInfusedTNT : TNTEntity {
val waterRatio = foundWaterBlocks.size.toFloat() / totalCountedBlocks
val dropAmount = when {
waterRatio < 0.1 -> remapRange(waterRatio, range(0.0F, 0.1F), range(1.0F, 1.6F))
waterRatio < 0.4 -> remapRange(waterRatio, range(0.1F, 0.4F), range(1.6F, 4.0F))
else -> remapRange(waterRatio, range(0.4F, 1.0F), range(4.0F, 5.8F))
waterRatio < 0.1 -> waterRatio.remap(fromMin = 0.0F, fromMax = 0.1F, toMin = 1.0F, toMax = 1.6F)
waterRatio < 0.4 -> waterRatio.remap(fromMin = 0.1F, fromMax = 0.4F, toMin = 1.6F, toMax = 4.0F)
else -> waterRatio.remap(fromMin = 0.4F, fromMax = 1.0F, toMin = 4.0F, toMax = 5.8F)
}
val lootTable = Environment.getLootTable(LootTables.GAMEPLAY_FISHING)

View File

@@ -5,7 +5,6 @@ import chylex.hee.game.particle.spawner.properties.IOffset.Constant
import chylex.hee.game.particle.spawner.properties.IOffset.InBox
import chylex.hee.game.particle.spawner.properties.IShape.Point
import chylex.hee.init.ModEntities
import chylex.hee.util.buffer.use
import chylex.hee.util.math.square
import net.minecraft.entity.EntityType
import net.minecraft.item.ItemStack
@@ -33,12 +32,12 @@ class EntityItemFreshlyCooked : EntityItemBase, IEntityAdditionalSpawnData {
)
}
override fun writeSpawnData(buffer: PacketBuffer) = buffer.use {
writeShort(age)
override fun writeSpawnData(buffer: PacketBuffer) {
buffer.writeShort(age)
}
override fun readSpawnData(buffer: PacketBuffer) = buffer.use {
age = readShort().toInt()
override fun readSpawnData(buffer: PacketBuffer) {
age = buffer.readShort().toInt()
}
override fun tick() {

Some files were not shown because too many files have changed in this diff Show More