diff --git a/common/src/main/kotlin/juuxel/adorn/block/BenchBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/BenchBlock.kt index 972ebecbb..9738ad48a 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/BenchBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/BenchBlock.kt @@ -3,6 +3,7 @@ package juuxel.adorn.block import it.unimi.dsi.fastutil.bytes.Byte2ObjectArrayMap import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap import juuxel.adorn.api.block.BlockVariant +import juuxel.adorn.lib.AdornStats import juuxel.adorn.util.buildShapeRotationsFromNorth import juuxel.adorn.util.getDirection import juuxel.adorn.util.turnHorizontally @@ -26,6 +27,8 @@ import net.minecraft.world.BlockView import net.minecraft.world.WorldAccess class BenchBlock(variant: BlockVariant) : SeatBlock(variant.createSettings()), Waterloggable { + override val sittingStat = AdornStats.SIT_ON_BENCH + init { defaultState = defaultState .with(AXIS, Direction.Axis.Z) diff --git a/common/src/main/kotlin/juuxel/adorn/block/ChairBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/ChairBlock.kt index 5f0ede4fe..9996b432a 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/ChairBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/ChairBlock.kt @@ -2,6 +2,7 @@ package juuxel.adorn.block import juuxel.adorn.api.block.BlockVariant +import juuxel.adorn.lib.AdornStats import juuxel.adorn.util.buildShapeRotations import juuxel.adorn.util.mergeIntoShapeMap import net.minecraft.block.Block @@ -31,6 +32,8 @@ import net.minecraft.world.WorldAccess import net.minecraft.world.WorldView class ChairBlock(variant: BlockVariant) : CarpetedBlock(variant.createSettings()), Waterloggable { + override val sittingStat = AdornStats.SIT_ON_CHAIR + init { defaultState = defaultState.with(HALF, DoubleBlockHalf.LOWER) .with(WATERLOGGED, false) diff --git a/common/src/main/kotlin/juuxel/adorn/block/DrawerBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/DrawerBlock.kt index 0e16310d5..e11d104a5 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/DrawerBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/DrawerBlock.kt @@ -3,6 +3,7 @@ package juuxel.adorn.block import juuxel.adorn.api.block.BlockVariant import juuxel.adorn.block.entity.SimpleContainerBlockEntity +import juuxel.adorn.lib.AdornStats import net.minecraft.block.Block import net.minecraft.block.BlockState import net.minecraft.block.entity.BlockEntity @@ -39,6 +40,11 @@ class DrawerBlock(variant: BlockVariant) : VisibleBlockWithEntity(variant.create state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand?, hitResult: BlockHitResult? ): ActionResult { player.openHandledScreen(state.createScreenHandlerFactory(world, pos)) + + if (!world.isClient) { + player.incrementStat(AdornStats.OPEN_DRAWER) + } + return ActionResult.SUCCESS } diff --git a/common/src/main/kotlin/juuxel/adorn/block/KitchenCupboardBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/KitchenCupboardBlock.kt index 0f83e3e81..8a99b393f 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/KitchenCupboardBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/KitchenCupboardBlock.kt @@ -3,6 +3,7 @@ package juuxel.adorn.block import juuxel.adorn.api.block.BlockVariant import juuxel.adorn.block.entity.SimpleContainerBlockEntity +import juuxel.adorn.lib.AdornStats import net.minecraft.block.BlockEntityProvider import net.minecraft.block.BlockState import net.minecraft.block.entity.BlockEntity @@ -27,6 +28,11 @@ class KitchenCupboardBlock(variant: BlockVariant) : AbstractKitchenCounterBlock( state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand?, hitResult: BlockHitResult? ): ActionResult { player.openHandledScreen(state.createScreenHandlerFactory(world, pos)) + + if (!world.isClient) { + player.incrementStat(AdornStats.OPEN_KITCHEN_CUPBOARD) + } + return ActionResult.SUCCESS } diff --git a/common/src/main/kotlin/juuxel/adorn/block/SeatBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/SeatBlock.kt index 217637e48..7287500ec 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/SeatBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/SeatBlock.kt @@ -12,6 +12,7 @@ import net.minecraft.state.property.BooleanProperty import net.minecraft.state.property.Properties import net.minecraft.util.ActionResult import net.minecraft.util.Hand +import net.minecraft.util.Identifier import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.math.BlockPos import net.minecraft.util.math.Box @@ -24,6 +25,7 @@ abstract class SeatBlock(settings: Settings) : Block(settings) { } open val sittingYOffset: Double = 0.0 + abstract val sittingStat: Identifier? override fun onUse( state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult @@ -45,6 +47,7 @@ abstract class SeatBlock(settings: Settings) : Block(settings) { world.spawnEntity(entity) world.setBlockState(actualPos, actualState.with(OCCUPIED, true)) player.startRiding(entity, true) + sittingStat?.let { player.incrementStat(it) } ActionResult.SUCCESS } ActionResult.SUCCESS diff --git a/common/src/main/kotlin/juuxel/adorn/block/ShelfBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/ShelfBlock.kt index d821b1e22..abb57743e 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/ShelfBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/ShelfBlock.kt @@ -2,6 +2,7 @@ package juuxel.adorn.block import juuxel.adorn.api.block.BlockVariant +import juuxel.adorn.lib.AdornStats import juuxel.adorn.platform.PlatformBridges import juuxel.adorn.util.buildShapeRotations import net.minecraft.block.Block @@ -100,6 +101,7 @@ class ShelfBlock(variant: BlockVariant) : VisibleBlockWithEntity(variant.createS be.markDirty() if (!world.isClient) { PlatformBridges.network.syncBlockEntity(be) + player.incrementStat(AdornStats.INTERACT_WITH_SHELF) } if (!player.abilities.creativeMode) { @@ -114,6 +116,7 @@ class ShelfBlock(variant: BlockVariant) : VisibleBlockWithEntity(variant.createS be.markDirty() if (!world.isClient) { PlatformBridges.network.syncBlockEntity(be) + player.incrementStat(AdornStats.INTERACT_WITH_SHELF) } } diff --git a/common/src/main/kotlin/juuxel/adorn/block/SofaBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/SofaBlock.kt index 2c0530024..af1239e32 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/SofaBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/SofaBlock.kt @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap import juuxel.adorn.api.block.BlockVariant import juuxel.adorn.block.property.FrontConnection +import juuxel.adorn.lib.AdornStats import juuxel.adorn.util.buildShapeRotations import juuxel.adorn.util.withBlock import net.minecraft.block.BedBlock @@ -39,6 +40,8 @@ import net.minecraft.world.World import net.minecraft.world.WorldAccess open class SofaBlock(variant: BlockVariant) : SeatBlock(variant.createSettings()), Waterloggable, SneakClickHandler { + override val sittingStat = AdornStats.SIT_ON_SOFA + init { defaultState = defaultState .with(FRONT_CONNECTION, FrontConnection.NONE) @@ -56,6 +59,7 @@ open class SofaBlock(variant: BlockVariant) : SeatBlock(variant.createSettings() world.setBlockState(pos, state.withBlock(AdornBlocks.SOFAS[item.color]!!)) world.playSound(player, pos, SoundEvents.BLOCK_WOOL_PLACE, SoundCategory.BLOCKS, 1f, 0.8f) if (!player.abilities.creativeMode) stack.decrement(1) + if (!world.isClient) player.incrementStat(AdornStats.DYE_SOFA) return ActionResult.SUCCESS } diff --git a/common/src/main/kotlin/juuxel/adorn/block/TableBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/TableBlock.kt index 6ab2c3c19..bae9b404d 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/TableBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/TableBlock.kt @@ -4,12 +4,14 @@ import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap import juuxel.adorn.api.block.BlockVariant import net.minecraft.block.BlockState +import net.minecraft.util.Identifier import net.minecraft.util.math.Direction import net.minecraft.util.shape.VoxelShape import net.minecraft.util.shape.VoxelShapes class TableBlock(variant: BlockVariant) : AbstractTableBlock(variant.createSettings()) { override val sittingYOffset = 0.6 + override val sittingStat: Identifier? = null override fun isSittingEnabled() = false diff --git a/common/src/main/kotlin/juuxel/adorn/block/TableLampBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/TableLampBlock.kt index 0105721dc..3bd1d532e 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/TableLampBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/TableLampBlock.kt @@ -2,6 +2,7 @@ package juuxel.adorn.block +import juuxel.adorn.lib.AdornStats import juuxel.adorn.util.buildShapeRotationsFromNorth import juuxel.adorn.util.withBlock import net.minecraft.block.Block @@ -54,11 +55,13 @@ class TableLampBlock(settings: Settings) : Block(settings), Waterloggable { world.setBlockState(pos, state.withBlock(AdornBlocks.TABLE_LAMPS[item.color]!!)) world.playSound(player, pos, SoundEvents.BLOCK_WOOL_PLACE, SoundCategory.BLOCKS, 1f, 0.8f) if (!player.abilities.creativeMode) stack.decrement(1) + if (!world.isClient) player.incrementStat(AdornStats.DYE_TABLE_LAMP) } else { val wasLit = state[LIT] world.setBlockState(pos, state.with(LIT, !wasLit)) val pitch = if (wasLit) 0.5f else 0.6f world.playSound(player, pos, SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.BLOCKS, 0.3f, pitch) + if (!world.isClient) player.incrementStat(AdornStats.INTERACT_WITH_TABLE_LAMP) } return ActionResult.SUCCESS } diff --git a/common/src/main/kotlin/juuxel/adorn/block/TradingStationBlock.kt b/common/src/main/kotlin/juuxel/adorn/block/TradingStationBlock.kt index 75a72ff87..6795ad1d3 100644 --- a/common/src/main/kotlin/juuxel/adorn/block/TradingStationBlock.kt +++ b/common/src/main/kotlin/juuxel/adorn/block/TradingStationBlock.kt @@ -2,6 +2,7 @@ package juuxel.adorn.block import juuxel.adorn.block.entity.TradingStationBlockEntity +import juuxel.adorn.lib.AdornStats import net.minecraft.block.Block import net.minecraft.block.BlockState import net.minecraft.block.Blocks @@ -77,9 +78,14 @@ class TradingStationBlock : VisibleBlockWithEntity(Settings.copy(Blocks.CRAFTING player.giveItemStack(trade.selling.copy()) be.storage.tryExtract(trade.selling) be.storage.tryInsert(trade.price) + player.incrementStat(AdornStats.INTERACT_WITH_TRADING_STATION) } } else { player.openHandledScreen(state.createScreenHandlerFactory(world, pos)) + + if (!world.isClient) { + player.incrementStat(AdornStats.INTERACT_WITH_TRADING_STATION) + } } } @@ -94,6 +100,11 @@ class TradingStationBlock : VisibleBlockWithEntity(Settings.copy(Blocks.CRAFTING // Show customer GUI if (!be.isOwner(player)) { player.openHandledScreen(state.createScreenHandlerFactory(world, pos)) + + if (!world.isClient) { + player.incrementStat(AdornStats.INTERACT_WITH_TRADING_STATION) + } + return ActionResult.SUCCESS } diff --git a/common/src/main/kotlin/juuxel/adorn/lib/AdornStats.kt b/common/src/main/kotlin/juuxel/adorn/lib/AdornStats.kt new file mode 100644 index 000000000..996137ea5 --- /dev/null +++ b/common/src/main/kotlin/juuxel/adorn/lib/AdornStats.kt @@ -0,0 +1,25 @@ +package juuxel.adorn.lib + +import juuxel.adorn.AdornCommon +import net.minecraft.stat.StatFormatter +import net.minecraft.stat.Stats +import net.minecraft.util.Identifier + +object AdornStats { + val OPEN_DRAWER: Identifier = register("open_drawer", StatFormatter.DEFAULT) + val OPEN_KITCHEN_CUPBOARD: Identifier = register("open_kitchen_cupboard", StatFormatter.DEFAULT) + val INTERACT_WITH_SHELF: Identifier = register("interact_with_shelf", StatFormatter.DEFAULT) + val INTERACT_WITH_TABLE_LAMP: Identifier = register("interact_with_table_lamp", StatFormatter.DEFAULT) + val INTERACT_WITH_TRADING_STATION: Identifier = register("interact_with_trading_station", StatFormatter.DEFAULT) + val DYE_TABLE_LAMP: Identifier = register("dye_table_lamp", StatFormatter.DEFAULT) + val DYE_SOFA: Identifier = register("dye_sofa", StatFormatter.DEFAULT) + val SIT_ON_CHAIR: Identifier = register("sit_on_chair", StatFormatter.DEFAULT) + val SIT_ON_SOFA: Identifier = register("sit_on_sofa", StatFormatter.DEFAULT) + val SIT_ON_BENCH: Identifier = register("sit_on_bench", StatFormatter.DEFAULT) + + private fun register(id: String, formatter: StatFormatter) = + Stats.register("${AdornCommon.NAMESPACE}:$id", formatter) + + fun init() { + } +} diff --git a/common/src/main/kotlin/juuxel/adorn/platform/Registrar.kt b/common/src/main/kotlin/juuxel/adorn/platform/Registrar.kt index cec1a3984..1947bf24f 100644 --- a/common/src/main/kotlin/juuxel/adorn/platform/Registrar.kt +++ b/common/src/main/kotlin/juuxel/adorn/platform/Registrar.kt @@ -3,7 +3,17 @@ package juuxel.adorn.platform import juuxel.adorn.lib.Registered interface Registrar { + /** + * Registers an object with the [id]. The object is created using the [provider]. + */ fun register(id: String, provider: () -> U): Registered + + /** + * Registers an optional object with the [id]. The [provider] can either create the object, + * or return null, in which case the return value contains null. + * + * Note that this, unlike the other methods, always invokes the provider eagerly even on Forge. + */ fun registerOptional(id: String, provider: () -> U?): Registered { val value: U = provider.invoke() ?: return Registered { null } return register(id) { value } diff --git a/common/src/main/resources/adorn.accesswidener b/common/src/main/resources/adorn.accesswidener index ac3c196ed..6d6d55932 100644 --- a/common/src/main/resources/adorn.accesswidener +++ b/common/src/main/resources/adorn.accesswidener @@ -9,3 +9,7 @@ accessible method net/minecraft/block/WallTorchBlock (Lnet/minecraft/bloc # Game rules accessible method net/minecraft/world/GameRules register (Ljava/lang/String;Lnet/minecraft/world/GameRules$Category;Lnet/minecraft/world/GameRules$Type;)Lnet/minecraft/world/GameRules$Key; accessible method net/minecraft/world/GameRules$BooleanRule create (Z)Lnet/minecraft/world/GameRules$Type; + +# Stats +## Yeah, I know this method isn't technically needed but it's really useful :^) +accessible method net/minecraft/stat/Stats register (Ljava/lang/String;Lnet/minecraft/stat/StatFormatter;)Lnet/minecraft/util/Identifier; diff --git a/common/src/main/resources/assets/adorn/lang/en_us.json b/common/src/main/resources/assets/adorn/lang/en_us.json index d8ae34e04..427889c31 100644 --- a/common/src/main/resources/assets/adorn/lang/en_us.json +++ b/common/src/main/resources/assets/adorn/lang/en_us.json @@ -960,6 +960,17 @@ "gui.adorn.config.restart_required.title": "Restart required!", "gui.adorn.config.restart_required.message": "One of your changed options requires Minecraft to be restarted.", + "stat.adorn.dye_sofa": "Sofas Dyed", + "stat.adorn.dye_table_lamp": "Table Lamps Dyed", + "stat.adorn.interact_with_shelf": "Interactions with Shelf", + "stat.adorn.interact_with_table_lamp": "Interactions with Table Lamp", + "stat.adorn.interact_with_trading_station": "Interactions with Trading Station", + "stat.adorn.open_drawer": "Drawers Opened", + "stat.adorn.open_kitchen_cupboard": "Kitchen Cupboards Opened", + "stat.adorn.sit_on_bench": "Times Sat on a Bench", + "stat.adorn.sit_on_chair": "Times Sat on a Chair", + "stat.adorn.sit_on_sofa": "Times Sat on a Sofa", + "itemGroup.adorn.items": "Adorn", "text.adorn.item_stack_with_count": "%sx %s" diff --git a/fabric/src/main/kotlin/juuxel/adorn/Adorn.kt b/fabric/src/main/kotlin/juuxel/adorn/Adorn.kt index 00c9858d8..c827b1caa 100644 --- a/fabric/src/main/kotlin/juuxel/adorn/Adorn.kt +++ b/fabric/src/main/kotlin/juuxel/adorn/Adorn.kt @@ -11,6 +11,7 @@ import juuxel.adorn.lib.AdornGameRules import juuxel.adorn.lib.AdornItemsFabric import juuxel.adorn.lib.AdornNetworking import juuxel.adorn.lib.AdornSounds +import juuxel.adorn.lib.AdornStats import juuxel.adorn.lib.AdornTags import juuxel.adorn.lib.SofaSleeping import juuxel.adorn.menu.AdornMenus @@ -34,6 +35,7 @@ object Adorn : ModInitializer { AdornNetworking.init() AdornTags.init() AdornGameRules.init() + AdornStats.init() SofaSleeping.init() Compat.init() ConfigManagerImpl.finalize() diff --git a/forge/src/main/kotlin/juuxel/adorn/platform/forge/Adorn.kt b/forge/src/main/kotlin/juuxel/adorn/platform/forge/Adorn.kt index d7580282a..f4a4fd971 100644 --- a/forge/src/main/kotlin/juuxel/adorn/platform/forge/Adorn.kt +++ b/forge/src/main/kotlin/juuxel/adorn/platform/forge/Adorn.kt @@ -1,12 +1,14 @@ package juuxel.adorn.platform.forge import juuxel.adorn.AdornCommon +import juuxel.adorn.lib.AdornStats import juuxel.adorn.platform.PlatformBridges import juuxel.adorn.platform.forge.client.AdornClient import net.minecraftforge.api.distmarker.Dist import net.minecraftforge.fml.DistExecutor import net.minecraftforge.fml.DistExecutor.SafeRunnable import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent import thedarkcolour.kotlinforforge.forge.FORGE_BUS import thedarkcolour.kotlinforforge.forge.MOD_BUS @@ -14,8 +16,13 @@ import thedarkcolour.kotlinforforge.forge.MOD_BUS object Adorn { init { PlatformBridges.configManager.init() + MOD_BUS.addListener(this::init) EventsImplementedInJava().register(MOD_BUS, FORGE_BUS) DistExecutor.safeRunWhenOn(Dist.CLIENT) { SafeRunnable(AdornClient::init) } // TODO: Compat.init(MOD_BUS) } + + private fun init(event: FMLCommonSetupEvent) { + AdornStats.init() + } }