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

2 Commits

Author SHA1 Message Date
1135c192bb TODOs 2022-06-20 18:33:28 +02:00
8933d8d8cc WIP 2022-06-20 18:28:11 +02:00
94 changed files with 2218 additions and 1272 deletions

View File

@@ -580,6 +580,8 @@ 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

@@ -0,0 +1,17 @@
{
"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

@@ -0,0 +1,7 @@
{
"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)?.model?.let { registerModel(block, it.blockModel) { builder -> builder } }
(block as? IHeeBlock)?.let { registerModel(block, it.model.generate(block).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)?.model?.let { registerState(block, it.blockState) }
(block as? IHeeBlock)?.let { registerState(block, it.model.generate(block).blockState) }
}
}

View File

@@ -39,15 +39,13 @@ 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)?.model?.let {
registerModel(item, it)
}
(item as? IHeeItem)?.let { registerModel(item, it.model) }
}
for (block in ModBlocks.ALL) {
(block as? IHeeBlock)?.model?.itemModel?.let {
registerModel(if (it.asItem) block.asItem() else block, it.model)
}
(block as? IHeeBlock)
?.let { it.model.generate(block).itemModel }
?.let { registerModel(if (it.asItem) block.asItem() else block, it.model) }
}
}

View File

@@ -6,8 +6,6 @@ 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
@@ -45,9 +43,8 @@ internal object Debug : IDebugModule {
CommandServerTestWorld
)
override fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock {
return BlockScaffoldingDebug(builder)
}
override val scaffoldingBlockBehavior
get() = BlockScaffoldingDebug
@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.properties.BlockBuilder
import chylex.hee.game.block.components.IPlayerUseBlockComponent
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,14 +27,13 @@ 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
class BlockScaffoldingDebug(builder: BlockBuilder) : BlockScaffolding(builder) {
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
object BlockScaffoldingDebug : IPlayerUseBlockComponent {
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType {
if (world.isRemote && player.isSneaking && !player.abilities.isFlying) {
val palette = CommandClientScaffolding.currentPalette
@@ -54,7 +53,7 @@ class BlockScaffoldingDebug(builder: BlockBuilder) : BlockScaffolding(builder) {
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, this)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, state.block)
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 {
open class HeeBlock(builder: BlockBuilder) : Block(builder.p), IHeeBlock { // TODO abstract
override val drop
get() = if (lootTable == LootTables.EMPTY) BlockDrop.Nothing else BlockDrop.Self
}

View File

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

View File

@@ -0,0 +1,229 @@
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,12 +1,13 @@
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.IBlockStateModel
import chylex.hee.game.block.properties.IBlockStateModelSupplier
import net.minecraft.block.Block
import net.minecraft.tags.ITag.INamedTag
@@ -17,7 +18,7 @@ interface IHeeBlock {
val localizationExtra: Map<String, String>
get() = emptyMap()
val model: IBlockStateModel
val model: IBlockStateModelSupplier
get() = BlockModel.Cube
val renderLayer: BlockRenderLayer
@@ -31,4 +32,14 @@ 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

@@ -0,0 +1,149 @@
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

@@ -0,0 +1,26 @@
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

@@ -0,0 +1,86 @@
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

@@ -0,0 +1,23 @@
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

@@ -0,0 +1,50 @@
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

@@ -0,0 +1,9 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,15 @@
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

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

View File

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

View File

@@ -0,0 +1,11 @@
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

@@ -0,0 +1,8 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,21 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,30 @@
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

@@ -0,0 +1,11 @@
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

@@ -0,0 +1,20 @@
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

@@ -0,0 +1,12 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,9 @@
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

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

View File

@@ -0,0 +1,15 @@
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

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

View File

@@ -1,9 +1,10 @@
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 {
interface IBlockDynamicHardness : IBlockInterface {
fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float
}

View File

@@ -0,0 +1,11 @@
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

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

View File

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

View File

@@ -0,0 +1,19 @@
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.World
import net.minecraft.world.IBlockReader
fun interface ITooltipComponent {
fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?)
fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?)
}

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.World
import net.minecraft.world.IBlockReader
class StaticTooltipComponent(private vararg val lines: ITextComponent) : ITooltipComponent {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?) {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?) {
lines.addAll(this.lines)
}
}

View File

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

View File

@@ -0,0 +1,16 @@
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

@@ -10,6 +10,7 @@ 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
@@ -35,7 +36,7 @@ import net.minecraftforge.client.event.RenderGameOverlayEvent
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.HELMET
@SubscribeAllEvents(Side.CLIENT, modid = HEE.ID)
object OverlayRenderer {
object OverlayRenderer { // TODO move to appropriate block builders
private const val BORDER_SIZE = 4
private const val LINE_SPACING = 7
@@ -147,7 +148,7 @@ object OverlayRenderer {
clusterLookedAt = pos.getTile(world)
e.isCanceled = true
}
else if (block is BlockAbstractPortal) {
else if (block.getHeeInterface<BlockAbstractPortal.IInnerPortalBlock>() != null) {
e.isCanceled = true
}
}

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

@@ -0,0 +1,51 @@
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,11 +1,15 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
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.BlockModel
import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset
import chylex.hee.game.block.util.asVoxelShape
import chylex.hee.game.entity.util.EntityPortalContact
import chylex.hee.game.world.util.Facing4
import chylex.hee.game.world.util.allInBox
import chylex.hee.game.world.util.allInBoxMutable
@@ -24,25 +28,27 @@ 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.world.IBlockReader
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.World
abstract class BlockAbstractPortal(builder: BlockBuilder) : BlockSimpleShaped(builder, AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.75, 1.0)) {
class BlockAbstractPortal(impl: IInnerPortalBlock) : HeeBlockBuilder() {
companion object {
const val MAX_DISTANCE_FROM_FRAME = 6.0
const val MAX_SIZE = 5
const val TRANSLATION_SPEED_LONG = 600000L
private const val TRANSLATION_SPEED_LONG = 600000L
const val TRANSLATION_SPEED_INV = 1.0 / TRANSLATION_SPEED_LONG
private val COLLISION_AABB = AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.025, 1.0).asVoxelShape
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)
fun findInnerArea(world: World, controllerPos: BlockPos, frameBlock: Block): Pair<BlockPos, BlockPos>? {
val mirrorRange = 1..(MAX_SIZE + 1)
@@ -94,36 +100,52 @@ abstract class BlockAbstractPortal(builder: BlockBuilder) : BlockSimpleShaped(bu
}
}
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,11 +5,18 @@ 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.BlockBuilder
import chylex.hee.game.block.properties.BlockDrop
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
@@ -35,60 +42,123 @@ 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.entity.Entity
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
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
class BlockCorruptedEnergy(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
private const val MIN_LEVEL = 0
private const val MAX_LEVEL = 20
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
private const val MAX_TICK_RATE = 5
private const val MIN_TICK_RATE = 1
material = Materials.CORRUPTED_ENERGY
color = MaterialColor.PURPLE
sound = SoundType.SAND
val LEVEL = Property.int("level", MIN_LEVEL..MAX_LEVEL)
isSolid = false
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))
drop = BlockDrop.Nothing
private val PARTICLE_CORRUPTION = ParticleSpawnerCustom(
type = ParticleCorruptedEnergy,
pos = InBox(0.75F),
mot = InBox(0.05F),
hideOnMinimalSetting = false
)
components.states.set(LEVEL, MIN_LEVEL)
private fun tickRateForLevel(level: Int): Int {
return (MAX_TICK_RATE - (level / 2)).coerceAtLeast(MIN_TICK_RATE)
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 isEntityTolerant(entity: LivingEntity): Boolean {
return CustomCreatureType.isDemon(entity) || CustomCreatureType.isShadow(entity) || entity is IImmuneToCorruptedEnergy
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))
}
}
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
}
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)
private fun isEntityTolerant(entity: LivingEntity): Boolean {
return CustomCreatureType.isDemon(entity) || CustomCreatureType.isShadow(entity) || entity is IImmuneToCorruptedEnergy
}
// Utility methods
@@ -97,19 +167,19 @@ class BlockCorruptedEnergy(builder: BlockBuilder) : HeeBlock(builder) {
SUCCESS, PASSTHROUGH, FAIL
}
fun spawnCorruptedEnergy(world: World, pos: BlockPos, level: Int): SpawnResult {
fun spawn(world: World, pos: BlockPos, level: Int): SpawnResult {
if (level < MIN_LEVEL) {
return FAIL
}
else if (level > MAX_LEVEL) {
return spawnCorruptedEnergy(world, pos, MAX_LEVEL)
return spawn(world, pos, MAX_LEVEL)
}
val currentState = pos.getState(world)
val currentBlock = currentState.block
var updateFlags = FLAG_SYNC_CLIENT
if (currentBlock === this) {
if (currentBlock === ModBlocks.CORRUPTED_ENERGY) {
if (level - currentState[LEVEL] < 3 || world.rand.nextBoolean()) {
return FAIL
}
@@ -130,88 +200,7 @@ class BlockCorruptedEnergy(builder: BlockBuilder) : HeeBlock(builder) {
PASSTHROUGH
}
pos.setState(world, this.with(LEVEL, level), updateFlags)
pos.setState(world, ModBlocks.CORRUPTED_ENERGY.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,56 +1,53 @@
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
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
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)
}
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.setStateFromNeighbor = ISetBlockStateFromNeighbor { state, world, pos, neighborFacing, _ ->
if (!world.isRemote && neighborFacing == UP) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.refreshClusterState()
} // TODO neighbor changed?
state
}
@Suppress("DEPRECATION")
return super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
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
}
}
}
}

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,41 +12,39 @@ 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
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)
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))
}
if (entity is PlayerEntity) {
EnderCausatum.triggerStage(entity, CausatumStage.S2_ENTERED_END)
}
DimensionTeleporter.changeDimension(entity, HEE.dim, DimensionTeleporter.EndSpawnPortal)
object BlockEndPortalInner : HeeBlockBuilder() {
init {
includeFrom(BlockAbstractPortal(object : IInnerPortalBlock {
override fun createTileEntity(): TileEntity {
return TileEntityPortalInner.End()
}
}
override fun teleportEntity(world: World, pos: BlockPos, entity: Entity) {
if (world.isEndDimension) {
DimensionTeleporter.changeDimension(entity, World.OVERWORLD, DimensionTeleporter.LastEndPortal)
}
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)
}
}
}
}))
}
}

