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

4 Commits

145 changed files with 1555 additions and 2533 deletions

View File

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

View File

@@ -580,8 +580,6 @@ e66091a13a6e7593eb5bd971978d24a5a0e375b3 data/hee/loot_tables/blocks/whitebark.j
9bd3a9e24162d2c81047b834f8f79d6cabec86be data/hee/loot_tables/blocks/whitebark_planks.json 9bd3a9e24162d2c81047b834f8f79d6cabec86be data/hee/loot_tables/blocks/whitebark_planks.json
7d84dc443a052e349593b71d2c0a523e75396cdf data/hee/loot_tables/blocks/whitebark_slab.json 7d84dc443a052e349593b71d2c0a523e75396cdf data/hee/loot_tables/blocks/whitebark_slab.json
83e0b81adb3f9dd488397e8459b95f7b0ce19927 data/hee/loot_tables/blocks/whitebark_stairs.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 f5996244831ab38fe1fae2f304bbd7825d6ad98b data/minecraft/tags/blocks/bamboo_plantable_on.json
479189f9b35a3c8f795539daf6a1809130242c5b data/minecraft/tags/blocks/flower_pots.json 479189f9b35a3c8f795539daf6a1809130242c5b data/minecraft/tags/blocks/flower_pots.json
424e2e03cf62f23f4496468a97b9f0df060df9fe data/minecraft/tags/blocks/impermeable.json 424e2e03cf62f23f4496468a97b9f0df060df9fe data/minecraft/tags/blocks/impermeable.json

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,8 @@ import chylex.hee.client.DebugMenu
import chylex.hee.client.GameModeToggle import chylex.hee.client.GameModeToggle
import chylex.hee.client.TerritoryVoidDebug import chylex.hee.client.TerritoryVoidDebug
import chylex.hee.game.block.BlockScaffoldingDebug 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.CommandClientDebugToggles
import chylex.hee.game.command.client.CommandClientScaffolding import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.command.server.CommandServerInstability import chylex.hee.game.command.server.CommandServerInstability
@@ -43,8 +45,9 @@ internal object Debug : IDebugModule {
CommandServerTestWorld CommandServerTestWorld
) )
override val scaffoldingBlockBehavior override fun createScaffoldingBlock(builder: BlockBuilder): HeeBlock {
get() = BlockScaffoldingDebug return BlockScaffoldingDebug(builder)
}
@SubscribeEvent @SubscribeEvent
fun onClientSetup(@Suppress("UNUSED_PARAMETER") e: FMLClientSetupEvent) { 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.debug.PowerShell
import chylex.hee.game.Environment import chylex.hee.game.Environment
import chylex.hee.game.block.components.IPlayerUseBlockComponent import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.command.client.CommandClientScaffolding import chylex.hee.game.command.client.CommandClientScaffolding
import chylex.hee.game.world.generation.structure.file.StructureFile import chylex.hee.game.world.generation.structure.file.StructureFile
import chylex.hee.game.world.generation.util.WorldToStructureWorldAdapter import chylex.hee.game.world.generation.util.WorldToStructureWorldAdapter
@@ -27,13 +27,14 @@ import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand import net.minecraft.util.Hand
import net.minecraft.util.Util import net.minecraft.util.Util
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.text.StringTextComponent import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TextFormatting import net.minecraft.util.text.TextFormatting
import net.minecraft.world.World import net.minecraft.world.World
import java.nio.file.Files import java.nio.file.Files
object BlockScaffoldingDebug : IPlayerUseBlockComponent { class BlockScaffoldingDebug(builder: BlockBuilder) : BlockScaffolding(builder) {
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType { override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (world.isRemote && player.isSneaking && !player.abilities.isFlying) { if (world.isRemote && player.isSneaking && !player.abilities.isFlying) {
val palette = CommandClientScaffolding.currentPalette val palette = CommandClientScaffolding.currentPalette
@@ -53,7 +54,7 @@ object BlockScaffoldingDebug : IPlayerUseBlockComponent {
val box = BoundingBox(minPos, maxPos) val box = BoundingBox(minPos, maxPos)
val serverWorld = Environment.getDimension(world.dimensionKey) val serverWorld = Environment.getDimension(world.dimensionKey)
val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, state.block) val (structureTag, missingMappings) = StructureFile.save(WorldToStructureWorldAdapter(serverWorld, serverWorld.rand, box.min), box.size, palette, this)
val structureFile = Files.createTempDirectory("HardcoreEnderExpansion_Structure_").resolve(CommandClientScaffolding.currentFile).toFile() val structureFile = Files.createTempDirectory("HardcoreEnderExpansion_Structure_").resolve(CommandClientScaffolding.currentFile).toFile()
CompressedStreamTools.write(structureTag, structureFile) 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.block.Block
import net.minecraft.loot.LootTables import net.minecraft.loot.LootTables
open class HeeBlock(builder: BlockBuilder) : Block(builder.p), IHeeBlock { // TODO abstract open class HeeBlock(builder: BlockBuilder) : Block(builder.p), IHeeBlock {
override val drop override val drop
get() = if (lootTable == LootTables.EMPTY) BlockDrop.Nothing else BlockDrop.Self get() = if (lootTable == LootTables.EMPTY) BlockDrop.Nothing else BlockDrop.Self
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
package chylex.hee.client.render.block package chylex.hee.client.render.block
import chylex.hee.game.block.BlockAbstractPortal 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.ITerritoryInstanceFactory
import chylex.hee.game.block.BlockVoidPortalInner.IVoidPortalController 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.HUB
import chylex.hee.game.block.BlockVoidPortalInner.Type.RETURN_ACTIVE import chylex.hee.game.block.BlockVoidPortalInner.Type.RETURN_ACTIVE
import chylex.hee.game.block.entity.TileEntityPortalInner import chylex.hee.game.block.entity.TileEntityPortalInner

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,53 +1,56 @@
package chylex.hee.game.block 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.entity.TileEntityEndPortalAcceptor
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockModel import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.world.util.getTile import chylex.hee.game.world.util.getTile
import chylex.hee.init.ModBlocks import chylex.hee.init.ModBlocks
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.PASS import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.Hand import net.minecraft.util.Hand
import net.minecraft.util.math.BlockPos 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 import net.minecraft.world.World
object BlockEndPortalAcceptor : HeeBlockBuilder() { class BlockEndPortalAcceptor(builder: BlockBuilder) : BlockPortalFrame(builder) {
init { override val model
includeFrom(BlockPortalFrameIndestructible) get() = BlockModel.PortalFrame(ModBlocks.END_PORTAL_FRAME, "acceptor")
model = BlockModel.PortalFrame(ModBlocks.END_PORTAL_FRAME, "acceptor") override fun hasTileEntity(state: BlockState): Boolean {
return true
components.entity = IBlockEntityComponent(::TileEntityEndPortalAcceptor) }
components.onAdded = IBlockAddedComponent { _, world, pos -> override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.END_PORTAL_FRAME, ModBlocks.END_PORTAL_INNER, minSize = 1) return TileEntityEndPortalAcceptor()
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
BlockAbstractPortal.spawnInnerBlocks(world, pos, ModBlocks.END_PORTAL_FRAME, ModBlocks.END_PORTAL_INNER, minSize = 1)
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
if (player.isCreative && player.isSneaking) {
pos.getTile<TileEntityEndPortalAcceptor>(world)?.toggleChargeFromCreativeMode()
return SUCCESS
} }
components.setStateFromNeighbor = ISetBlockStateFromNeighbor { state, world, pos, neighborFacing, _ -> return PASS
if (!world.isRemote && neighborFacing == UP) { }
pos.getTile<TileEntityEndPortalAcceptor>(world)?.refreshClusterState()
} // TODO neighbor changed? override fun updatePostPlacement(state: BlockState, facing: Direction, neighborState: BlockState, world: IWorld, pos: BlockPos, neighborPos: BlockPos): BlockState {
if (!world.isRemote && facing == UP) {
state pos.getTile<TileEntityEndPortalAcceptor>(world)?.refreshClusterState()
} }
components.playerUse = object : IPlayerUseBlockComponent { @Suppress("DEPRECATION")
override fun use(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): ActionResultType { return super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
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 package chylex.hee.game.block
import chylex.hee.HEE 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.TileEntityEndPortalAcceptor
import chylex.hee.game.block.entity.TileEntityPortalInner 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.CausatumStage
import chylex.hee.game.mechanics.causatum.EnderCausatum import chylex.hee.game.mechanics.causatum.EnderCausatum
import chylex.hee.game.world.isEndDimension import chylex.hee.game.world.isEndDimension
@@ -12,39 +12,41 @@ import chylex.hee.game.world.server.DimensionTeleporter
import chylex.hee.game.world.util.closestTickingTile import chylex.hee.game.world.util.closestTickingTile
import chylex.hee.init.ModBlocks import chylex.hee.init.ModBlocks
import chylex.hee.util.math.Pos import chylex.hee.util.math.Pos
import net.minecraft.block.BlockState
import net.minecraft.entity.Entity import net.minecraft.entity.Entity
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.tileentity.TileEntity import net.minecraft.tileentity.TileEntity
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.World import net.minecraft.world.World
object BlockEndPortalInner : HeeBlockBuilder() { class BlockEndPortalInner(builder: BlockBuilder) : BlockAbstractPortal(builder) {
init { override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
includeFrom(BlockAbstractPortal(object : IInnerPortalBlock { return TileEntityPortalInner.End()
override fun createTileEntity(): TileEntity { }
return TileEntityPortalInner.End()
} override fun onEntityInside(world: World, pos: BlockPos, entity: Entity) {
if (!EntityPortalContact.shouldTeleport(entity)) {
return
}
if (world.isEndDimension) {
DimensionTeleporter.changeDimension(entity, World.OVERWORLD, DimensionTeleporter.LastEndPortal)
}
else {
val acceptor = pos.closestTickingTile<TileEntityEndPortalAcceptor>(world, MAX_DISTANCE_FROM_FRAME)
override fun teleportEntity(world: World, pos: BlockPos, entity: Entity) { if (acceptor != null && acceptor.isCharged) {
if (world.isEndDimension) { findInnerArea(world, acceptor.pos, ModBlocks.END_PORTAL_FRAME)?.let { (min, max) ->
DimensionTeleporter.changeDimension(entity, World.OVERWORLD, DimensionTeleporter.LastEndPortal) DimensionTeleporter.LastEndPortal.updateForEntity(entity, Pos((min.x + max.x) / 2, pos.y, (min.z + max.z) / 2))
} }
else {
val acceptor = pos.closestTickingTile<TileEntityEndPortalAcceptor>(world, BlockAbstractPortal.MAX_DISTANCE_FROM_FRAME) if (entity is PlayerEntity) {
EnderCausatum.triggerStage(entity, CausatumStage.S2_ENTERED_END)
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)
}
} }
DimensionTeleporter.changeDimension(entity, HEE.dim, DimensionTeleporter.EndSpawnPortal)
} }
})) }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,37 +1,31 @@
package chylex.hee.game.block package chylex.hee.game.block
import chylex.hee.game.Resource.location 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.entity.TileEntityIgneousPlate
import chylex.hee.game.block.logic.IBlockDynamicHardness 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.BlockModel
import chylex.hee.game.block.properties.BlockStateModel import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset 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.FURNACE_FACING
import chylex.hee.game.block.util.Property 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.entity.technical.EntityTechnicalIgneousPlateLogic
import chylex.hee.game.item.properties.ItemModel import chylex.hee.game.item.properties.ItemModel
import chylex.hee.game.world.util.Facing6 import chylex.hee.game.world.util.Facing6
import chylex.hee.game.world.util.getState import chylex.hee.game.world.util.getState
import chylex.hee.game.world.util.getTile import chylex.hee.game.world.util.getTile
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType.ENTITYBLOCK_ANIMATED import net.minecraft.block.BlockRenderType.ENTITYBLOCK_ANIMATED
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks 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.entity.player.PlayerEntity
import net.minecraft.item.BlockItemUseContext import net.minecraft.item.BlockItemUseContext
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.Items import net.minecraft.item.Items
import net.minecraft.state.StateContainer.Builder
import net.minecraft.tileentity.FurnaceTileEntity import net.minecraft.tileentity.FurnaceTileEntity
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.ActionResultType import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.PASS import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS import net.minecraft.util.ActionResultType.SUCCESS
@@ -43,114 +37,139 @@ import net.minecraft.util.Direction.SOUTH
import net.minecraft.util.Direction.UP import net.minecraft.util.Direction.UP
import net.minecraft.util.Direction.WEST import net.minecraft.util.Direction.WEST
import net.minecraft.util.Hand 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.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.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader import net.minecraft.world.IWorldReader
import net.minecraft.world.World import net.minecraft.world.World
object BlockIgneousPlate : HeeBlockBuilder() { class BlockIgneousPlate(builder: BlockBuilder) : HeeBlock(builder), IBlockDynamicHardness {
val FACING_NOT_DOWN = Property.facing("facing", Facing6.minusElement(DOWN)) companion object {
val FACING_NOT_DOWN = Property.facing("facing", Facing6.minusElement(DOWN))
private const val BB_SIDE_MIN = 0.125
private const val BB_SIDE_MAX = 0.875
private const val BB_TOP = 0.125
private val BOUNDING_BOX = mapOf(
UP to AxisAlignedBB(BB_SIDE_MIN, 0.0, BB_SIDE_MIN, BB_SIDE_MAX, BB_TOP, BB_SIDE_MAX).asVoxelShape,
NORTH to AxisAlignedBB(BB_SIDE_MIN, BB_SIDE_MIN, 1.0 - BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX, 1.0).asVoxelShape,
SOUTH to AxisAlignedBB(BB_SIDE_MIN, BB_SIDE_MIN, 0.0, BB_SIDE_MAX, BB_SIDE_MAX, BB_TOP).asVoxelShape,
EAST to AxisAlignedBB(0.0, BB_SIDE_MIN, BB_SIDE_MIN, BB_TOP, BB_SIDE_MAX, BB_SIDE_MAX).asVoxelShape,
WEST to AxisAlignedBB(1.0 - BB_TOP, BB_SIDE_MIN, BB_SIDE_MIN, 1.0, BB_SIDE_MAX, BB_SIDE_MAX).asVoxelShape
)
private fun canPlacePlateAt(world: IWorldReader, pos: BlockPos, facing: Direction): Boolean {
val furnacePos = pos.offset(facing.opposite)
val state = furnacePos.getState(world)
return (
state.properties.contains(FURNACE_FACING) &&
state[FURNACE_FACING] != facing &&
furnacePos.getTile<FurnaceTileEntity>(world) != null
)
}
}
private const val BB_SIDE_MIN = 0.125 override val model
private const val BB_SIDE_MAX = 0.875 get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(this.location), ItemModel.Simple)
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 { init {
model = IBlockStateModelSupplier { defaultState = stateContainer.baseState.with(FACING_NOT_DOWN, UP)
BlockStateModel(BlockStatePreset.Simple, BlockModel.ParticleOnly(it.location), ItemModel.Simple) }
override fun fillStateContainer(container: Builder<Block, BlockState>) {
container.add(FACING_NOT_DOWN)
}
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityIgneousPlate()
}
// Placement rules
override fun isValidPosition(state: BlockState, world: IWorldReader, pos: BlockPos): Boolean {
return FACING_NOT_DOWN.allowedValues.any { canPlacePlateAt(world, pos, it) }
}
override fun getStateForPlacement(context: BlockItemUseContext): BlockState {
val world = context.world
val pos = context.pos
val facing = context.face
return if (canPlacePlateAt(world, pos, facing))
defaultState.with(FACING_NOT_DOWN, facing)
else
FACING_NOT_DOWN.allowedValues.firstOrNull { canPlacePlateAt(world, pos, it) }?.let { defaultState.with(FACING_NOT_DOWN, it) } ?: defaultState
}
override fun onBlockAdded(state: BlockState, world: World, pos: BlockPos, oldState: BlockState, isMoving: Boolean) {
pos.offset(state[FACING_NOT_DOWN].opposite).getTile<FurnaceTileEntity>(world)?.let(EntityTechnicalIgneousPlateLogic.Companion::createForFurnace)
}
override fun updatePostPlacement(state: BlockState, facing: Direction, neighborState: BlockState, world: IWorld, pos: BlockPos, neighborPos: BlockPos): BlockState {
@Suppress("DEPRECATION")
return if (!canPlacePlateAt(world, pos, state[FACING_NOT_DOWN]))
Blocks.AIR.defaultState
else
super.updatePostPlacement(state, facing, neighborState, world, pos, neighborPos)
}
// Interactions
override fun getBlockHardness(world: IBlockReader, pos: BlockPos, state: BlockState, originalHardness: Float): Float {
val tile = pos.getTile<TileEntityIgneousPlate>(world) ?: return 0F
return when {
tile.isOverheating -> 10F
tile.isWorking -> 4F
else -> 0F
} }
}
override fun onBlockActivated(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockRayTraceResult): ActionResultType {
val heldItem = player.getHeldItem(hand)
material = Materials.IGNEOUS_ROCK_PLATE if (heldItem.item === Items.WATER_BUCKET) {
color = MaterialColor.AIR if (!world.isRemote && tryCoolPlate(world, pos, state) && !player.abilities.isCreativeMode) {
sound = SoundType.STONE player.setHeldItem(hand, ItemStack(Items.BUCKET))
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) }
} }
override fun getPlacedState(defaultState: BlockState, world: World, pos: BlockPos, context: BlockItemUseContext): BlockState { return SUCCESS
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
}
} }
components.onAdded = IBlockAddedComponent { state, world, pos -> return PASS
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 { 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 return pos.offset(state[FACING_NOT_DOWN].opposite).getTile<FurnaceTileEntity>(world)?.let(EntityTechnicalIgneousPlateLogic.Companion::triggerCooling) == true
} }
private fun canPlacePlateAt(world: IWorldReader, pos: BlockPos, facing: Direction): Boolean { // State handling
val furnacePos = pos.offset(facing.opposite)
val state = furnacePos.getState(world) override fun rotate(state: BlockState, rot: Rotation): BlockState {
return state.with(FACING_NOT_DOWN, rot.rotate(state[FACING_NOT_DOWN]))
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,24 +1,14 @@
package chylex.hee.game.block package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy 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.entity.TileEntityJarODust
import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.properties.BlockDrop 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.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.TRANSLUCENT import chylex.hee.game.block.properties.BlockRenderLayer.TRANSLUCENT
import chylex.hee.game.block.properties.BlockStateModel import chylex.hee.game.block.properties.BlockStateModel
import chylex.hee.game.block.properties.BlockStatePreset 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.fx.util.playServer
import chylex.hee.game.item.components.ITooltipComponent
import chylex.hee.game.item.util.size import chylex.hee.game.item.util.size
import chylex.hee.game.mechanics.dust.DustLayers import chylex.hee.game.mechanics.dust.DustLayers
import chylex.hee.game.mechanics.dust.DustLayers.Side.BOTTOM import chylex.hee.game.mechanics.dust.DustLayers.Side.BOTTOM
@@ -26,165 +16,164 @@ import chylex.hee.game.mechanics.dust.DustLayers.Side.TOP
import chylex.hee.game.mechanics.dust.DustType import chylex.hee.game.mechanics.dust.DustType
import chylex.hee.game.world.util.getTile import chylex.hee.game.world.util.getTile
import chylex.hee.game.world.util.isTopSolid import chylex.hee.game.world.util.isTopSolid
import chylex.hee.init.ModBlocks
import chylex.hee.init.ModSounds import chylex.hee.init.ModSounds
import chylex.hee.system.heeTag import chylex.hee.system.heeTag
import chylex.hee.system.heeTagOrNull 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.math.center
import chylex.hee.util.nbt.getListOfCompounds import chylex.hee.util.nbt.getListOfCompounds
import chylex.hee.util.nbt.putList import chylex.hee.util.nbt.putList
import net.minecraft.block.Block
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.Blocks import net.minecraft.block.Blocks
import net.minecraft.block.SoundType import net.minecraft.client.util.ITooltipFlag
import net.minecraft.block.material.MaterialColor
import net.minecraft.entity.LivingEntity import net.minecraft.entity.LivingEntity
import net.minecraft.entity.player.PlayerEntity import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.loot.LootContext.Builder import net.minecraft.loot.LootContext
import net.minecraft.loot.LootParameters 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.PASS
import net.minecraft.util.ActionResultType.SUCCESS import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.Direction
import net.minecraft.util.Direction.DOWN import net.minecraft.util.Direction.DOWN
import net.minecraft.util.Hand import net.minecraft.util.Hand
import net.minecraft.util.SoundCategory import net.minecraft.util.SoundCategory
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.shapes.VoxelShapes import net.minecraft.util.math.BlockRayTraceResult
import net.minecraft.util.math.RayTraceResult
import net.minecraft.util.text.ITextComponent import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.Explosion import net.minecraft.world.Explosion
import net.minecraft.world.IBlockReader import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorld
import net.minecraft.world.IWorldReader import net.minecraft.world.IWorldReader
import net.minecraft.world.World import net.minecraft.world.World
object BlockJarODust : HeeBlockBuilder() { class BlockJarODust(builder: BlockBuilder) : BlockSimpleShaped(builder, AABB) {
init { companion object {
localization = LocalizationStrategy.ReplaceWords("O", "o'") val AABB = AxisAlignedBB(0.1875, 0.0, 0.1875, 0.8125, 0.84375, 0.8125)
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)
}
}
} }
// ItemStack override val localization
get() = LocalizationStrategy.ReplaceWords("O", "o'")
override val localizationExtra
get() = mapOf("block.hee.jar_o_dust.tooltip.entry" to "§7%sx %s")
override val model
get() = BlockStateModel(BlockStatePreset.Simple, BlockModel.Manual)
override val renderLayer
get() = TRANSLUCENT
override val drop
get() = BlockDrop.Manual
override fun hasTileEntity(state: BlockState): Boolean {
return true
}
override fun createTileEntity(state: BlockState, world: IBlockReader): TileEntity {
return TileEntityJarODust()
}
// ItemStack serialization
fun getLayersFromStack(stack: ItemStack): DustLayers? { fun getLayersFromStack(stack: ItemStack): DustLayers? {
return if (stack.item === ModBlocks.JAR_O_DUST.asItem()) return if (stack.item === this.asItem())
stack.heeTagOrNull?.getListOfCompounds(TileEntityJarODust.LAYERS_TAG)?.let { list -> DustLayers(TileEntityJarODust.DUST_CAPACITY).apply { deserializeNBT(list) } } stack.heeTagOrNull?.getListOfCompounds(TileEntityJarODust.LAYERS_TAG)?.let { list -> DustLayers(TileEntityJarODust.DUST_CAPACITY).apply { deserializeNBT(list) } }
else else
null null
} }
fun setLayersInStack(stack: ItemStack, layers: DustLayers) { fun setLayersInStack(stack: ItemStack, layers: DustLayers) {
if (stack.item === ModBlocks.JAR_O_DUST.asItem()) { if (stack.item === this.asItem()) {
stack.heeTag.putList(TileEntityJarODust.LAYERS_TAG, layers.serializeNBT()) 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 // Drops
private fun getDrop(tile: TileEntityJarODust): ItemStack { private fun getDrop(tile: TileEntityJarODust): ItemStack {
return ItemStack(ModBlocks.JAR_O_DUST).also { setLayersInStack(it, tile.layers) } return ItemStack(this).also { setLayersInStack(it, tile.layers) }
}
override fun getDrops(state: BlockState, context: LootContext.Builder): MutableList<ItemStack> {
val drop = (context.get(LootParameters.BLOCK_ENTITY) as? TileEntityJarODust)?.let(::getDrop)
return if (drop != null)
mutableListOf(drop)
else
mutableListOf()
}
override fun getPickBlock(state: BlockState, target: RayTraceResult, world: IBlockReader, pos: BlockPos, player: PlayerEntity): ItemStack {
return pos.getTile<TileEntityJarODust>(world)?.let(::getDrop) ?: ItemStack(this)
}
override fun canDropFromExplosion(explosion: Explosion): Boolean {
return false
}
override fun onBlockExploded(state: BlockState, world: World, pos: BlockPos, explosion: Explosion) {
pos.getTile<TileEntityJarODust>(world)?.let {
val layers = it.layers
repeat(layers.contents.size) {
spawnAsEntity(world, pos, layers.removeDust(BOTTOM))
}
}
ModSounds.BLOCK_JAR_O_DUST_SHATTER.playServer(world, pos.center, SoundCategory.BLOCKS)
super.onBlockExploded(state, world, pos, explosion)
} }
// Interaction // 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 { private fun tryExtractDust(world: World, pos: BlockPos, player: PlayerEntity, hand: Hand): Boolean {
if (world.isRemote) { if (world.isRemote) {
return true return true
} }
val removed = pos.getTile<TileEntityJarODust>(world)?.layers?.removeDust(if (player.isSneaking) BOTTOM else TOP) val removed = pos.getTile<TileEntityJarODust>(world)?.layers?.removeDust(if (player.isSneaking) BOTTOM else TOP)
if (removed != null) { if (removed != null) {
player.setHeldItem(hand, removed) player.setHeldItem(hand, removed)
} }
@@ -208,4 +197,23 @@ object BlockJarODust : HeeBlockBuilder() {
return true return true
} }
// Client side
@Sided(Side.CLIENT)
override fun addInformation(stack: ItemStack, world: IBlockReader?, lines: MutableList<ITextComponent>, flags: ITooltipFlag) {
val contents = getLayersFromStack(stack)?.contents
if (contents != null) {
val entries = contents
.groupingBy { it.first }
.fold(0) { acc, entry -> acc + entry.second }
.entries
.sortedWith(compareBy({ -it.value }, { it.key.key }))
for ((dustType, dustAmount) in entries) {
lines.add(TranslationTextComponent("block.hee.jar_o_dust.tooltip.entry", dustAmount, TranslationTextComponent(dustType.item.translationKey)))
}
}
}
} }

View File

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

View File

@@ -1,29 +1,9 @@
package chylex.hee.game.block package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder import chylex.hee.game.block.properties.BlockBuilder
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
object BlockMinersBurialCube : HeeBlockBuilder() { class BlockMinersBurialCube(builder: BlockBuilder) : HeeBlock(builder) {
init { override val localization
localization = LocalizationStrategy.Parenthesized(LocalizationStrategy.DeleteWords(LocalizationStrategy.ReplaceWords("Miners", "Miner's"), "Plain"), wordCount = 1, wordOffset = 3, fromStart = true) get() = 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,50 +1,28 @@
package chylex.hee.game.block package chylex.hee.game.block
import chylex.hee.client.text.LocalizationStrategy import chylex.hee.client.text.LocalizationStrategy
import chylex.hee.game.block.builder.HeeBlockBuilder import chylex.hee.game.block.properties.BlockBuilder
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.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.Block
import net.minecraft.block.SoundType
import net.minecraft.block.material.MaterialColor
import net.minecraftforge.common.Tags import net.minecraftforge.common.Tags
import net.minecraftforge.common.ToolType.PICKAXE
object BlockObsidianCube : HeeBlockBuilder() { open class BlockObsidianCube(builder: BlockBuilder) : HeeBlock(builder) {
private val DEFAULT_LOCALIZATION = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true) override val localization: LocalizationStrategy
get() = LocalizationStrategy.MoveToBeginning(wordCount = 1, wordOffset = 1, fromStart = true)
init { final override val tags
localization = DEFAULT_LOCALIZATION get() = listOf(Tags.Blocks.OBSIDIAN)
open class Lit(builder: BlockBuilder, private val modelBlock: Block) : BlockObsidianCube(builder) {
override val localization: LocalizationStrategy
get() = LocalizationStrategy.Parenthesized(super.localization, wordCount = 1, fromStart = false)
tags.add(Tags.Blocks.OBSIDIAN) override val model
get() = BlockStateModels.Cube(modelBlock)
material = Materials.SOLID
color = MaterialColor.BLACK
sound = SoundType.STONE
tool = BlockHarvestTool.required(DIAMOND, PICKAXE)
hardness = BlockHardness(hardness = 20F, resistance = 300F)
} }
class Lit(modelBlock: Block) : HeeBlockBuilder() { class TowerTop(builder: BlockBuilder, modelBlock: Block) : Lit(builder, modelBlock) {
init { override val localization
includeFrom(BlockObsidianCube) get() = LocalizationStrategy.Default
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

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

View File

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

View File

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

View File

@@ -2,55 +2,62 @@ package chylex.hee.game.block
import chylex.hee.HEE import chylex.hee.HEE
import chylex.hee.game.Environment import chylex.hee.game.Environment
import chylex.hee.game.block.builder.HeeBlockBuilder import chylex.hee.game.block.properties.BlockBuilder
import chylex.hee.game.block.components.IBlockShapeComponent
import chylex.hee.game.block.properties.BlockModel import chylex.hee.game.block.properties.BlockModel
import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT import chylex.hee.game.block.properties.BlockRenderLayer.CUTOUT
import chylex.hee.game.block.properties.Materials import chylex.hee.util.forge.Side
import chylex.hee.util.forge.Sided
import net.minecraft.block.BlockState import net.minecraft.block.BlockState
import net.minecraft.block.SoundType import net.minecraft.util.math.BlockPos
import net.minecraft.block.material.MaterialColor import net.minecraft.util.math.shapes.ISelectionContext
import net.minecraft.util.math.shapes.VoxelShape import net.minecraft.util.math.shapes.VoxelShape
import net.minecraft.util.math.shapes.VoxelShapes import net.minecraft.util.math.shapes.VoxelShapes
import net.minecraft.world.IBlockReader
object BlockScaffolding : HeeBlockBuilder() { open class BlockScaffolding protected constructor(builder: BlockBuilder) : HeeBlock(builder) {
var enableShape = true companion object {
var enableShape = true
init {
includeFrom(BlockIndestructible)
model = BlockModel.Manual fun create(builder: BlockBuilder): HeeBlock {
renderLayer = CUTOUT return HEE.debugModule?.createScaffoldingBlock(builder) ?: BlockScaffolding(builder)
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()
components.ambientOcclusionValue = 1F return if ((player == null || !player.abilities.isFlying) && enableShape)
VoxelShapes.fullCube()
else
VoxelShapes.empty()
}
override fun getRaytraceShape(state: BlockState, world: IBlockReader, pos: BlockPos): VoxelShape {
val player = Environment.getClientSidePlayer()
components.playerUse = HEE.debugModule?.scaffoldingBlockBehavior return if ((player == null || player.isSneaking || player.abilities.isFlying) && enableShape)
VoxelShapes.fullCube()
else
VoxelShapes.empty()
}
@Sided(Side.CLIENT)
override fun getAmbientOcclusionLightValue(state: BlockState, world: IBlockReader, pos: BlockPos): Float {
return 1F
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,47 +1,27 @@
package chylex.hee.game.block package chylex.hee.game.block
import chylex.hee.game.Resource.location import chylex.hee.game.Resource.location
import chylex.hee.game.block.builder.HeeBlockBuilder import chylex.hee.game.block.properties.BlockBuilder
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.block.properties.BlockModel
import chylex.hee.game.item.util.Tool.Level.WOOD
import chylex.hee.init.ModBlocks import chylex.hee.init.ModBlocks
import net.minecraft.block.SoundType import net.minecraft.block.BlockState
import net.minecraft.block.material.Material
import net.minecraft.block.material.MaterialColor
import net.minecraft.tags.BlockTags import net.minecraft.tags.BlockTags
import net.minecraftforge.common.ToolType.AXE import net.minecraft.util.Direction
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
object BlockWhitebark : HeeBlockBuilder() { class BlockWhitebark(builder: BlockBuilder) : HeeBlock(builder) {
init { override val model
material = Material.WOOD get() = BlockModel.Cube(ModBlocks.WHITEBARK_LOG.location)
color = MaterialColor.SNOW
sound = SoundType.WOOD override val tags
tool = BlockHarvestTool.optional(WOOD, AXE) get() = listOf(BlockTags.LOGS, BlockTags.LOGS_THAT_BURN)
override fun getFlammability(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
return 5
} }
val BARK = HeeBlockBuilder { override fun getFireSpreadSpeed(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction): Int {
includeFrom(BlockWhitebark) return 5
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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -46,6 +46,13 @@ object BlockBuilders {
explosionResistance = 0.6F 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 { val buildEnderSol = BlockBuilder(Materials.SOLID, MaterialColor.WOOD, SoundType.GROUND.clone(pitch = 0.85F)).apply {
requiresTool = true requiresTool = true
harvestTool = Pair(WOOD, SHOVEL) harvestTool = Pair(WOOD, SHOVEL)
@@ -69,6 +76,16 @@ object BlockBuilders {
explosionResistance = 4.2F 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 { val buildGloomtorch = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.STONE).apply {
explosionResistance = 0.3F explosionResistance = 0.3F
lightLevel = 13 lightLevel = 13
@@ -116,6 +133,19 @@ object BlockBuilders {
lightLevel = 15 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) // Building (Dark Loam)
val buildDarkLoam = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.GROUND).apply { val buildDarkLoam = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.GROUND).apply {
@@ -132,6 +162,10 @@ object BlockBuilders {
explosionResistance = 2.0F explosionResistance = 2.0F
} }
val buildWhitebarkPlanks = buildWhitebark.clone {
explosionResistance = 3.0F
}
// Building (Miner's Burial) // Building (Miner's Burial)
val buildMinersBurial = BlockBuilder(Materials.SOLID, MaterialColor.RED, SoundType.STONE).apply { val buildMinersBurial = BlockBuilder(Materials.SOLID, MaterialColor.RED, SoundType.STONE).apply {
@@ -141,6 +175,10 @@ object BlockBuilders {
explosionResistance = 120F explosionResistance = 120F
} }
val buildMinersBurialIndestructible = buildMinersBurial.clone {
makeIndestructible()
}
// Fluids // Fluids
val buildCauldron = BlockBuilder(Material.IRON, MaterialColor.STONE, SoundType.STONE).apply { val buildCauldron = BlockBuilder(Material.IRON, MaterialColor.STONE, SoundType.STONE).apply {
@@ -150,11 +188,26 @@ object BlockBuilders {
// Interactive (Storage) // 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 { val buildLootChest = BlockBuilder(Materials.SOLID, MaterialColor.BLACK, SoundType.METAL).apply {
makeIndestructible() makeIndestructible()
lightLevel = 13 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) // Interactive (Gates)
val buildExperienceGate = BlockBuilder(Materials.SOLID, MaterialColor.GREEN, SoundType.METAL).apply { val buildExperienceGate = BlockBuilder(Materials.SOLID, MaterialColor.GREEN, SoundType.METAL).apply {
@@ -164,6 +217,8 @@ object BlockBuilders {
// Interactive (Uncategorized) // Interactive (Uncategorized)
val buildIgneousPlate = BlockBuilder(Materials.IGNEOUS_ROCK_PLATE, MaterialColor.AIR, SoundType.STONE)
val buildBrewingStand = BlockBuilder(Material.IRON, MaterialColor.YELLOW, SoundType.STONE).apply { val buildBrewingStand = BlockBuilder(Material.IRON, MaterialColor.YELLOW, SoundType.STONE).apply {
isSolid = false isSolid = false
harvestHardness = 0.5F harvestHardness = 0.5F
@@ -177,6 +232,24 @@ object BlockBuilders {
requiresTool = true 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 { val buildIgneousRockOre = buildEndOre.clone {
harvestTool = Pair(DIAMOND, PICKAXE) harvestTool = Pair(DIAMOND, PICKAXE)
harvestHardness = 1.6F harvestHardness = 1.6F
@@ -242,6 +315,25 @@ object BlockBuilders {
noDrops = true 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 // Energy
val buildEnergyCluster = BlockBuilder(Materials.ENERGY_CLUSTER, MaterialColor.SNOW, SoundType.GLASS.clone(volume = 1.25F, pitch = 1.35F)).apply { val buildEnergyCluster = BlockBuilder(Materials.ENERGY_CLUSTER, MaterialColor.SNOW, SoundType.GLASS.clone(volume = 1.25F, pitch = 1.35F)).apply {
@@ -250,6 +342,12 @@ object BlockBuilders {
noDrops = true noDrops = true
} }
val buildCorruptedEnergy = BlockBuilder(Materials.CORRUPTED_ENERGY, MaterialColor.PURPLE, SoundType.SAND).apply {
isSolid = false
randomTicks = true // just to be safe
noDrops = true
}
// Tables // Tables
val buildTablePedestal = buildGloomrock.clone { val buildTablePedestal = buildGloomrock.clone {
@@ -274,6 +372,14 @@ object BlockBuilders {
lightLevel = 15 lightLevel = 15
} }
val buildScaffolding = BlockBuilder(Materials.SCAFFOLDING, MaterialColor.AIR, SoundType.STONE).apply {
makeIndestructible()
isSolid = false
isOpaque = false
suffocates = false
blocksVision = false
}
// Overrides // Overrides
val buildEndPortalOverride = BlockBuilder(Material.PORTAL, MaterialColor.BLACK, SoundType.STONE).apply { val buildEndPortalOverride = BlockBuilder(Material.PORTAL, MaterialColor.BLACK, SoundType.STONE).apply {

View File

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

View File

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

View File

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

View File

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

View File

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

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