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

2 Commits

Author SHA1 Message Date
b64005357e [WIP] Components 2021-02-28 14:33:35 +01:00
3279dde625 Add a component system 2021-02-28 13:29:18 +01:00
22 changed files with 292 additions and 164 deletions

View File

@@ -76,8 +76,8 @@ class EntityMobAngryEnderman(type: EntityType<EntityMobAngryEnderman>, world: Wo
}
override fun updateAITasks() {
teleportHandler.update()
waterHandler.update()
teleportHandler.tickServer()
waterHandler.tickServer()
val currentTarget = attackTarget

View File

@@ -26,6 +26,10 @@ import chylex.hee.game.mechanics.causatum.events.CausatumEventEndermanKill
import chylex.hee.game.world.playServer
import chylex.hee.init.ModEntities
import chylex.hee.init.ModSounds
import chylex.hee.system.component.EntityComponents
import chylex.hee.system.component.general.deserializeFrom
import chylex.hee.system.component.general.serializeTo
import chylex.hee.system.component.general.tick
import chylex.hee.system.facades.Resource
import chylex.hee.system.forge.SubscribeAllEvents
import chylex.hee.system.forge.SubscribeEvent
@@ -76,8 +80,6 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
@SubscribeAllEvents(modid = HEE.ID)
companion object {
private const val TELEPORT_HANDLER_TAG = "Teleport"
private const val WATER_HANDLER_TAG = "Water"
private const val CAN_PICK_UP_BLOCKS_TAG = "CanPickUpBlocks"
private const val HELD_BLOCK_TIMER_TAG = "HeldBlockTimer"
private const val HELD_BLOCK_DESPAWNS_TAG = "HeldBlockDespawns"
@@ -202,8 +204,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
// Instance
private lateinit var components: EntityComponents
private lateinit var teleportHandler: EndermanTeleportHandler
private lateinit var waterHandler: EndermanWaterHandler
private lateinit var blockHandler: EndermanBlockHandler
private lateinit var aiAttackTarget: AIToggle
@@ -227,6 +230,13 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
// Initialization
override fun registerData() {
super.registerData()
components = EntityComponents()
components.attach(EndermanWaterHandler(this, takeDamageAfterWetTicks = 80))
}
override fun registerAttributes() {
super.registerAttributes()
@@ -238,8 +248,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
}
override fun registerGoals() {
teleportHandler = EndermanTeleportHandler(this)
waterHandler = EndermanWaterHandler(this, takeDamageAfterWetTicks = 80)
teleportHandler = EndermanTeleportHandler(this).also(components::attach)
blockHandler = EndermanBlockHandler(this)
aiWatchTargetInShock = AIWatchTargetInShock(this, maxDistance = 72.0)
@@ -265,10 +274,9 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun livingTick() {
super.livingTick()
components.tick(this)
if (!world.isRemote) {
teleportHandler.update()
waterHandler.update()
if (heldBlockTimer > 0 && --heldBlockTimer == 0.toShort()) {
if (heldBlockDespawns || !blockHandler.tryPlaceBlock(allowPlayerProximity = false)) {
teleportHandler.teleportOutOfWorld(force = rand.nextBoolean())
@@ -536,8 +544,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun writeAdditional(nbt: TagCompound) = nbt.heeTag.use {
super.writeAdditional(nbt)
put(TELEPORT_HANDLER_TAG, teleportHandler.serializeNBT())
put(WATER_HANDLER_TAG, waterHandler.serializeNBT())
components.serializeTo(this)
putBoolean(CAN_PICK_UP_BLOCKS_TAG, aiPickUpBlocks.enabled)
putShort(HELD_BLOCK_TIMER_TAG, heldBlockTimer)
@@ -547,8 +554,7 @@ class EntityMobEnderman(type: EntityType<EntityMobEnderman>, world: World) : Ent
override fun readAdditional(nbt: TagCompound) = nbt.heeTag.use {
super.readAdditional(nbt)
teleportHandler.deserializeNBT(getCompound(TELEPORT_HANDLER_TAG))
waterHandler.deserializeNBT(getCompound(WATER_HANDLER_TAG))
components.deserializeFrom(this)
aiPickUpBlocks.enabled = getBoolean(CAN_PICK_UP_BLOCKS_TAG)
heldBlockTimer = getShort(HELD_BLOCK_TIMER_TAG)

View File

@@ -29,6 +29,8 @@ import chylex.hee.network.client.PacketClientFX
import chylex.hee.network.fx.FxEntityData
import chylex.hee.network.fx.FxEntityHandler
import chylex.hee.system.color.IntColor.Companion.RGB
import chylex.hee.system.component.general.SerializableComponent
import chylex.hee.system.component.general.TickableComponent
import chylex.hee.system.math.Vec
import chylex.hee.system.math.Vec3
import chylex.hee.system.math.addY
@@ -53,13 +55,12 @@ import net.minecraft.util.SoundCategory
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Vec3d
import net.minecraftforge.common.util.INBTSerializable
import java.util.Random
import java.util.UUID
import kotlin.math.min
import kotlin.math.sqrt
class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : INBTSerializable<TagCompound> {
class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) : TickableComponent, SerializableComponent {
companion object {
private const val DEFAULT_RESTORE_Y = -256.0
@@ -117,6 +118,9 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
}
}
override val serializationKey
get() = "Teleport"
val preventDespawn
get() = tpDelayTicks > 0
@@ -133,7 +137,7 @@ class EndermanTeleportHandler(private val enderman: EntityMobAbstractEnderman) :
private var lastDodged: UUID? = null
fun update() {
override fun tickServer() {
if (tpCooldown > 0) {
--tpCooldown
}

View File

@@ -4,15 +4,16 @@ import chylex.hee.game.entity.OPERATION_MUL_INCR_INDIVIDUAL
import chylex.hee.game.entity.living.EntityMobAbstractEnderman
import chylex.hee.game.entity.tryApplyModifier
import chylex.hee.game.entity.tryRemoveModifier
import chylex.hee.system.component.general.SerializableComponent
import chylex.hee.system.component.general.TickableComponent
import chylex.hee.system.random.nextInt
import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.use
import net.minecraft.entity.SharedMonsterAttributes.ATTACK_DAMAGE
import net.minecraft.entity.ai.attributes.AttributeModifier
import net.minecraft.util.DamageSource
import net.minecraftforge.common.util.INBTSerializable
class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : INBTSerializable<TagCompound> {
class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, private val takeDamageAfterWetTicks: Int) : TickableComponent, SerializableComponent {
private companion object {
private val DEBUFF_WEAKNESS = AttributeModifier("Water weakness", -0.5, OPERATION_MUL_INCR_INDIVIDUAL)
@@ -20,10 +21,13 @@ class EndermanWaterHandler(private val enderman: EntityMobAbstractEnderman, priv
private const val DEBUFF_TICKS_TAG = "DebuffTicks"
}
override val serializationKey
get() = "Water"
private var wetCounter = 0
private var debuffTicks = 0
fun update() {
override fun tickServer() {
val isWet = enderman.isWet
if (isWet) {

View File

@@ -3,6 +3,7 @@ package chylex.hee.game.item
import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.energy.IEnergyQuantity
import chylex.hee.game.mechanics.energy.IEnergyQuantity.Units
import chylex.hee.game.particle.ParticleEnergyTransferToPlayer
@@ -36,11 +37,11 @@ import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer
import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.MathHelper
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent
@@ -50,7 +51,7 @@ import java.util.Random
import kotlin.math.max
import kotlin.math.pow
abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties) {
abstract class ItemAbstractEnergyUser(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object {
private const val ENERGY_LEVEL_TAG = "EnergyLevel"
@@ -100,6 +101,8 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
init {
@Suppress("DEPRECATION")
require(maxStackSize == 1) { "energy item must have a maximum stack size of 1" }
components.attach(this)
}
protected abstract fun getEnergyCapacity(stack: ItemStack): Units
@@ -163,15 +166,11 @@ abstract class ItemAbstractEnergyUser(properties: Properties) : Item(properties)
// Energy charging
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
val tile = pos.getTile<TileEntityEnergyCluster>(world)
val stack = player.getHeldItem(context.hand)
val stack = player.getHeldItem(ctx.hand)
if (tile == null || !player.canPlayerEdit(pos, context.face, stack)) {
if (tile == null || !player.canPlayerEdit(pos, ctx.face, stack)) {
return FAIL
}
else if (world.isRemote) {

View File

@@ -13,7 +13,7 @@ import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
abstract class ItemAbstractInfusable(properties: Properties) : Item(properties), IInfusableItem {
abstract class ItemAbstractInfusable(properties: Properties) : ItemWithComponents(properties), IInfusableItem {
companion object {
fun onCanApplyInfusion(item: Item, infusion: Infusion): Boolean {
return infusion.targetItems.contains(item)

View File

@@ -1,6 +1,7 @@
package chylex.hee.game.item
import chylex.hee.game.inventory.size
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor
import chylex.hee.init.ModItems
import chylex.hee.network.client.PacketClientFX
@@ -15,7 +16,6 @@ import chylex.hee.system.migration.ItemBoneMeal
import net.minecraft.block.DispenserBlock.FACING
import net.minecraft.dispenser.IBlockSource
import net.minecraft.dispenser.OptionalDispenseBehavior
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
@@ -25,7 +25,7 @@ import net.minecraft.world.server.ServerWorld
import net.minecraftforge.common.util.FakePlayerFactory
import java.util.Random
class ItemCompost(properties: Properties) : Item(properties) {
class ItemCompost(properties: Properties) : ItemWithComponents(properties) {
companion object {
private const val BONE_MEAL_EQUIVALENT = 2
@@ -61,6 +61,24 @@ class ItemCompost(properties: Properties) : Item(properties) {
}
init {
components.attach(object : UseOnBlockComponent {
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
else if (world.isRemote) {
return SUCCESS
}
if (applyCompost(world, pos, player)) {
item.shrink(1)
return SUCCESS
}
return PASS
}
})
BlockDispenser.registerDispenseBehavior(this, object : OptionalDispenseBehavior() {
override fun dispenseStack(source: IBlockSource, stack: ItemStack): ItemStack {
val world = source.world
@@ -77,26 +95,4 @@ class ItemCompost(properties: Properties) : Item(properties) {
}
})
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL
}
else if (world.isRemote) {
return SUCCESS
}
if (applyCompost(world, pos, player)) {
heldItem.shrink(1)
return SUCCESS
}
return PASS
}
}

View File

@@ -2,27 +2,27 @@ package chylex.hee.game.item
import chylex.hee.game.block.IBlockDeathFlowerDecaying
import chylex.hee.game.entity.item.EntityItemCauldronTrigger
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.getBlock
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.PASS
import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class ItemEndPowder(properties: Properties) : Item(properties) {
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
class ItemEndPowder(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
init {
components.attach(this)
}
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
@@ -33,7 +33,7 @@ class ItemEndPowder(properties: Properties) : Item(properties) {
block.healDeathFlower(world, pos)
}
heldItem.shrink(1)
item.shrink(1)
return SUCCESS
}

View File

@@ -28,7 +28,6 @@ import chylex.hee.system.math.angleBetween
import chylex.hee.system.math.floorToInt
import chylex.hee.system.math.over
import chylex.hee.system.math.toDegrees
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityLivingBase
import chylex.hee.system.migration.EntityPlayer
@@ -150,17 +149,13 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
return ItemAbstractInfusable.onCanApplyInfusion(this, infusion)
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (player.isSneaking && pos.getTile<TileEntityEnergyCluster>(world) != null) {
if (world.isRemote) {
return SUCCESS
}
val heldItem = player.getHeldItem(context.hand)
val heldItem = player.getHeldItem(ctx.hand)
val entry = pos.toLong()
with(heldItem.heeTag) {
@@ -176,7 +171,7 @@ class ItemEnergyOracle(properties: Properties) : ItemAbstractEnergyUser(properti
return SUCCESS
}
return super.onItemUse(context)
return super.useOnBlock(world, pos, player, item, ctx)
}
override fun inventoryTick(stack: ItemStack, world: World, entity: Entity, itemSlot: Int, isSelected: Boolean) {

View File

@@ -4,6 +4,7 @@ import chylex.hee.client.color.NO_TINT
import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.item.infusion.Infusion.SAFETY
import chylex.hee.game.item.infusion.Infusion.STABILITY
import chylex.hee.game.item.infusion.InfusionList
@@ -27,10 +28,10 @@ import chylex.hee.system.forge.Side
import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.serialization.TagCompound
import chylex.hee.system.serialization.getIntegerOrNull
import chylex.hee.system.serialization.hasKey
import chylex.hee.system.serialization.use
import net.minecraft.client.renderer.color.IItemColor
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity
@@ -43,7 +44,7 @@ import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
import kotlin.math.pow
class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties) {
class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(properties), UseOnBlockComponent {
private companion object {
private const val CLUSTER_SNAPSHOT_TAG = "Cluster"
private const val UPDATE_TIME_TAG = "UpdateTime"
@@ -105,18 +106,14 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
}
// POLISH tweak animation
components.attach(this)
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val stack = player.getHeldItem(context.hand)
stack.heeTag.use {
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
with(item.heeTag) {
if (hasKey(CLUSTER_SNAPSHOT_TAG)) {
val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, stack, context)
val finalPos = BlockEditor.place(ModBlocks.ENERGY_CLUSTER, player, item, ctx)
if (world.isRemote) {
return SUCCESS
@@ -126,7 +123,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
finalPos.getTile<TileEntityEnergyCluster>(world)?.let {
it.loadClusterSnapshot(ClusterSnapshot(getCompound(CLUSTER_SNAPSHOT_TAG)), inactive = false)
if (shouldLoseHealth(it, this, InfusionTag.getList(stack))) {
if (shouldLoseHealth(it, this, InfusionTag.getList(item))) {
it.deteriorateHealth()
}
}
@@ -141,7 +138,7 @@ class ItemEnergyReceptacle(properties: Properties) : ItemAbstractInfusable(prope
return SUCCESS
}
}
else if (BlockEditor.canEdit(pos, player, stack)) {
else if (BlockEditor.canEdit(pos, player, item)) {
if (world.isRemote) {
return SUCCESS
}

View File

@@ -6,6 +6,7 @@ import chylex.hee.game.entity.heeTag
import chylex.hee.game.entity.heeTagOrNull
import chylex.hee.game.entity.posVec
import chylex.hee.game.inventory.doDamage
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.FLAG_NONE
import chylex.hee.game.world.getBlock
@@ -14,7 +15,6 @@ import chylex.hee.game.world.playServer
import chylex.hee.game.world.removeBlock
import chylex.hee.game.world.setBlock
import chylex.hee.init.ModBlocks
import chylex.hee.system.compatibility.MinecraftForgeEventBus
import chylex.hee.system.forge.EventPriority
import chylex.hee.system.forge.SubscribeAllEvents
import chylex.hee.system.forge.SubscribeEvent
@@ -26,7 +26,6 @@ import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.migration.Sounds
import chylex.hee.system.random.nextFloat
import net.minecraft.block.Blocks
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
@@ -36,7 +35,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.minecraftforge.event.world.ExplosionEvent
class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
class ItemFlintAndInfernium(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
@SubscribeAllEvents(modid = HEE.ID)
companion object {
private const val CREEPER_INFERNIUM_TAG = "Infernium"
@@ -55,7 +54,7 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
}
init {
MinecraftForgeEventBus.register(this)
components.attach(this)
}
fun igniteTNT(world: World, pos: BlockPos, player: EntityPlayer?, ignoreTrap: Boolean) {
@@ -67,14 +66,8 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
pos.removeBlock(world)
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
@@ -85,11 +78,11 @@ class ItemFlintAndInfernium(properties: Properties) : Item(properties) {
igniteTNT(world, pos, player, ignoreTrap = false)
}
else {
BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, heldItem, context) ?: return FAIL
BlockEditor.place(ModBlocks.ETERNAL_FIRE, player, item, ctx) ?: return FAIL
}
Sounds.ITEM_FLINTANDSTEEL_USE.playServer(world, pos, SoundCategory.BLOCKS, volume = 1.1F, pitch = world.rand.nextFloat(0.4F, 0.5F))
heldItem.doDamage(1, player, context.hand)
item.doDamage(1, player, ctx.hand)
}
return SUCCESS

View File

@@ -9,6 +9,7 @@ import chylex.hee.game.entity.item.EntityTokenHolder
import chylex.hee.game.entity.selectExistingEntities
import chylex.hee.game.inventory.heeTag
import chylex.hee.game.inventory.heeTagOrNull
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.portal.DimensionTeleporter
import chylex.hee.game.mechanics.portal.EntityPortalContact
import chylex.hee.game.world.BlockEditor
@@ -34,7 +35,6 @@ import chylex.hee.system.serialization.putEnum
import net.minecraft.client.renderer.color.IItemColor
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemGroup
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
@@ -43,13 +43,14 @@ import net.minecraft.util.ActionResultType
import net.minecraft.util.Hand
import net.minecraft.util.NonNullList
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.StringTextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
import net.minecraft.world.dimension.DimensionType
class ItemPortalToken(properties: Properties) : Item(properties) {
class ItemPortalToken(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object {
private const val TYPE_TAG = "Type"
private const val TERRITORY_TYPE_TAG = "Territory"
@@ -72,6 +73,8 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
}
init {
components.attach(this)
addPropertyOverride(Resource.Custom("token_type")) { stack, _, _ ->
getTokenType(stack).propertyValue + (if (stack.heeTagOrNull.hasKey(IS_CORRUPTED_TAG)) 0.5F else 0F)
}
@@ -178,10 +181,7 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
return ActionResult(SUCCESS, heldItem)
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
if (!player.isCreative || player.isSneaking) {
return PASS
}
@@ -190,16 +190,14 @@ class ItemPortalToken(properties: Properties) : Item(properties) {
return SUCCESS
}
val targetPos = context.pos.up()
val targetPos = pos.up()
val territoryType = getTerritoryType(item)
val heldItem = player.getHeldItem(context.hand)
val territoryType = getTerritoryType(heldItem)
if (territoryType == null || context.face != UP || !BlockEditor.canEdit(targetPos, player, heldItem) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
if (territoryType == null || ctx.face != UP || !BlockEditor.canEdit(targetPos, player, item) || world.selectExistingEntities.inBox<EntityTokenHolder>(AxisAlignedBB(targetPos)).any()) {
return FAIL
}
world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(heldItem), territoryType))
world.addEntity(EntityTokenHolder(world, targetPos, getTokenType(item), territoryType))
return SUCCESS
}

View File

@@ -1,6 +1,7 @@
package chylex.hee.game.item
import chylex.hee.game.block.entity.TileEntityMinersBurialAltar
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.getTile
import chylex.hee.game.world.playUniversal
@@ -8,33 +9,34 @@ import chylex.hee.init.ModSounds
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.PASS
import chylex.hee.system.migration.ActionResult.SUCCESS
import net.minecraft.item.Item
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.SoundCategory
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
class ItemPuzzleMedallion(properties: Properties) : Item(properties) {
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
return FAIL
}
val tile = pos.getTile<TileEntityMinersBurialAltar>(world)
if (tile != null && !tile.hasMedallion) {
tile.hasMedallion = true
heldItem.shrink(1)
ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F)
return SUCCESS
}
return PASS
class ItemPuzzleMedallion(properties: Properties) : ItemWithComponents(properties) {
init {
components.attach(object : UseOnBlockComponent {
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
val tile = pos.getTile<TileEntityMinersBurialAltar>(world)
if (tile != null && !tile.hasMedallion) {
tile.hasMedallion = true
item.shrink(1)
ModSounds.ITEM_PUZZLE_MEDALLION_INSERT.playUniversal(player, pos, SoundCategory.BLOCKS, volume = 2F, pitch = 0.8F)
return SUCCESS
}
return PASS
}
})
}
}

View File

@@ -3,6 +3,7 @@ package chylex.hee.game.item
import chylex.hee.client.model.ModelHelper
import chylex.hee.game.block.entity.TileEntityEnergyCluster
import chylex.hee.game.entity.item.EntityItemRevitalizationSubstance
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.mechanics.energy.IClusterHealth.HealthOverride.REVITALIZING
import chylex.hee.game.particle.ParticleSmokeCustom
import chylex.hee.game.particle.spawner.ParticleSpawnerCustom
@@ -26,7 +27,6 @@ import chylex.hee.system.serialization.readPos
import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer
@@ -37,7 +37,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.util.Random
class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
class ItemRevitalizationSubstance(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object {
private val PARTICLE_FAIL = ParticleSpawnerCustom(
type = ParticleSmokeCustom,
@@ -70,11 +70,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
}
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
init {
components.attach(this)
}
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (world.isRemote) {
return FAIL // disable animation
}
@@ -83,11 +83,11 @@ class ItemRevitalizationSubstance(properties: Properties) : Item(properties) {
if (cluster.currentHealth != REVITALIZING) {
if (cluster.addRevitalizationSubstance()) {
player.getHeldItem(context.hand).shrink(1)
player.getHeldItem(ctx.hand).shrink(1)
ModSounds.ITEM_REVITALIZATION_SUBSTANCE_USE_SUCCESS.playServer(world, pos, SoundCategory.BLOCKS, volume = 0.5F)
}
else {
PacketClientFX(FX_FAIL, FxUseData(pos, player, context.hand)).sendToAllAround(player, 24.0)
PacketClientFX(FX_FAIL, FxUseData(pos, player, ctx.hand)).sendToAllAround(player, 24.0)
}
}

View File

@@ -2,33 +2,33 @@ package chylex.hee.game.item
import chylex.hee.game.block.BlockAbstractTableTile
import chylex.hee.game.block.BlockTableBase
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.BlockEditor
import chylex.hee.game.world.breakBlock
import chylex.hee.game.world.getBlock
import chylex.hee.game.world.setBlock
import chylex.hee.system.forge.Side
import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.client.util.ITooltipFlag
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.PASS
import net.minecraft.util.ActionResultType.SUCCESS
import net.minecraft.util.math.BlockPos
import net.minecraft.util.text.ITextComponent
import net.minecraft.util.text.TranslationTextComponent
import net.minecraft.world.World
class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : Item(properties) {
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
val heldItem = player.getHeldItem(context.hand)
if (!BlockEditor.canEdit(pos, player, heldItem)) {
class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
init {
components.attach(this)
}
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType {
if (!BlockEditor.canEdit(pos, player, item)) {
return FAIL
}
@@ -42,7 +42,7 @@ class ItemTableCore(private val tableBlocks: Array<BlockAbstractTableTile<*>>, p
pos.setBlock(world, table)
}
heldItem.shrink(1)
item.shrink(1)
return SUCCESS
}

View File

@@ -12,6 +12,7 @@ import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_FAIL
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_OUTPUT
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_RESTART
import chylex.hee.game.item.ItemTableLink.Companion.SoundType.LINK_SUCCESS
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.game.world.getBlock
import chylex.hee.game.world.getTile
import chylex.hee.game.world.playClient
@@ -26,6 +27,7 @@ import chylex.hee.system.forge.Sided
import chylex.hee.system.migration.ActionResult.FAIL
import chylex.hee.system.migration.ActionResult.SUCCESS
import chylex.hee.system.migration.EntityItem
import chylex.hee.system.migration.EntityPlayer
import chylex.hee.system.random.nextFloat
import chylex.hee.system.serialization.getPos
import chylex.hee.system.serialization.hasKey
@@ -34,7 +36,6 @@ import chylex.hee.system.serialization.readPos
import chylex.hee.system.serialization.use
import chylex.hee.system.serialization.writePos
import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.network.PacketBuffer
@@ -44,7 +45,7 @@ import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.util.Random
class ItemTableLink(properties: Properties) : Item(properties) {
class ItemTableLink(properties: Properties) : ItemWithComponents(properties), UseOnBlockComponent {
companion object {
private const val POS_TAG = "StoredPos"
private const val TIME_TAG = "StoredTime"
@@ -106,11 +107,11 @@ class ItemTableLink(properties: Properties) : Item(properties) {
}
}
override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
val world = context.world
val pos = context.pos
init {
components.attach(this)
}
override fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType? {
if (!player.isSneaking || !isValidTarget(world, pos)) {
val pedestal = pos.getTile<TileEntityTablePedestal>(world)
@@ -131,7 +132,7 @@ class ItemTableLink(properties: Properties) : Item(properties) {
return SUCCESS
}
val heldItem = player.getHeldItem(context.hand)
val heldItem = player.getHeldItem(ctx.hand)
var newStoredPos = pos
var soundType = LINK_RESTART

View File

@@ -0,0 +1,18 @@
package chylex.hee.game.item
import chylex.hee.game.item.components.UseOnBlockComponent
import chylex.hee.system.component.EntityComponents
import net.minecraft.item.Item
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.ActionResultType.FAIL
import net.minecraft.util.ActionResultType.PASS
open class ItemWithComponents(properties: Properties) : Item(properties) {
val components = EntityComponents()
final override fun onItemUse(context: ItemUseContext): ActionResultType {
val player = context.player ?: return FAIL
return components.handle<UseOnBlockComponent, ActionResultType> { useOnBlock(context.world, context.pos, player, context.item, context) } ?: PASS
}
}

View File

@@ -0,0 +1,12 @@
package chylex.hee.game.item.components
import chylex.hee.system.migration.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.item.ItemUseContext
import net.minecraft.util.ActionResultType
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
interface UseOnBlockComponent { // TODO use as objects instead of inheriting the interface on Item
fun useOnBlock(world: World, pos: BlockPos, player: EntityPlayer, item: ItemStack, ctx: ItemUseContext): ActionResultType?
}

View File

@@ -0,0 +1,8 @@
package chylex.hee.system.component
abstract class AbstractAwareComponent {
var entityComponents: EntityComponents? = null
open fun onComponentAttached() {}
open fun onComponentDetached() {}
}

View File

@@ -0,0 +1,56 @@
package chylex.hee.system.component
class EntityComponents {
private val mutableComponents = mutableListOf<Any>()
val components: List<Any>
get() = mutableComponents
fun attach(component: Any) {
require(!mutableComponents.contains(component)) { "[EntityComponents] component must not be registered twice" }
mutableComponents.add(component)
if (component is AbstractAwareComponent) {
require(component.entityComponents === null) { "[EntityComponents] component must not be registered in two entities" }
component.entityComponents = this
component.onComponentAttached()
}
}
fun detach(component: Any) {
if (!mutableComponents.remove(component)) {
return
}
if (component is AbstractAwareComponent) {
require(component.entityComponents === this) { "[EntityComponents] component was not registered correctly" }
component.onComponentDetached()
component.entityComponents = null
}
}
inline fun <reified T> on(f: T.() -> Unit) {
for(component in components) {
if (component is T) {
f(component)
}
}
}
inline fun <reified T, U> handle(f: T.() -> U?): U? {
for(component in components) {
if (component is T) {
val result = f(component)
if (result != null) {
return result
}
}
}
return null
}
inline fun <reified T> list(): List<T> {
return components.filterIsInstance<T>()
}
}

View File

@@ -0,0 +1,20 @@
package chylex.hee.system.component.general
import chylex.hee.system.component.EntityComponents
import chylex.hee.system.serialization.TagCompound
import net.minecraftforge.common.util.INBTSerializable
interface SerializableComponent : INBTSerializable<TagCompound> {
val serializationKey: String
}
fun EntityComponents.serializeTo(tag: TagCompound) {
this.on<SerializableComponent> {
require(!tag.contains(serializationKey)) { "[SerializableComponent] cannot serialize duplicate key: $serializationKey" }
tag.put(serializationKey, serializeNBT())
}
}
fun EntityComponents.deserializeFrom(tag: TagCompound) {
this.on<SerializableComponent> { deserializeNBT(tag.getCompound(serializationKey)) }
}

View File

@@ -0,0 +1,19 @@
package chylex.hee.system.component.general
import chylex.hee.system.component.EntityComponents
import net.minecraft.entity.Entity
interface TickableComponent {
@JvmDefault fun tickClient() {}
@JvmDefault fun tickServer() {}
}
@JvmName("tickEntity")
fun <T : Entity> EntityComponents.tick(entity: T) {
if (entity.world.isRemote) {
this.on(TickableComponent::tickClient)
}
else {
this.on(TickableComponent::tickServer)
}
}