View File

@@ -1,22 +1,23 @@
package chylex.hee.game.block
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockExperienceComponent
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.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IWorldReader
import net.minecraft.world.World
import net.minecraftforge.common.Tags
import net.minecraftforge.common.ToolType.PICKAXE
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)
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) }
}
}

View File

@@ -2,22 +2,48 @@ package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.Resource.location
import chylex.hee.game.block.properties.BlockBuilder
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.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
class BlockEndStoneCustom(builder: BlockBuilder, mapColor: MaterialColor) : HeeBlock(builder.clone { color = mapColor }) {
override val localization
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1)
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)
}
override val model
get() = BlockModel.WithTextures(
BlockModel.CubeBottomTop(bottom = Blocks.END_STONE.location),
mapOf("particle" to this.location("_top"))
)
val INFESTED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.RED
}
override val tags
get() = listOf(Tags.Blocks.END_STONES)
val BURNED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.ADOBE // RENAME ORANGE
}
val ENCHANTED = HeeBlockBuilder {
includeFrom(BlockEndStoneCustom)
color = MaterialColor.PURPLE
}
}

View File

@@ -1,26 +1,48 @@
package chylex.hee.game.block
import chylex.hee.game.block.properties.BlockBuilder
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
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 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
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
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
}
}
class Ore(builder: BlockBuilder) : BlockEndium(builder) {
override val tags
get() = listOf(Tags.Blocks.ORES)
object Ore : BlockEndium() {
init {
includeFrom(BlockEndOre)
hardness = BlockHardness(hardness = 5F, resistance = 9.9F)
}
}
class Block(builder: BlockBuilder) : BlockEndium(builder) {
override val tags
get() = listOf(Tags.Blocks.STORAGE_BLOCKS)
object Block : BlockEndium() {
init {
color = MaterialColor.LAPIS
sound = SoundType.METAL
tags.add(Tags.Blocks.STORAGE_BLOCKS)
hardness = BlockHardness(hardness = 6.2F, resistance = 12F)
}
}
}

View File

@@ -9,7 +9,6 @@ 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
@@ -43,7 +42,7 @@ class BlockEnergyCluster(builder: BlockBuilder) : BlockSimpleShaped(builder, Axi
val units = amount.units.value.toFloat()
val corruptedEnergyLevel = (2F + (units.pow(0.74F) / 9F)).ceilToInt()
ModBlocks.CORRUPTED_ENERGY.spawnCorruptedEnergy(world, pos, corruptedEnergyLevel)
BlockCorruptedEnergy.spawn(world, pos, corruptedEnergyLevel)
if (causeInstability) {
Instability.get(world).triggerAction((10 + 2 * corruptedEnergyLevel).toUShort(), pos)
@@ -57,7 +56,7 @@ class BlockEnergyCluster(builder: BlockBuilder) : BlockSimpleShaped(builder, Axi
val corruptedEnergyLevel = (2F + (units.pow(0.74F) / 9F)).ceilToInt()
for (testPos in pos.allInCenteredSphereMutable(corruptedEnergyRadius)) {
ModBlocks.CORRUPTED_ENERGY.spawnCorruptedEnergy(world, testPos, corruptedEnergyLevel)
BlockCorruptedEnergy.spawn(world, testPos, corruptedEnergyLevel)
}
}
}

View File

@@ -1,35 +1,74 @@
package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.game.block.properties.BlockBuilder
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.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.BlockState
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
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
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
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))
}
}
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)
}
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)
}
}

View File

@@ -1,9 +0,0 @@
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

@@ -1,9 +0,0 @@
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,31 +1,37 @@
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
@@ -37,139 +43,114 @@ 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
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
)
}
}
object BlockIgneousPlate : HeeBlockBuilder() {
val FACING_NOT_DOWN = Property.facing("facing", Facing6.minusElement(DOWN))
override val model
get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(this.location), ItemModel.Simple)
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)
)
init {
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
model = IBlockStateModelSupplier {
BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(it.location), ItemModel.Simple)
}
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
val heldItem = player.getHeldItem(hand)
if (heldItem.item === Items.WATER_BUCKET) {
if (!world.isRemote && tryCoolPlate(world, pos, state) && !player.abilities.isCreativeMode) {
player.setHeldItem(hand, ItemStack(Items.BUCKET))
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) }
}
return SUCCESS
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 PASS
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
}
}
}
}
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
}
// State handling
override fun rotate(state: BlockState, rot: Rotation): BlockState {
return state.with(FACING_NOT_DOWN, rot.rotate(state[FACING_NOT_DOWN]))
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
)
}
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,14 +1,24 @@
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
@@ -16,164 +26,165 @@ 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.client.util.ITooltipFlag
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.loot.LootContext
import net.minecraft.loot.LootContext.Builder
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.BlockRayTraceResult
import net.minecraft.util.math.RayTraceResult
import net.minecraft.util.math.shapes.VoxelShapes
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
class BlockJarODust(builder: BlockBuilder) : BlockSimpleShaped(builder, AABB) {
companion object {
val AABB = AxisAlignedBB(0.1875, 0.0, 0.1875, 0.8125, 0.84375, 0.8125)
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)
}
}
}
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
// ItemStack
fun getLayersFromStack(stack: ItemStack): DustLayers? {
return if (stack.item === this.asItem())
return if (stack.item === ModBlocks.JAR_O_DUST.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 === this.asItem()) {
if (stack.item === ModBlocks.JAR_O_DUST.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(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)
return ItemStack(ModBlocks.JAR_O_DUST).also { setLayersInStack(it, tile.layers) }
}
// 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)
}
@@ -197,23 +208,4 @@ class BlockJarODust(builder: BlockBuilder) : BlockSimpleShaped(builder, AABB) {
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,26 +1,18 @@
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
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()
object BlockMinersBurialAltar : HeeBlockBuilder() {
init {
includeFrom(BlockMinersBurialCube.INDESCRUCTIBLE)
localization = LocalizationStrategy.ReplaceWords("Miners", "Miner's")
model = BlockModel.Manual
components.entity = IBlockEntityComponent(::TileEntityMinersBurialAltar)
}
}

View File

@@ -1,9 +1,29 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
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
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)
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)
}
}

View File

@@ -1,28 +1,50 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
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.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
open class BlockObsidianCube(builder: BlockBuilder) : HeeBlock(builder) {
override val localization: LocalizationStrategy
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true)
object BlockObsidianCube : HeeBlockBuilder() {
private val DEFAULT_LOCALIZATION = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true)
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)
init {
localization = DEFAULT_LOCALIZATION
override val model
get() = BlockStateModels.Cube(modelBlock)
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)
}
class TowerTop(builder: BlockBuilder, modelBlock: Block) : Lit(builder, modelBlock) {
override val localization
get() = LocalizationStrategy.Default
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
}
}
}

View File

@@ -1,10 +0,0 @@
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,16 +3,20 @@ 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.properties.BlockBuilder
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.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.IBlockStateModel
import chylex.hee.game.block.properties.Materials
import chylex.hee.game.block.util.Property
import chylex.hee.game.block.util.withFacing
import chylex.hee.game.entity.util.posVec
@@ -46,9 +50,10 @@ 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
@@ -60,7 +65,7 @@ import net.minecraft.world.IBlockDisplayReader
import net.minecraft.world.World
import java.util.Random
sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
class BlockPuzzleLogic(impl: IPuzzleLogic) : HeeBlockBuilder() {
companion object {
val STATE = Property.enum<State>("state")
@@ -101,7 +106,7 @@ sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
var closest = pos
var closestDistSq = pos.distanceSqTo(player)
for (testPos in pos.floodFill(Facing4) { it.getBlock(world) is BlockPuzzleLogic }) {
for (testPos in pos.floodFill(Facing4) { isPuzzleBlock(it.getBlock(world)) }) {
PARTICLE_TOGGLE.spawn(Point(testPos, 3), rand)
val distSq = testPos.distanceSqTo(player)
@@ -123,8 +128,12 @@ sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
}
}
private fun isPuzzleBlockEnabled(state: BlockState): Boolean {
return state.block is BlockPuzzleLogic && state[STATE] != DISABLED
fun isPuzzleBlock(block: Block): Boolean {
return block.getHeeInterface<IPuzzleLogic>() != null
}
fun isPuzzleBlockEnabled(state: BlockState): Boolean {
return isPuzzleBlock(state.block) && state[STATE] != DISABLED
}
fun findAllBlocks(world: World, pos: BlockPos): List<BlockPos> {
@@ -204,6 +213,66 @@ sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
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 {
@@ -223,159 +292,101 @@ sealed class BlockPuzzleLogic(builder: BlockBuilder) : HeeBlock(builder) {
}
}
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)
object Plain : HeeBlockBuilder() {
internal val LOGIC = IPuzzleLogic { _, pos, facing -> listOf(makePair(pos, facing)) }
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))
init {
includeFrom(BlockPuzzleLogic(LOGIC))
localization = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
model = createPlainModel()
}
}
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)
class Burst(radius: Int) : HeeBlockBuilder() {
private val logic = IPuzzleLogic { world, pos, facing ->
pos.allInCenteredBox(radius, 0, radius).toList().flatMap { toggleAndChain(world, it, facing) }.distinct()
}
override val model
get() = createOverlayModel("burst_$diameter")
private val diameter
get() = 1 + (radius * 2)
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")
}
private fun toggleAndChain(world: World, pos: BlockPos, facing: Direction): List<Pair<BlockPos, Direction>> {
val state = pos.getState(world)
val block = state.block
val logic = state.block.getHeeInterface<IPuzzleLogic>()
return if (block !is BlockPuzzleLogic || !toggleState(world, pos, state) || block is Plain || block is Burst)
return if (logic == null || !toggleState(world, pos, state) || logic === Plain.LOGIC || logic === this.logic)
emptyList()
else
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()
logic.getNextChains(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>> {
private class RedirectSome(blockDirections: Array<String>, itemDirection: String, directions: Array<Direction>) : HeeBlockBuilder() {
private val logic = BlockPuzzleLogic { world, pos, facing ->
val rotation = pos.getState(world)[HORIZONTAL_FACING].horizontalIndex + NORTH.horizontalIndex
val exclude = facing.opposite
return directions.map { Direction.byHorizontalIndex(it.horizontalIndex + rotation) }.filter { it != exclude }.map { makePair(pos, it) }
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)
override val model
get() = createOverlayModel("redirect_4")
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
}
init {
includeFrom(logic)
if (world == null && pos == null) {
return RGB(104, 58, 16).i // make the color slightly more visible in inventory
}
localization = LocalizationStrategy.Parenthesized(wordCount = 2, fromStart = false)
model = createOverlayModel("redirect_" + directions.size + itemDirection, blockDirections.map { "redirect_" + directions.size + it })
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(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) }
}
}
init {
includeFrom(BlockPuzzleLogic(logic))
localization = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
model = createOverlayModel("teleport")
}
}
}

View File

@@ -1,9 +1,20 @@
package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.properties.BlockBuilder
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
class BlockPuzzleWall(builder: BlockBuilder) : HeeBlock(builder) {
override val localization
get() = LocalizationStrategy.Parenthesized(wordCount = 1, fromStart = false)
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
}
}

View File

@@ -2,62 +2,55 @@ package chylex.hee.game.block
import chylex.hee.HEE
import chylex.hee.game.Environment
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import chylex.hee.game.block.properties.Materials
import net.minecraft.block.BlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
open class BlockScaffolding protected constructor(builder: BlockBuilder) : HeeBlock(builder) {
companion object {
var enableShape = true
object BlockScaffolding : HeeBlockBuilder() {
var enableShape = true
init {
includeFrom(BlockIndestructible)
fun create(builder: BlockBuilder): HeeBlock {
return HEE.debugModule?.createScaffoldingBlock(builder) ?: BlockScaffolding(builder)
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()
}
}
}
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()
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.ambientOcclusionValue = 1F
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
components.playerUse = HEE.debugModule?.scaffoldingBlockBehavior
}
}

View File

@@ -2,42 +2,43 @@ package chylex.hee.game.block
import chylex.hee.game.Resource
import chylex.hee.game.Resource.location
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.components.IBlockExperienceComponent
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.init.ModBlocks
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.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
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()
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() }
}
}

View File

@@ -1,26 +0,0 @@
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

@@ -0,0 +1,48 @@
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,14 +1,16 @@
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
@@ -24,44 +26,67 @@ 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
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)
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)
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()
}
else {
entity.setPositionAndUpdate(targetVec.x, targetVec.y, targetVec.z)
entity.motion = Vec3.ZERO
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 -> {}
}
}
}))
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)
}
}
}
}
@@ -85,38 +110,29 @@ class BlockVoidPortalInner(builder: BlockBuilder) : BlockAbstractPortal(builder)
fun create(entity: Entity): TerritoryInstance?
}
// 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)
}
}
fun teleportEntity(entity: Entity, info: SpawnInfo) {
val targetVec = info.pos.center.subtractY(0.45)
@Suppress("DEPRECATION")
super.neighborChanged(state, world, pos, neighborBlock, neighborPos, isMoving)
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
}
}
// Interaction
private fun findSpawnPortalCenter(entity: Entity, pos: BlockPos): BlockPos? {
val world = entity.world
val offsets = Facing4.map { facing -> pos.offsetUntil(facing, 1..MAX_SIZE) { it.getBlock(world) !== this } ?: return null }
val block = pos.getBlock(world)
val offsets = Facing4.map { facing -> pos.offsetUntil(facing, 1..BlockAbstractPortal.MAX_SIZE) { it.getBlock(world) !== block } ?: return null }
val minPos = offsets.reduce(BlockPos::min)
val maxPos = offsets.reduce(BlockPos::max)
@@ -134,37 +150,4 @@ class BlockVoidPortalInner(builder: BlockBuilder) : BlockAbstractPortal(builder)
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,47 +1,40 @@
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
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
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityVoidPortalStorage()
}
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
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)
}
pos.getTile<TileEntityVoidPortalStorage>(world)?.let {
ModContainers.open(player, it, pos)
components.playerUse = IPlayerUseBlockComponent { _, world, pos, player, _ ->
pos.getTile<TileEntityVoidPortalStorage>(world)?.let { ModContainers.open(player, it, pos) }
SUCCESS
}
}
object Indestructible : BlockVoidPortalStorage(BlockVoidPortalFrame.Indestructible, minPortalSize = 1)
object Crafted : BlockVoidPortalStorage(BlockVoidPortalFrame.Crafted, minPortalSize = 3) {
init {
components.name = IBlockNameComponent.of(ModBlocks.VOID_PORTAL_STORAGE)
}
return SUCCESS
}
}

View File

@@ -1,39 +0,0 @@
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,27 +1,47 @@
package chylex.hee.game.block
import chylex.hee.game.Resource.location
import chylex.hee.game.block.properties.BlockBuilder
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.BlockModel
import chylex.hee.game.item.util.Tool.Level.WOOD
import chylex.hee.init.ModBlocks
import net.minecraft.block.BlockState
import net.minecraft.block.SoundType
import net.minecraft.block.material.Material
import net.minecraft.block.material.MaterialColor
import net.minecraft.tags.BlockTags
import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraftforge.common.ToolType.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
object BlockWhitebark : HeeBlockBuilder() {
init {
material = Material.WOOD
color = MaterialColor.SNOW
sound = SoundType.WOOD
tool = BlockHarvestTool.optional(WOOD, AXE)
}
override fun getFireSpreadSpeed(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)
}
}

View File

@@ -1,21 +0,0 @@
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

@@ -1,5 +1,6 @@
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
@@ -16,7 +17,7 @@ class DispenseWaterExtinguishIgneousPlate(private val originalBehavior: IDispens
val facingState = facingPos.getState(world)
if (facingState.block === ModBlocks.IGNEOUS_PLATE) {
return if (ModBlocks.IGNEOUS_PLATE.tryCoolPlate(world, facingPos, facingState))
return if (BlockIgneousPlate.tryCoolPlate(world, facingPos, facingState))
ItemStack(Items.BUCKET)
else
stack

View File

@@ -46,13 +46,6 @@ 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)
@@ -76,16 +69,6 @@ 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
@@ -133,19 +116,6 @@ 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 {
@@ -162,10 +132,6 @@ 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 {
@@ -175,10 +141,6 @@ object BlockBuilders {
explosionResistance = 120F
}
val buildMinersBurialIndestructible = buildMinersBurial.clone {
makeIndestructible()
}
// Fluids
val buildCauldron = BlockBuilder(Material.IRON, MaterialColor.STONE, SoundType.STONE).apply {
@@ -188,26 +150,11 @@ 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 {
@@ -217,8 +164,6 @@ 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
@@ -232,24 +177,6 @@ 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
@@ -315,25 +242,6 @@ 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 {
@@ -342,12 +250,6 @@ 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 {
@@ -372,14 +274,6 @@ 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

@@ -160,7 +160,7 @@ class EntityItemIgneousRock : EntityItemNoBob {
if (!world.isRemote && age > 4 && (world.gameTime - 1L) % BlockPuzzleLogic.UPDATE_RATE == 0L) {
val posBelow = currentPos.down()
if (posBelow.getBlock(world) is BlockPuzzleLogic) {
if (BlockPuzzleLogic.isPuzzleBlock(posBelow.getBlock(world))) {
val entity = EntityTechnicalPuzzle(world)
if (entity.startChain(posBelow, throwFacing)) {

View File

@@ -2,11 +2,11 @@ package chylex.hee.game.entity.living
import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.Resource
import chylex.hee.game.block.BlockCorruptedEnergy
import chylex.hee.game.entity.util.DefaultEntityAttributes
import chylex.hee.game.entity.util.with
import chylex.hee.game.mechanics.instability.Instability
import chylex.hee.game.world.util.isPeaceful
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModEntities
import chylex.hee.system.heeTag
import chylex.hee.util.forge.Side
@@ -78,7 +78,7 @@ class EntityMobEndermiteInstability(type: EntityType<EntityMobEndermiteInstabili
val pos = Pos(this)
Instability.get(world).triggerRelief(20u, pos)
ModBlocks.CORRUPTED_ENERGY.spawnCorruptedEnergy(world, pos, 2)
BlockCorruptedEnergy.spawn(world, pos, 2)
}
super.remove()

View File

@@ -83,13 +83,10 @@ class EntityTechnicalPuzzle(type: EntityType<EntityTechnicalPuzzle>, world: Worl
}
private fun moveToBlockAndToggle(pos: BlockPos) {
val block = pos.getBlock(world)
if (block is BlockPuzzleLogic) {
if (BlockPuzzleLogic.isPuzzleBlock(pos.getBlock(world))) {
setPosition(pos)
val nextChains = block.onToggled(world, pos, facing)
val nextChains = BlockPuzzleLogic.onToggled(world, pos, facing)
if (nextChains.isEmpty()) {
endChain()
}
@@ -125,10 +122,7 @@ class EntityTechnicalPuzzle(type: EntityType<EntityTechnicalPuzzle>, world: Worl
}
fun startChain(pos: BlockPos, facing: Direction): Boolean {
val state = pos.getState(world)
val block = state.block
if (block !is BlockPuzzleLogic || state[BlockPuzzleLogic.STATE] == BlockPuzzleLogic.State.DISABLED) {
if (!BlockPuzzleLogic.isPuzzleBlockEnabled(pos.getState(world))) {
return false
}

View File

@@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
import net.minecraft.world.IBlockReader
class ItemAbstractTrinket(trinket: ITrinketItem) : HeeItemBuilder() {
private companion object {
@@ -27,7 +27,7 @@ class ItemAbstractTrinket(trinket: ITrinketItem) : HeeItemBuilder() {
localizationExtra[LANG_TOOLTIP_NOT_IN_SLOT_UNCHARGED] = "§cMust be charged and placed in Trinket slot"
components.tooltip.add(object : ITooltipComponent {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?) {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?) {
val player = MC.player ?: return
if (lines.size > 1) { // first line is item name

View File

@@ -19,7 +19,7 @@ import net.minecraft.item.Rarity
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
import net.minecraft.world.IBlockReader
object ItemBindingEssence : HeeItemBuilder() {
init {
@@ -57,7 +57,7 @@ object ItemBindingEssence : HeeItemBuilder() {
maxStackSize = 16
components.tooltip.add(object : ITooltipComponent {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: World?) {
override fun add(lines: MutableList<ITextComponent>, stack: ItemStack, advanced: Boolean, world: IBlockReader?) {
val list = InfusionTag.getList(stack)
if (list.isEmpty) {
return

View File

@@ -1,9 +1,9 @@
package chylex.hee.game.recipe
import chylex.hee.game.block.BlockJarODust
import chylex.hee.game.inventory.util.nonEmptySlots
import chylex.hee.game.inventory.util.size
import chylex.hee.game.mechanics.dust.DustLayers.Side.BOTTOM
import chylex.hee.init.ModBlocks
import net.minecraft.inventory.CraftingInventory
import net.minecraft.item.ItemStack
import net.minecraft.util.NonNullList
@@ -33,10 +33,10 @@ object RecipeJarODustExtract : RecipeBaseDynamic() {
if (layers != null) {
layers.removeDust(BOTTOM)
it[first.slot] = first.stack.copy().also { stack -> ModBlocks.JAR_O_DUST.setLayersInStack(stack, layers) }
it[first.slot] = first.stack.copy().also { stack -> BlockJarODust.setLayersInStack(stack, layers) }
}
}
}
private fun getLayers(stack: ItemStack) = ModBlocks.JAR_O_DUST.getLayersFromStack(stack)
private fun getLayers(stack: ItemStack) = BlockJarODust.getLayersFromStack(stack)
}

View File

@@ -3,6 +3,7 @@ package chylex.hee.game.territory
import chylex.hee.HEE
import chylex.hee.client.util.MC
import chylex.hee.game.block.BlockAbstractPortal
import chylex.hee.game.block.interfaces.getHeeInterface
import chylex.hee.game.entity.damage.Damage
import chylex.hee.game.entity.damage.IDamageDealer.Companion.TITLE_WITHER
import chylex.hee.game.entity.damage.IDamageProcessor.Companion.DEAL_CREATIVE
@@ -149,7 +150,7 @@ object TerritoryVoid {
continue
}
if (entity !is LivingEntity || Pos(entity).getBlock(world) is BlockAbstractPortal) { // protecting entities inside portals should help with server lag frustrations
if (entity !is LivingEntity || Pos(entity).getBlock(world).getHeeInterface<BlockAbstractPortal.IInnerPortalBlock>() != null) { // protecting entities inside portals should help with server lag frustrations
continue
}

View File

@@ -1,6 +1,6 @@
package chylex.hee.game.world.generation.feature.basic
import chylex.hee.game.block.BlockVoidPortalInner.Companion.TYPE
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.BlockVoidPortalInner.Type.RETURN_INACTIVE

View File

@@ -1,7 +1,6 @@
package chylex.hee.game.world.generation.feature.energyshrine.piece
import chylex.hee.game.Environment
import chylex.hee.game.block.BlockGloomrock
import chylex.hee.game.entity.technical.EntityTechnicalTrigger
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.ITriggerHandler
import chylex.hee.game.entity.technical.EntityTechnicalTrigger.Types.ENERGY_SHRINE_GLOBAL
@@ -17,6 +16,7 @@ import chylex.hee.game.world.generation.trigger.EntityStructureTrigger
import chylex.hee.game.world.util.getBlock
import chylex.hee.game.world.util.getState
import chylex.hee.game.world.util.offsetUntil
import chylex.hee.init.ModTags
import chylex.hee.util.color.IColorGenerator
import chylex.hee.util.color.RGB
import chylex.hee.util.math.Pos
@@ -69,11 +69,11 @@ class EnergyShrineRoom_Main_Start(file: String) : EnergyShrineRoom_Generic(file)
continue
}
if (targetPos.offsetUntil(UP, PARTICLE_GLOOMROCK_CHECK_RANGE) { it.getBlock(world) is BlockGloomrock } == null) {
if (targetPos.offsetUntil(UP, PARTICLE_GLOOMROCK_CHECK_RANGE) { ModTags.GLOOMROCK_PARTICLES.contains(it.getBlock(world)) } == null) {
continue
}
if (targetPos.offsetUntil(DOWN, PARTICLE_GLOOMROCK_CHECK_RANGE) { it.getBlock(world) is BlockGloomrock } == null) {
if (targetPos.offsetUntil(DOWN, PARTICLE_GLOOMROCK_CHECK_RANGE) { ModTags.GLOOMROCK_PARTICLES.contains(it.getBlock(world)) } == null) {
continue
}

View File

@@ -34,8 +34,6 @@ import chylex.hee.game.block.BlockFlowerPotCustom
import chylex.hee.game.block.BlockFlowerPotDeathFlower
import chylex.hee.game.block.BlockFlowerPotDeathFlowerDecaying
import chylex.hee.game.block.BlockGloomrock
import chylex.hee.game.block.BlockGloomrockSmooth
import chylex.hee.game.block.BlockGloomrockSmoothColored
import chylex.hee.game.block.BlockGloomrockSmoothSlab
import chylex.hee.game.block.BlockGloomrockSmoothStairs
import chylex.hee.game.block.BlockGloomtorch
@@ -52,7 +50,7 @@ import chylex.hee.game.block.BlockMinersBurialCube
import chylex.hee.game.block.BlockMinersBurialPillar
import chylex.hee.game.block.BlockObsidianCube
import chylex.hee.game.block.BlockObsidianPillar
import chylex.hee.game.block.BlockPortalFrame
import chylex.hee.game.block.BlockPortalFrameIndestructible
import chylex.hee.game.block.BlockPuzzleLogic
import chylex.hee.game.block.BlockPuzzleWall
import chylex.hee.game.block.BlockScaffolding
@@ -65,17 +63,17 @@ import chylex.hee.game.block.BlockStardustOre
import chylex.hee.game.block.BlockTableBase
import chylex.hee.game.block.BlockTablePedestal
import chylex.hee.game.block.BlockTableTile
import chylex.hee.game.block.BlockVoidPortalCrafted
import chylex.hee.game.block.BlockVoidPortalFrame
import chylex.hee.game.block.BlockVoidPortalInner
import chylex.hee.game.block.BlockVoidPortalStorage
import chylex.hee.game.block.BlockVoidPortalStorageCrafted
import chylex.hee.game.block.BlockWallCustom
import chylex.hee.game.block.BlockWhitebark
import chylex.hee.game.block.BlockWhitebarkLeaves
import chylex.hee.game.block.BlockWhitebarkLog
import chylex.hee.game.block.BlockWhitebarkPlanks
import chylex.hee.game.block.BlockWhitebarkSapling
import chylex.hee.game.block.HeeBlock
import chylex.hee.game.block.HeeBlock2
import chylex.hee.game.block.builder.HeeBlockBuilder
import chylex.hee.game.block.entity.TileEntityAccumulationTable
import chylex.hee.game.block.entity.TileEntityExperienceTable
import chylex.hee.game.block.entity.TileEntityInfusionTable
@@ -84,7 +82,6 @@ import chylex.hee.game.block.fluid.FluidEnderGooPurified
import chylex.hee.game.block.properties.BlockBuilders.buildAncientCobweb
import chylex.hee.game.block.properties.BlockBuilders.buildBrewingStand
import chylex.hee.game.block.properties.BlockBuilders.buildCauldron
import chylex.hee.game.block.properties.BlockBuilders.buildCorruptedEnergy
import chylex.hee.game.block.properties.BlockBuilders.buildDarkLoam
import chylex.hee.game.block.properties.BlockBuilders.buildDragonEgg
import chylex.hee.game.block.properties.BlockBuilders.buildDryVines
@@ -93,49 +90,31 @@ import chylex.hee.game.block.properties.BlockBuilders.buildDustyStoneBricks
import chylex.hee.game.block.properties.BlockBuilders.buildDustyStoneCracked
import chylex.hee.game.block.properties.BlockBuilders.buildDustyStoneDamaged
import chylex.hee.game.block.properties.BlockBuilders.buildEndPortalOverride
import chylex.hee.game.block.properties.BlockBuilders.buildEndPowderOre
import chylex.hee.game.block.properties.BlockBuilders.buildEndStone
import chylex.hee.game.block.properties.BlockBuilders.buildEnderSol
import chylex.hee.game.block.properties.BlockBuilders.buildEndermanHead
import chylex.hee.game.block.properties.BlockBuilders.buildEndiumBlock
import chylex.hee.game.block.properties.BlockBuilders.buildEndiumOre
import chylex.hee.game.block.properties.BlockBuilders.buildEnergyCluster
import chylex.hee.game.block.properties.BlockBuilders.buildEternalFire
import chylex.hee.game.block.properties.BlockBuilders.buildEtherealLantern
import chylex.hee.game.block.properties.BlockBuilders.buildExperienceGate
import chylex.hee.game.block.properties.BlockBuilders.buildFlowerPot
import chylex.hee.game.block.properties.BlockBuilders.buildGloomrock
import chylex.hee.game.block.properties.BlockBuilders.buildGloomrockBricks
import chylex.hee.game.block.properties.BlockBuilders.buildGloomrockSmooth
import chylex.hee.game.block.properties.BlockBuilders.buildGloomtorch
import chylex.hee.game.block.properties.BlockBuilders.buildGraveDirt
import chylex.hee.game.block.properties.BlockBuilders.buildHumus
import chylex.hee.game.block.properties.BlockBuilders.buildIgneousPlate
import chylex.hee.game.block.properties.BlockBuilders.buildIgneousRockOre
import chylex.hee.game.block.properties.BlockBuilders.buildInfusedGlass
import chylex.hee.game.block.properties.BlockBuilders.buildJarODust
import chylex.hee.game.block.properties.BlockBuilders.buildLootChest
import chylex.hee.game.block.properties.BlockBuilders.buildMinersBurial
import chylex.hee.game.block.properties.BlockBuilders.buildMinersBurialIndestructible
import chylex.hee.game.block.properties.BlockBuilders.buildObsidian
import chylex.hee.game.block.properties.BlockBuilders.buildObsidianTowerTop
import chylex.hee.game.block.properties.BlockBuilders.buildObsidianVariation
import chylex.hee.game.block.properties.BlockBuilders.buildObsidianVariationLit
import chylex.hee.game.block.properties.BlockBuilders.buildPlant
import chylex.hee.game.block.properties.BlockBuilders.buildPortalFrame
import chylex.hee.game.block.properties.BlockBuilders.buildPortalFrameCrafted
import chylex.hee.game.block.properties.BlockBuilders.buildPortalInner
import chylex.hee.game.block.properties.BlockBuilders.buildPuzzleLogic
import chylex.hee.game.block.properties.BlockBuilders.buildPuzzleWall
import chylex.hee.game.block.properties.BlockBuilders.buildScaffolding
import chylex.hee.game.block.properties.BlockBuilders.buildSpawnerObsidianTowers
import chylex.hee.game.block.properties.BlockBuilders.buildStardustOre
import chylex.hee.game.block.properties.BlockBuilders.buildTable
import chylex.hee.game.block.properties.BlockBuilders.buildTablePedestal
import chylex.hee.game.block.properties.BlockBuilders.buildVantablock
import chylex.hee.game.block.properties.BlockBuilders.buildWhitebark
import chylex.hee.game.block.properties.BlockBuilders.buildWhitebarkLeaves
import chylex.hee.game.block.properties.BlockBuilders.buildWhitebarkPlanks
import chylex.hee.game.block.properties.BlockBuilders.buildWhitebarkSapling
import chylex.hee.game.block.properties.CustomSkull
import chylex.hee.game.item.ItemAncientCobweb
@@ -176,28 +155,28 @@ object ModBlocks {
@JvmField val STONE_BRICK_WALL = BlockWallCustom(Blocks.STONE_BRICKS) named "stone_brick_wall"
@JvmField val INFUSED_GLASS = BlockInfusedGlass(buildInfusedGlass) named "infused_glass"
@JvmField val VANTABLOCK = HeeBlock(buildVantablock) named "vantablock"
@JvmField val ENDIUM_BLOCK = BlockEndium.Block(buildEndiumBlock) named "endium_block"
@JvmField val ENDIUM_BLOCK = BlockEndium.Block named "endium_block"
@JvmField val ENDERSOL = BlockEndersol(buildEnderSol, mergeBottom = Blocks.END_STONE) named "endersol"
@JvmField val HUMUS = BlockHumus(buildHumus, mergeBottom = ENDERSOL) named "humus"
// Blocks: Building (Gloomrock)
@JvmField val GLOOMROCK = BlockGloomrock(buildGloomrock) named "gloomrock"
@JvmField val GLOOMROCK_BRICKS = BlockGloomrock(buildGloomrockBricks) named "gloomrock_bricks"
@JvmField val GLOOMROCK_BRICK_STAIRS = BlockStairsCustom(GLOOMROCK_BRICKS) named "gloomrock_brick_stairs"
@JvmField val GLOOMROCK = BlockGloomrock named "gloomrock"
@JvmField val GLOOMROCK_BRICKS = BlockGloomrock.BRICKS named "gloomrock_bricks"
@JvmField val GLOOMROCK_BRICK_STAIRS = BlockStairsCustom(GLOOMROCK_BRICKS) named "gloomrock_brick_stairs" // TODO tags for all gloomrock?
@JvmField val GLOOMROCK_BRICK_SLAB = BlockSlabCustom(GLOOMROCK_BRICKS) named "gloomrock_brick_slab"
@JvmField val GLOOMROCK_SMOOTH = BlockGloomrockSmooth(buildGloomrockSmooth) named "gloomrock_smooth"
@JvmField val GLOOMROCK_SMOOTH = BlockGloomrock.SMOOTH named "gloomrock_smooth"
@JvmField val GLOOMROCK_SMOOTH_STAIRS = BlockGloomrockSmoothStairs(GLOOMROCK_SMOOTH) named "gloomrock_smooth_stairs"
@JvmField val GLOOMROCK_SMOOTH_SLAB = BlockGloomrockSmoothSlab(GLOOMROCK_SMOOTH) named "gloomrock_smooth_slab"
@JvmField val GLOOMROCK_SMOOTH_RED = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_red"
@JvmField val GLOOMROCK_SMOOTH_ORANGE = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_orange"
@JvmField val GLOOMROCK_SMOOTH_YELLOW = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_yellow"
@JvmField val GLOOMROCK_SMOOTH_GREEN = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_green"
@JvmField val GLOOMROCK_SMOOTH_CYAN = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_cyan"
@JvmField val GLOOMROCK_SMOOTH_BLUE = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_blue"
@JvmField val GLOOMROCK_SMOOTH_PURPLE = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_purple"
@JvmField val GLOOMROCK_SMOOTH_MAGENTA = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_magenta"
@JvmField val GLOOMROCK_SMOOTH_WHITE = BlockGloomrockSmoothColored(buildGloomrockSmooth) named "gloomrock_smooth_white"
@JvmField val GLOOMROCK_SMOOTH_RED = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_red"
@JvmField val GLOOMROCK_SMOOTH_ORANGE = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_orange"
@JvmField val GLOOMROCK_SMOOTH_YELLOW = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_yellow"
@JvmField val GLOOMROCK_SMOOTH_GREEN = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_green"
@JvmField val GLOOMROCK_SMOOTH_CYAN = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_cyan"
@JvmField val GLOOMROCK_SMOOTH_BLUE = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_blue"
@JvmField val GLOOMROCK_SMOOTH_PURPLE = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_purple"
@JvmField val GLOOMROCK_SMOOTH_MAGENTA = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_magenta"
@JvmField val GLOOMROCK_SMOOTH_WHITE = BlockGloomrock.SMOOTH_COLORED named "gloomrock_smooth_white"
@JvmField val GLOOMTORCH = BlockGloomtorch(buildGloomtorch) named "gloomtorch"
// Blocks: Building (Dusty Stone)
@@ -215,19 +194,19 @@ object ModBlocks {
@JvmField val OBSIDIAN_STAIRS = BlockStairsCustom(Blocks.OBSIDIAN) named "obsidian_stairs"
@JvmField val OBSIDIAN_FALLING = BlockFallingObsidian(buildObsidian) named "obsidian_falling"
@JvmField val OBSIDIAN_SMOOTH = BlockObsidianCube(buildObsidianVariation) named "obsidian_smooth"
@JvmField val OBSIDIAN_CHISELED = BlockObsidianCube(buildObsidianVariation) named "obsidian_chiseled"
@JvmField val OBSIDIAN_SMOOTH = BlockObsidianCube named "obsidian_smooth"
@JvmField val OBSIDIAN_CHISELED = BlockObsidianCube named "obsidian_chiseled"
@JvmField val OBSIDIAN_PILLAR = BlockObsidianPillar(buildObsidianVariation) named "obsidian_pillar"
@JvmField val OBSIDIAN_SMOOTH_LIT = BlockObsidianCube.Lit(buildObsidianVariationLit, OBSIDIAN_SMOOTH) named "obsidian_smooth_lit"
@JvmField val OBSIDIAN_CHISELED_LIT = BlockObsidianCube.Lit(buildObsidianVariationLit, OBSIDIAN_CHISELED) named "obsidian_chiseled_lit"
@JvmField val OBSIDIAN_SMOOTH_LIT = BlockObsidianCube.Lit(OBSIDIAN_SMOOTH) named "obsidian_smooth_lit"
@JvmField val OBSIDIAN_CHISELED_LIT = BlockObsidianCube.Lit(OBSIDIAN_CHISELED) named "obsidian_chiseled_lit"
@JvmField val OBSIDIAN_PILLAR_LIT = BlockObsidianPillar.Lit(buildObsidianVariationLit, OBSIDIAN_PILLAR) named "obsidian_pillar_lit"
@JvmField val OBSIDIAN_TOWER_TOP = BlockObsidianCube.TowerTop(buildObsidianTowerTop, OBSIDIAN_CHISELED) named "obsidian_tower_top"
@JvmField val OBSIDIAN_TOWER_TOP = BlockObsidianCube.TowerTop(OBSIDIAN_CHISELED) named "obsidian_tower_top"
// Blocks: Building (End Stone)
@JvmField val END_STONE_INFESTED = BlockEndStoneCustom(buildEndStone, MaterialColor.RED) named "end_stone_infested"
@JvmField val END_STONE_BURNED = BlockEndStoneCustom(buildEndStone, MaterialColor.ADOBE /* RENAME ORANGE */) named "end_stone_burned"
@JvmField val END_STONE_ENCHANTED = BlockEndStoneCustom(buildEndStone, MaterialColor.PURPLE) named "end_stone_enchanted"
@JvmField val END_STONE_INFESTED = BlockEndStoneCustom.INFESTED named "end_stone_infested"
@JvmField val END_STONE_BURNED = BlockEndStoneCustom.BURNED named "end_stone_burned"
@JvmField val END_STONE_ENCHANTED = BlockEndStoneCustom.ENCHANTED named "end_stone_enchanted"
// Blocks: Building (Dark Loam)
@@ -243,18 +222,18 @@ object ModBlocks {
// Blocks: Building (Wood)
@JvmField val WHITEBARK_LOG = BlockWhitebarkLog(buildWhitebark) named "whitebark_log"
@JvmField val WHITEBARK = BlockWhitebark(buildWhitebark) named "whitebark"
@JvmField val WHITEBARK_PLANKS = BlockWhitebarkPlanks(buildWhitebarkPlanks) named "whitebark_planks"
@JvmField val WHITEBARK = BlockWhitebark.BARK named "whitebark"
@JvmField val WHITEBARK_PLANKS = BlockWhitebark.PLANKS named "whitebark_planks"
@JvmField val WHITEBARK_STAIRS = BlockFlammableStairs(WHITEBARK_PLANKS) named "whitebark_stairs"
@JvmField val WHITEBARK_SLAB = BlockFlammableSlab(WHITEBARK_PLANKS) named "whitebark_slab"
// Blocks: Building (Miner's Burial)
@JvmField val MINERS_BURIAL_BLOCK_PLAIN = BlockMinersBurialCube(buildMinersBurial) named "miners_burial_block_plain"
@JvmField val MINERS_BURIAL_BLOCK_CHISELED = BlockMinersBurialCube(buildMinersBurial) named "miners_burial_block_chiseled"
@JvmField val MINERS_BURIAL_BLOCK_PLAIN = BlockMinersBurialCube named "miners_burial_block_plain"
@JvmField val MINERS_BURIAL_BLOCK_CHISELED = BlockMinersBurialCube named "miners_burial_block_chiseled"
@JvmField val MINERS_BURIAL_BLOCK_PILLAR = BlockMinersBurialPillar(buildMinersBurial) named "miners_burial_block_pillar"
@JvmField val MINERS_BURIAL_BLOCK_JAIL = BlockMinersBurialCube(buildMinersBurialIndestructible) named "miners_burial_block_jail"
@JvmField val MINERS_BURIAL_ALTAR = BlockMinersBurialAltar(buildMinersBurialIndestructible) named "miners_burial_altar"
@JvmField val MINERS_BURIAL_BLOCK_JAIL = BlockMinersBurialCube.INDESCRUCTIBLE named "miners_burial_block_jail"
@JvmField val MINERS_BURIAL_ALTAR = BlockMinersBurialAltar named "miners_burial_altar"
// Blocks: Fluids
@@ -267,20 +246,20 @@ object ModBlocks {
// Blocks: Interactive (Storage)
@JvmField val JAR_O_DUST = BlockJarODust(buildJarODust) named "jar_o_dust"
@JvmField val JAR_O_DUST = BlockJarODust named "jar_o_dust"
@JvmField val DARK_CHEST = BlockDarkChest(buildGloomrock) named "dark_chest"
@JvmField val LOOT_CHEST = BlockLootChest(buildLootChest) named "loot_chest"
// Blocks: Interactive (Puzzle)
@JvmField val PUZZLE_WALL = BlockPuzzleWall(buildPuzzleWall) named "puzzle_block_wall"
@JvmField val PUZZLE_PLAIN = BlockPuzzleLogic.Plain(buildPuzzleLogic) named "puzzle_block_plain"
@JvmField val PUZZLE_BURST_3 = BlockPuzzleLogic.Burst(buildPuzzleLogic, radius = 1) named "puzzle_block_burst_3"
@JvmField val PUZZLE_BURST_5 = BlockPuzzleLogic.Burst(buildPuzzleLogic, radius = 2) named "puzzle_block_burst_5"
@JvmField val PUZZLE_REDIRECT_1 = BlockPuzzleLogic.RedirectSome.R1(buildPuzzleLogic) named "puzzle_block_redirect_1"
@JvmField val PUZZLE_REDIRECT_2 = BlockPuzzleLogic.RedirectSome.R2(buildPuzzleLogic) named "puzzle_block_redirect_2"
@JvmField val PUZZLE_REDIRECT_4 = BlockPuzzleLogic.RedirectAll(buildPuzzleLogic) named "puzzle_block_redirect_4"
@JvmField val PUZZLE_TELEPORT = BlockPuzzleLogic.Teleport(buildPuzzleLogic) named "puzzle_block_teleport"
@JvmField val PUZZLE_WALL = BlockPuzzleWall named "puzzle_block_wall"
@JvmField val PUZZLE_PLAIN = BlockPuzzleLogic.Plain named "puzzle_block_plain"
@JvmField val PUZZLE_BURST_3 = BlockPuzzleLogic.Burst(radius = 1) named "puzzle_block_burst_3"
@JvmField val PUZZLE_BURST_5 = BlockPuzzleLogic.Burst(radius = 2) named "puzzle_block_burst_5"
@JvmField val PUZZLE_REDIRECT_1 = BlockPuzzleLogic.RedirectOne named "puzzle_block_redirect_1"
@JvmField val PUZZLE_REDIRECT_2 = BlockPuzzleLogic.RedirectTwo named "puzzle_block_redirect_2"
@JvmField val PUZZLE_REDIRECT_4 = BlockPuzzleLogic.RedirectAll named "puzzle_block_redirect_4"
@JvmField val PUZZLE_TELEPORT = BlockPuzzleLogic.Teleport named "puzzle_block_teleport"
// Blocks: Interactive (Gates)
@@ -290,14 +269,14 @@ object ModBlocks {
// Blocks: Interactive (Uncategorized)
@JvmField val INFUSED_TNT = BlockInfusedTNT() named "infused_tnt"
@JvmField val IGNEOUS_PLATE = BlockIgneousPlate(buildIgneousPlate) named "igneous_plate"
@JvmField val IGNEOUS_PLATE = BlockIgneousPlate named "igneous_plate"
@JvmField val ENHANCED_BREWING_STAND = BlockBrewingStandCustom(buildBrewingStand) named "enhanced_brewing_stand"
// Blocks: Ores
@JvmField val END_POWDER_ORE = BlockEndPowderOre(buildEndPowderOre) named "end_powder_ore"
@JvmField val ENDIUM_ORE = BlockEndium.Ore(buildEndiumOre) named "endium_ore"
@JvmField val STARDUST_ORE = BlockStardustOre(buildStardustOre) named "stardust_ore"
@JvmField val END_POWDER_ORE = BlockEndPowderOre named "end_powder_ore"
@JvmField val ENDIUM_ORE = BlockEndium.Ore named "endium_ore"
@JvmField val STARDUST_ORE = BlockStardustOre named "stardust_ore"
@JvmField val IGNEOUS_ROCK_ORE = BlockIgneousRockOre(buildIgneousRockOre) named "igneous_rock_ore"
// Blocks: Decorative (Trees)
@@ -340,21 +319,21 @@ object ModBlocks {
// Blocks: Portals
@JvmField val END_PORTAL_INNER = BlockEndPortalInner(buildPortalInner) named "end_portal_inner"
@JvmField val END_PORTAL_FRAME = BlockPortalFrame(buildPortalFrame) named "end_portal_frame"
@JvmField val END_PORTAL_ACCEPTOR = BlockEndPortalAcceptor(buildPortalFrame) named "end_portal_acceptor"
@JvmField val END_PORTAL_INNER = BlockEndPortalInner named "end_portal_inner"
@JvmField val END_PORTAL_FRAME = BlockPortalFrameIndestructible named "end_portal_frame"
@JvmField val END_PORTAL_ACCEPTOR = BlockEndPortalAcceptor named "end_portal_acceptor"
@JvmField val VOID_PORTAL_INNER = BlockVoidPortalInner(buildPortalInner) named "void_portal_inner"
@JvmField val VOID_PORTAL_FRAME = BlockPortalFrame(buildPortalFrame) named "void_portal_frame"
@JvmField val VOID_PORTAL_STORAGE = BlockVoidPortalStorage(buildPortalFrame) named "void_portal_storage"
@JvmField val VOID_PORTAL_INNER = BlockVoidPortalInner named "void_portal_inner"
@JvmField val VOID_PORTAL_FRAME = BlockVoidPortalFrame.Indestructible named "void_portal_frame"
@JvmField val VOID_PORTAL_STORAGE = BlockVoidPortalStorage.Indestructible named "void_portal_storage"
@JvmField val VOID_PORTAL_FRAME_CRAFTED = BlockVoidPortalCrafted(buildPortalFrameCrafted) named "void_portal_frame_crafted"
@JvmField val VOID_PORTAL_STORAGE_CRAFTED = BlockVoidPortalStorageCrafted(buildPortalFrameCrafted) named "void_portal_storage_crafted"
@JvmField val VOID_PORTAL_FRAME_CRAFTED = BlockVoidPortalFrame.Crafted named "void_portal_frame_crafted"
@JvmField val VOID_PORTAL_STORAGE_CRAFTED = BlockVoidPortalStorage.Crafted named "void_portal_storage_crafted"
// Blocks: Energy
@JvmField val ENERGY_CLUSTER = BlockEnergyCluster(buildEnergyCluster) named "energy_cluster"
@JvmField val CORRUPTED_ENERGY = BlockCorruptedEnergy(buildCorruptedEnergy) named "corrupted_energy"
@JvmField val CORRUPTED_ENERGY = BlockCorruptedEnergy named "corrupted_energy"
// Blocks: Tables
@@ -375,7 +354,7 @@ object ModBlocks {
// Blocks: Utilities
@JvmField val ETERNAL_FIRE = BlockEternalFire(buildEternalFire) named "eternal_fire"
@JvmField val SCAFFOLDING = BlockScaffolding.create(buildScaffolding) named "scaffolding"
@JvmField val SCAFFOLDING = BlockScaffolding named "scaffolding"
// Registry
@@ -586,6 +565,10 @@ object ModBlocks {
private val temporaryItemBlocks = mutableListOf<BlockItem>()
private val overrideBlocks = mutableListOf<Block>()
private infix fun HeeBlockBuilder.named(registryName: String): HeeBlock2 {
return this.build() named registryName
}
private inline fun Block.override(vanillaBlock: Block, itemBlockConstructor: ((Block) -> BlockItem?)) = apply {
this.useVanillaName(vanillaBlock)
overrideBlocks.add(this)

View File

@@ -0,0 +1,15 @@
package chylex.hee.init
import chylex.hee.game.Resource
import net.minecraft.block.Block
import net.minecraft.tags.BlockTags
import net.minecraft.tags.ITag.INamedTag
object ModTags {
@JvmField val GLOOMROCK_PARTICLES = tag("gloomrock_particles")
@JvmField val VOID_PORTAL_FRAME_CRAFTED = tag("void_portal_frame_crafted")
private fun tag(name: String): INamedTag<Block> {
return BlockTags.createOptional(Resource.Custom(name))
}
}

View File

@@ -1,5 +1,6 @@
package chylex.hee.mixin;
import chylex.hee.game.block.interfaces.IBlockWithInterfaces;
import chylex.hee.game.block.logic.IBlockDynamicHardness;
import net.minecraft.block.AbstractBlock.AbstractBlockState;
import net.minecraft.block.Block;
@@ -19,8 +20,13 @@ public abstract class HookBlockHardness {
final BlockState state = world.getBlockState(pos);
final Block block = state.getBlock();
if (block instanceof IBlockDynamicHardness) {
ci.setReturnValue(Float.valueOf(((IBlockDynamicHardness)block).getBlockHardness(world, pos, state, ci.getReturnValueF())));
if (block instanceof IBlockWithInterfaces) {
final IBlockWithInterfaces blockWithInterfaces = (IBlockWithInterfaces)block;
final IBlockDynamicHardness dynamicHardness = (IBlockDynamicHardness)blockWithInterfaces.getInterface(IBlockDynamicHardness.class);
if (dynamicHardness != null) {
ci.setReturnValue(Float.valueOf(dynamicHardness.getBlockHardness(world, pos, state, ci.getReturnValueF())));
}
}
}
}