Compare commits

..
Author SHA1 Message Date
Paul 9a0f389c6b experimenting with entity bound battle code 2024-07-08 20:16:03 -04:00
987 changed files with 1967 additions and 34317 deletions

No files matched your search

-1
View File
@@ -3,4 +3,3 @@
# are changed when only line endings change.
src/generated/**/.cache/cache text eol=lf
src/generated/**/*.json text eol=lf
CHANGELOG.md merge=union
+1 -28
View File
@@ -1,32 +1,5 @@
# Changelog
## [1.5.3](#1-5-3)
### Fixes
- Scaled down Amaura's fetus model to avoid clipping through the tank while animating
- Added Polished Tumblestone and Tumblestone Brick block sets from Tumblestone, Black Tumblestone, and Sky Tumblestone.
- Fixed Cubone's cry not having a sound.
- Fixed the Seafloor spawning context not being a usable context.
- Fixed Pokemon spawning in non-full blocks like slabs.
- Fixed Gilded Chests not dropping the chest itself when broken, only the contents.
- Fixed Pokémon losing their Hidden Ability through evolution if the middle stage did not have a Hidden Ability.
### Additions
- Added extra visuals to early berry growth stages
### Added cries to the following Pokémon
- Timburr, Gurdurr, Conkeldurr
- Golett, Golurk
### Changes
- Altered the item model for Medicinal Leeks and Roasted Leeks to be held like sticks and other rod items.
- Adjusted some berry balance values like yield and growth times
- Changes to mulch buffs/durations
### Developer
### Data Pack & Resource Pack Creators
- Added support for "shedders" similar to Shedinja's evolution logic.
## [1.5.2 (May 27th, 2024)](#1-5-2)
### Fixes
- Fixed Wooloo and Dubwool dyeing making your game start dying. Only if you do it on a server.
@@ -110,7 +83,7 @@
- Fixed a bunch of spam during world generation.
- Fixed a bug in which throwing a Poké Ball at a player owned Pokémon with the ability Illusion would reveal its true species. Hilarious meta strategy.
- Fixed root-part animations not working for JSON posed Pokémon. You didn't notice this but if we didn't fix this in this update then if you use Quick Attack a lot you'd have seen a whole lot of [this](https://cdn.discordapp.com/attachments/1076993968803434627/1242660506783715369/Minecraft__1.20.1_-_Singleplayer_2024-05-21_22-08-17.mp4?ex=66549408&is=66534288&hm=ff95ee293eb15634fd63e6546534ea279540a1c892605e8d561593ca2c5600c5&) which is damn funny but very unintended.
### Developer
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. Provides more information this way.
- Added an event that fires when a fossil is revived, with or without a player.
@@ -1,72 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.SaccharineLeafBlock;
import net.minecraft.block.*;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.Flutterer;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.Angerable;
import net.minecraft.entity.mob.PathAwareEntity;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.passive.BeeEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldView;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Desc;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(targets="net.minecraft.entity.passive.BeeEntity$GrowCropsGoal")
public abstract class BeeEntityMixin {
@Unique
private BlockState cobblemon$result = null;
@Inject(method = "tick()V", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/Fertilizable;grow(Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/util/math/random/Random;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V",
shift = At.Shift.BY,
by = 2
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
if (block instanceof SaccharineLeafBlock) {
int age = blockState.get(SaccharineLeafBlock.Companion.getAGE());
if (age < 2) {
this.cobblemon$result = blockState.with(SaccharineLeafBlock.Companion.getAGE(), age + 1);
}
}
}
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
private BlockState applyCustomBlockState(BlockState before) {
if(this.cobblemon$result != null && before == null) {
BlockState result = this.cobblemon$result;
this.cobblemon$result = null;
return result;
}
return before;
}
}
@@ -1,16 +0,0 @@
package com.cobblemon.mod.common.mixin.invoker;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.ScreenHandlerType.Factory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ScreenHandlerType.class)
public interface ScreenHandlerTypeInvoker {
@Invoker("<init>")
static <T extends ScreenHandler> ScreenHandlerType<T> cobblemon$create(Factory<T> factory, FeatureSet requiredFeatures) {
throw new UnsupportedOperationException();
}
}
@@ -371,6 +371,36 @@ object Cobblemon {
BATTLE_VICTORY.subscribe { AdvancementHandler.onWinBattle(it) }
EVOLUTION_COMPLETE.subscribe(Priority.LOWEST) { event ->
AdvancementHandler.onEvolve(event)
val pokemon = event.pokemon
val ninjaskIdentifier = cobblemonResource("ninjask")
// Ensure the config option is enabled and that the result was a ninjask and that shedinja exists
if (this.config.ninjaskCreatesShedinja && pokemon.species.resourceIdentifier == ninjaskIdentifier && PokemonSpecies.getByIdentifier(Pokemon.SHEDINJA) != null) {
val player = pokemon.getOwnerPlayer() ?: return@subscribe
if (player.isCreative || player.inventory.containsAny { it.item is PokeBallItem }) {
var pokeball = Items.AIR
player.inventory.combinedInventory.forEach {
it.forEach {
itemStack -> if (itemStack.item is PokeBallItem && pokeball == Items.AIR) {
pokeball = itemStack.item as PokeBallItem
}
}
}
if (!player.isCreative) {
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
}
if (pokeball == Items.AIR) {
pokeball = CobblemonItems.POKE_BALL
}
val properties = event.evolution.result.copy()
properties.species = Pokemon.SHEDINJA.toString()
val product = pokemon.clone()
product.removeHeldItem()
properties.apply(product)
product.caughtBall = (pokeball as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(product)
CobblemonCriteria.EVOLVE_POKEMON.trigger(player, EvolvePokemonContext(event.pokemon.preEvolution!!.species.resourceIdentifier, product.species.resourceIdentifier, playerData.get(player).advancementData.totalEvolvedCount))
}
}
}
LEVEL_UP_EVENT.subscribe { AdvancementHandler.onLevelUp(it) }
TRADE_COMPLETED.subscribe { AdvancementHandler.onTradeCompleted(it) }
@@ -83,9 +83,4 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
)
@JvmField
val COOKING_POT: BlockEntityType<CookingPotBlockEntity> = this.create("cooking_pot",
BlockEntityType.Builder.create(::CookingPotBlockEntity, CobblemonBlocks.COOKING_POT).build(null)
)
}
@@ -28,7 +28,6 @@ import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import net.minecraft.block.*
import net.minecraft.block.AbstractBlock.Settings
import net.minecraft.block.enums.Instrument
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.effect.StatusEffects
@@ -50,8 +49,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val APRICORN_BLOCK_SET_TYPE = BlockSetType("apricorn")
val APRICORN_WOOD_TYPE = WoodType.register(WoodType("apricorn", APRICORN_BLOCK_SET_TYPE))
val SACCHARINE_BLOCK_SET_TYPE = BlockSetType("saccharine")
val SACCHARINE_WOOD_TYPE = WoodType.register(WoodType("saccharine", SACCHARINE_BLOCK_SET_TYPE))
// Evolution Ores
@JvmField
@@ -156,52 +153,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
// Saccharines
@JvmField
val SACCHARINE_LOG = log("saccharine_log", arg2 = MapColor.BLUE)
@JvmField
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", SaccharineStrippedLogBlock(Settings.create().mapColor(MapColor.LIGHT_BLUE).instrument(Instrument.BASS).strength(2.0F).sounds(BlockSoundGroup.WOOD).burnable())) //log("stripped_saccharine_log")
@JvmField
val SACCHARINE_WOOD = log("saccharine_wood")
@JvmField
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", SaccharineStrippedLogBlock(Settings.create().mapColor(MapColor.LIGHT_BLUE).instrument(Instrument.BASS).strength(2.0F).sounds(BlockSoundGroup.WOOD).burnable())) //log("stripped_saccharine_log")
//log("stripped_saccharine_wood")
@JvmField
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.LIGHT_BLUE).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val SACCHARINE_LEAVES = this.create("saccharine_leaves", SaccharineLeafBlock(Settings.create().mapColor(MapColor.LIGHT_BLUE).strength(0.2F).ticksRandomly().sounds(BlockSoundGroup.GRASS).nonOpaque().allowsSpawning { _, _, _, _ -> false }))
@JvmField
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(SACCHARINE_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(SACCHARINE_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), SACCHARINE_WOOD_TYPE))
@JvmField // Note At the time of 1.20.0 we don't need our own BlockSetType for SACCHARINE wood
val SACCHARINE_BUTTON = this.create("saccharine_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(SACCHARINE_PLANKS.defaultMapColor).instrument(Instrument.BASS).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), SACCHARINE_BLOCK_SET_TYPE))
@JvmField
val SACCHARINE_SIGN = this.create("saccharine_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_SLAB = this.create("saccharine_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val SACCHARINE_STAIRS = this.create("saccharine_stairs", StairsBlockInvoker.`cobblemon$create`(SACCHARINE_PLANKS.defaultState, AbstractBlock.Settings.copy(SACCHARINE_PLANKS)))
@JvmField
val SACCHARINE_DOOR = this.create("saccharine_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(SACCHARINE_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), SACCHARINE_BLOCK_SET_TYPE))
@JvmField
val SACCHARINE_TRAPDOOR = this.create("saccharine_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, SACCHARINE_BLOCK_SET_TYPE))
@JvmField
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaccharineSaplingBlock(PLANT_PROPERTIES))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val BUGWORT = this.create("bugwort", BugwortBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.PALE_PURPLE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
@@ -260,213 +214,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_TUMBLESTONE = this.create("polished_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_TUMBLESTONE_STAIRS = this.create("polished_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(POLISHED_TUMBLESTONE.defaultState, AbstractBlock.Settings.copy(POLISHED_TUMBLESTONE)))
@JvmField
val POLISHED_TUMBLESTONE_SLAB = this.create("polished_tumblestone_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_TUMBLESTONE_WALL = this.create("polished_tumblestone_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_POLISHED_TUMBLESTONE = this.create("chiseled_polished_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val TUMBLESTONE_BRICKS = this.create("tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val TUMBLESTONE_BRICK_STAIRS = this.create("tumblestone_brick_stairs", StairsBlockInvoker.`cobblemon$create`(TUMBLESTONE_BRICKS.defaultState, AbstractBlock.Settings.copy(TUMBLESTONE_BRICKS)))
@JvmField
val TUMBLESTONE_BRICK_SLAB = this.create("tumblestone_brick_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val TUMBLESTONE_BRICK_WALL = this.create("tumblestone_brick_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_TUMBLESTONE_BRICKS = this.create("chiseled_tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_SKY_TUMBLESTONE = this.create("polished_sky_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_SKY_TUMBLESTONE_STAIRS = this.create("polished_sky_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(POLISHED_SKY_TUMBLESTONE.defaultState, AbstractBlock.Settings.copy(POLISHED_SKY_TUMBLESTONE)))
@JvmField
val POLISHED_SKY_TUMBLESTONE_SLAB = this.create("polished_sky_tumblestone_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_SKY_TUMBLESTONE_WALL = this.create("polished_sky_tumblestone_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_POLISHED_SKY_TUMBLESTONE = this.create("chiseled_polished_sky_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BRICKS = this.create("sky_tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BRICK_STAIRS = this.create("sky_tumblestone_brick_stairs", StairsBlockInvoker.`cobblemon$create`(
SKY_TUMBLESTONE_BRICKS.defaultState, AbstractBlock.Settings.copy(SKY_TUMBLESTONE_BRICKS)))
@JvmField
val SKY_TUMBLESTONE_BRICK_SLAB = this.create("sky_tumblestone_brick_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BRICK_WALL = this.create("sky_tumblestone_brick_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_SKY_TUMBLESTONE_BRICKS = this.create("chiseled_sky_tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_BLACK_TUMBLESTONE = this.create("polished_black_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_BLACK_TUMBLESTONE_STAIRS = this.create("polished_black_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(POLISHED_BLACK_TUMBLESTONE.defaultState, AbstractBlock.Settings.copy(POLISHED_BLACK_TUMBLESTONE)))
@JvmField
val POLISHED_BLACK_TUMBLESTONE_SLAB = this.create("polished_black_tumblestone_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val POLISHED_BLACK_TUMBLESTONE_WALL = this.create("polished_black_tumblestone_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_POLISHED_BLACK_TUMBLESTONE = this.create("chiseled_polished_black_tumblestone", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BRICKS = this.create("black_tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BRICK_STAIRS = this.create("black_tumblestone_brick_stairs", StairsBlockInvoker.`cobblemon$create`(
BLACK_TUMBLESTONE_BRICKS.defaultState, AbstractBlock.Settings.copy(BLACK_TUMBLESTONE_BRICKS)))
@JvmField
val BLACK_TUMBLESTONE_BRICK_SLAB = this.create("black_tumblestone_brick_slab", SlabBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BRICK_WALL = this.create("black_tumblestone_brick_wall", WallBlock(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val CHISELED_BLACK_TUMBLESTONE_BRICKS = this.create("chiseled_black_tumblestone_bricks", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
@@ -654,32 +401,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
)
@JvmField
val COOKING_POT = create(
"cooking_pot",
CookingPotBlock(
Settings.create()
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.STONE_GRAY)
.strength(0.3f)
)
)
@JvmField
val SWEET_INCENSE = create(
"sweet_incense",
SweetIncenseBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.STONE_GRAY)
.strength(0.3f)
)
)
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@@ -720,9 +441,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
*/
fun strippedBlocks(): Map<Block, Block> = mapOf(
APRICORN_WOOD to STRIPPED_APRICORN_WOOD,
APRICORN_LOG to STRIPPED_APRICORN_LOG,
SACCHARINE_WOOD to STRIPPED_SACCHARINE_WOOD,
SACCHARINE_LOG to STRIPPED_SACCHARINE_LOG
APRICORN_LOG to STRIPPED_APRICORN_LOG
)
@@ -809,7 +528,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val WEPEAR_BERRY = this.berryBlock("wepear")
val WIKI_BERRY = this.berryBlock("wiki")
val YACHE_BERRY = this.berryBlock("yache")
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(AbstractBlock.Settings.create()))
init {
/**
@@ -874,14 +592,4 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val block = BlocksInvoker.createLeavesBlock(BlockSoundGroup.GRASS)
return this.create(name, block)
}
/**
* Helper method for creating saccharine leaves
* similar to Vanilla
private fun saccharineLeaves(name: String): SaccharineLeafBlock {
val block = BlocksInvoker.createLeavesBlock(BlockSoundGroup.GRASS)
return this.create(name, block)
}*/
}
@@ -48,6 +48,7 @@ object CobblemonCommands {
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
OpenDialogueCommand.register(dispatcher)
ChallengeCommand.register(dispatcher)
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
@@ -26,7 +26,6 @@ import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader
import net.minecraft.resource.ResourceType
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
@@ -159,8 +158,6 @@ interface CobblemonImplementation {
*/
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
fun registerScreenHandlerType(identifier: Identifier, screenHandlerType: ScreenHandlerType<*>)
/**
* TODO
*
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.BugwortBlock
import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
@@ -24,7 +23,6 @@ import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.item.berry.FriendshipRaisingBerryItem
import com.cobblemon.mod.common.item.berry.HealingBerryItem
import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
@@ -244,57 +242,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
// Saccharines
@JvmField
val SACCHARINE_LOG = blockItem("saccharine_log", CobblemonBlocks.SACCHARINE_LOG)
@JvmField
val STRIPPED_SACCHARINE_LOG = blockItem("stripped_saccharine_log", CobblemonBlocks.STRIPPED_SACCHARINE_LOG)
@JvmField
val SACCHARINE_WOOD = blockItem("saccharine_wood", CobblemonBlocks.SACCHARINE_WOOD)
@JvmField
val STRIPPED_SACCHARINE_WOOD = blockItem("stripped_saccharine_wood", CobblemonBlocks.STRIPPED_SACCHARINE_WOOD)
@JvmField
val SACCHARINE_PLANKS = blockItem("saccharine_planks", CobblemonBlocks.SACCHARINE_PLANKS)
@JvmField
val SACCHARINE_LEAVES = compostableBlockItem("saccharine_leaves", CobblemonBlocks.SACCHARINE_LEAVES)
@JvmField
val SACCHARINE_BOAT = create("saccharine_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, false, Item.Settings().maxCount(1)))
@JvmField
val SACCHARINE_CHEST_BOAT = create("saccharine_chest_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, true, Item.Settings().maxCount(1)))
@JvmField
val SACCHARINE_DOOR = blockItem("saccharine_door", CobblemonBlocks.SACCHARINE_DOOR)
@JvmField
val SACCHARINE_TRAPDOOR = blockItem("saccharine_trapdoor", CobblemonBlocks.SACCHARINE_TRAPDOOR)
@JvmField
val SACCHARINE_FENCE = blockItem("saccharine_fence", CobblemonBlocks.SACCHARINE_FENCE)
@JvmField
val SACCHARINE_FENCE_GATE = blockItem("saccharine_fence_gate", CobblemonBlocks.SACCHARINE_FENCE_GATE)
@JvmField
val SACCHARINE_BUTTON = blockItem("saccharine_button", CobblemonBlocks.SACCHARINE_BUTTON)
@JvmField
val SACCHARINE_PRESSURE_PLATE = blockItem("saccharine_pressure_plate", CobblemonBlocks.SACCHARINE_PRESSURE_PLATE)
@JvmField
val SACCHARINE_SLAB = blockItem("saccharine_slab", CobblemonBlocks.SACCHARINE_SLAB)
@JvmField
val SACCHARINE_STAIRS = blockItem("saccharine_stairs", CobblemonBlocks.SACCHARINE_STAIRS)
@JvmField
val SACCHARINE_SIGN = this.create("saccharine_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", HangingSignItem(CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
@JvmField
val SACCHARINE_SAPLING = saccharineSaplingItem("saccharine_sapling", SaccharineSaplingItem(CobblemonBlocks.SACCHARINE_SAPLING))
@JvmField
val SWEET_SAP = noSettingsItem("sweet_sap")
@JvmField
val BUGWORT = bugwortItem("bugwort", BugwortItem(CobblemonBlocks.BUGWORT))
@JvmField
val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
@JvmField
val STICKY_GLOB = this.create("sticky_glob", StickyGlobItem(Item.Settings()))
@JvmField
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
@JvmField
@@ -309,10 +256,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val COOKING_POT = blockItem("cooking_pot", CobblemonBlocks.COOKING_POT)
@JvmField
val SWEET_INCENSE = blockItem("sweet_incense", CobblemonBlocks.SWEET_INCENSE)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -989,67 +932,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
@JvmField
val POLISHED_TUMBLESTONE = blockItem("polished_tumblestone", CobblemonBlocks.POLISHED_TUMBLESTONE)
@JvmField
val POLISHED_TUMBLESTONE_STAIRS = blockItem("polished_tumblestone_stairs", CobblemonBlocks.POLISHED_TUMBLESTONE_STAIRS)
@JvmField
val POLISHED_TUMBLESTONE_SLAB = blockItem("polished_tumblestone_slab", CobblemonBlocks.POLISHED_TUMBLESTONE_SLAB)
@JvmField
val POLISHED_TUMBLESTONE_WALL = blockItem("polished_tumblestone_wall", CobblemonBlocks.POLISHED_TUMBLESTONE_WALL)
@JvmField
val CHISELED_POLISHED_TUMBLESTONE = blockItem("chiseled_polished_tumblestone", CobblemonBlocks.CHISELED_POLISHED_TUMBLESTONE)
@JvmField
val TUMBLESTONE_BRICKS = blockItem("tumblestone_bricks", CobblemonBlocks.TUMBLESTONE_BRICKS)
@JvmField
val TUMBLESTONE_BRICK_STAIRS = blockItem("tumblestone_brick_stairs", CobblemonBlocks.TUMBLESTONE_BRICK_STAIRS)
@JvmField
val TUMBLESTONE_BRICK_SLAB = blockItem("tumblestone_brick_slab", CobblemonBlocks.TUMBLESTONE_BRICK_SLAB)
@JvmField
val TUMBLESTONE_BRICK_WALL = blockItem("tumblestone_brick_wall", CobblemonBlocks.TUMBLESTONE_BRICK_WALL)
@JvmField
val CHISELED_TUMBLESTONE_BRICKS = blockItem("chiseled_tumblestone_bricks", CobblemonBlocks.CHISELED_TUMBLESTONE_BRICKS)
@JvmField
val POLISHED_SKY_TUMBLESTONE = blockItem("polished_sky_tumblestone", CobblemonBlocks.POLISHED_SKY_TUMBLESTONE)
@JvmField
val POLISHED_SKY_TUMBLESTONE_STAIRS = blockItem("polished_sky_tumblestone_stairs", CobblemonBlocks.POLISHED_SKY_TUMBLESTONE_STAIRS)
@JvmField
val POLISHED_SKY_TUMBLESTONE_SLAB = blockItem("polished_sky_tumblestone_slab", CobblemonBlocks.POLISHED_SKY_TUMBLESTONE_SLAB)
@JvmField
val POLISHED_SKY_TUMBLESTONE_WALL = blockItem("polished_sky_tumblestone_wall", CobblemonBlocks.POLISHED_SKY_TUMBLESTONE_WALL)
@JvmField
val CHISELED_POLISHED_SKY_TUMBLESTONE = blockItem("chiseled_polished_sky_tumblestone", CobblemonBlocks.CHISELED_POLISHED_SKY_TUMBLESTONE)
@JvmField
val SKY_TUMBLESTONE_BRICKS = blockItem("sky_tumblestone_bricks", CobblemonBlocks.SKY_TUMBLESTONE_BRICKS)
@JvmField
val SKY_TUMBLESTONE_BRICK_STAIRS = blockItem("sky_tumblestone_brick_stairs", CobblemonBlocks.SKY_TUMBLESTONE_BRICK_STAIRS)
@JvmField
val SKY_TUMBLESTONE_BRICK_SLAB = blockItem("sky_tumblestone_brick_slab", CobblemonBlocks.SKY_TUMBLESTONE_BRICK_SLAB)
@JvmField
val SKY_TUMBLESTONE_BRICK_WALL = blockItem("sky_tumblestone_brick_wall", CobblemonBlocks.SKY_TUMBLESTONE_BRICK_WALL)
@JvmField
val CHISELED_SKY_TUMBLESTONE_BRICKS = blockItem("chiseled_sky_tumblestone_bricks", CobblemonBlocks.CHISELED_SKY_TUMBLESTONE_BRICKS)
@JvmField
val POLISHED_BLACK_TUMBLESTONE = blockItem("polished_black_tumblestone", CobblemonBlocks.POLISHED_BLACK_TUMBLESTONE)
@JvmField
val POLISHED_BLACK_TUMBLESTONE_STAIRS = blockItem("polished_black_tumblestone_stairs", CobblemonBlocks.POLISHED_BLACK_TUMBLESTONE_STAIRS)
@JvmField
val POLISHED_BLACK_TUMBLESTONE_SLAB = blockItem("polished_black_tumblestone_slab", CobblemonBlocks.POLISHED_BLACK_TUMBLESTONE_SLAB)
@JvmField
val POLISHED_BLACK_TUMBLESTONE_WALL = blockItem("polished_black_tumblestone_wall", CobblemonBlocks.POLISHED_BLACK_TUMBLESTONE_WALL)
@JvmField
val CHISELED_POLISHED_BLACK_TUMBLESTONE = blockItem("chiseled_polished_black_tumblestone", CobblemonBlocks.CHISELED_POLISHED_BLACK_TUMBLESTONE)
@JvmField
val BLACK_TUMBLESTONE_BRICKS = blockItem("black_tumblestone_bricks", CobblemonBlocks.BLACK_TUMBLESTONE_BRICKS)
@JvmField
val BLACK_TUMBLESTONE_BRICK_STAIRS = blockItem("black_tumblestone_brick_stairs", CobblemonBlocks.BLACK_TUMBLESTONE_BRICK_STAIRS)
@JvmField
val BLACK_TUMBLESTONE_BRICK_SLAB = blockItem("black_tumblestone_brick_slab", CobblemonBlocks.BLACK_TUMBLESTONE_BRICK_SLAB)
@JvmField
val BLACK_TUMBLESTONE_BRICK_WALL = blockItem("black_tumblestone_brick_wall", CobblemonBlocks.BLACK_TUMBLESTONE_BRICK_WALL)
@JvmField
val CHISELED_BLACK_TUMBLESTONE_BRICKS = blockItem("chiseled_black_tumblestone_bricks", CobblemonBlocks.CHISELED_BLACK_TUMBLESTONE_BRICKS)
@JvmField
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
"automaton_armor_trim_smithing_template",
@@ -1103,8 +985,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val STEEL_GEM = noSettingsItem("steel_gem")
@JvmField
val FAIRY_GEM = noSettingsItem("fairy_gem")
//@JvmField
//val BINDING_SOIL = blockItem("binding_soil", CobblemonBlocks.BINDING_SOIL)
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
@@ -1181,20 +1061,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
return item
}
private fun saccharineSaplingItem(name: String, saccharineSaplingItem: SaccharineSaplingItem): SaccharineSaplingItem {
val finalName = "saccharine_sapling"
val item = this.create(finalName, saccharineSaplingItem)
compostable(item, .65f)
return item
}
private fun bugwortItem(name: String, bugwortItem: BugwortItem): BugwortItem {
val finalName = "bugwort"
val item = this.create(finalName, bugwortItem)
compostable(item, .65f)
return item
}
private fun mintSeed(name: String, mintBlock: MintBlock): Item {
val finalName = "${name}_mint_seeds"
val item = this.blockItem(finalName, mintBlock)
@@ -16,7 +16,7 @@ import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.util.readBox
import com.cobblemon.mod.common.util.writeBox
@@ -45,8 +45,9 @@ import net.minecraft.world.biome.Biome
* @property identifier The [Identifier] of this berry.
* @property baseYield The [IntRange] possible for the berry tree before [bonusYield] is calculated.
* @property preferredBiomeTags The [TagKey]s of the berries preffered biomes. Determines spawning and yield
* @property growthTime The [IntRange] possible in minutes for how long the berry tree takes to grow frome age 0 to age 3
* @property refreshRate The [IntRange] possible in minutes for how long the berry tree takes to grow from age 3 to age 5
* @property growthTime The [IntRange] possible in minutes for how long the berry tree takes to grow.
* @property refreshRate The [IntRange] possible in minutes for how long the berry tree takes to regrow its berries once it has been harvested.
* @depreciated @property lifeCycles The [IntRange] possible for the berry to live for between harvests.
* @property favoriteMulches The types of mulches that benefit this berries yield
* @property growthFactors An array of [GrowthFactor]s that will affect this berry. The client is not aware of these.
* @property mutations A map of the partner berry as the key and the value as the resulting mutation with this berry.
@@ -59,7 +60,6 @@ import net.minecraft.world.biome.Biome
* @property flowerTexture The [Identifier] for the texture of the berry in flower form. This is resolved into a [ModelPart] on the client.
* @property fruitModelIdentifier The [Identifier] for the model of the berry in flower form. This is resolved into a [ModelPart] on the client.
* @property fruitTexture The [Identifier] for the texture of the berry in flower form.
* @property stageOnePositioning Transformation of the berry model for age 0
*
* @throws IllegalArgumentException if the any yield range argument is not a positive range.
*/
@@ -69,6 +69,7 @@ class Berry(
val preferredBiomeTags: List<TagKey<Biome>>,
val growthTime: IntRange,
val refreshRate: IntRange,
//val lifeCycles: IntRange,
val favoriteMulches: EnumSet<MulchVariant>,
val growthFactors: Collection<GrowthFactor>,
val spawnConditions: List<BerrySpawnCondition>,
@@ -87,9 +88,7 @@ class Berry(
@SerializedName("fruitModel")
val fruitModelIdentifier: Identifier,
val fruitTexture: Identifier,
val stageOnePositioning: GrowthPoint,
val weight: Float,
val boneMealChance: Float
val weight: Float
) {
@Transient
@@ -162,9 +161,8 @@ class Berry(
val bonus = this.bonusYield(world, state, pos)
var yield = base + bonus.first
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (BerryBlock.getMulch(treeEntity) == MulchVariant.RICH) {
//I hope the upper bound isnt exclusive, especially when there's a method called nextBetweenExclusive
yield += world.random.nextBetween(1, 3)
if (BerryBlock.getMulch(state) == MulchVariant.RICH) {
yield = min(yield + 1, maxYield())
treeEntity.decrementMulchDuration(world, pos, state)
}
val event = BerryYieldCalculationEvent(this, world, state, pos, placer, yield, bonus.second)
@@ -281,13 +279,6 @@ class Berry(
buffer.writeIdentifier(this.flowerTexture)
buffer.writeIdentifier(this.fruitModelIdentifier)
buffer.writeIdentifier(this.fruitTexture)
buffer.writeDouble(stageOnePositioning.position.x)
buffer.writeDouble(stageOnePositioning.position.y)
buffer.writeDouble(stageOnePositioning.position.z)
buffer.writeDouble(stageOnePositioning.rotation.x)
buffer.writeDouble(stageOnePositioning.rotation.y)
buffer.writeDouble(stageOnePositioning.rotation.z)
buffer.writeFloat(boneMealChance)
}
/**
@@ -301,8 +292,7 @@ class Berry(
private fun bonusYield(world: World, state: BlockState, pos: BlockPos): Pair<Int, Collection<GrowthFactor>> {
var bonus = 0
val passed = arrayListOf<GrowthFactor>()
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return 0 to passed
val mulchVariant = BerryBlock.getMulch(treeEntity)
val mulchVariant = BerryBlock.getMulch(state)
val hasBiomeMulch = mulchVariant in favoriteMulches
this.growthFactors.forEach { factor ->
if (factor.isValid(world, state, pos)) {
@@ -349,9 +339,7 @@ class Berry(
val flowerTexture = buffer.readIdentifier()
val fruitModelIdentifier = buffer.readIdentifier()
val fruitTexture = buffer.readIdentifier()
val stageOneYPos = GrowthPoint(Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()), Vec3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()))
val boneMealChance = buffer.readFloat()
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, stageOneYPos, 0F, boneMealChance)
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, 0F)
}
}
@@ -8,30 +8,24 @@
package com.cobblemon.mod.common.api.mulch
import com.cobblemon.mod.common.BakingOverride
import com.cobblemon.mod.common.client.CobblemonBakingOverrides
import net.minecraft.util.StringIdentifiable
/**
* Represents the different types of Mulch implemented in the mod.
*
*/
enum class MulchVariant(val model: BakingOverride?, val duration: Int = -1) : StringIdentifiable {
COARSE(CobblemonBakingOverrides.COARSE_MULCH),
GROWTH(CobblemonBakingOverrides.GROWTH_MULCH, 5),
HUMID(CobblemonBakingOverrides.HUMID_MULCH),
LOAMY(CobblemonBakingOverrides.LOAMY_MULCH),
PEAT(CobblemonBakingOverrides.PEAT_MULCH),
RICH(CobblemonBakingOverrides.RICH_MULCH, 5),
SANDY(CobblemonBakingOverrides.SANDY_MULCH),
SURPRISE(CobblemonBakingOverrides.SURPRISE_MULCH, 3),
NONE(null);
enum class MulchVariant(val duration: Int = -1) : StringIdentifiable {
COARSE,
GROWTH(3),
HUMID,
LOAMY,
PEAT,
RICH(3),
SANDY,
SURPRISE(3),
NONE;
override fun asString(): String {
return name.lowercase()
}
companion object {
const val GROWTH_TIME_MULTIPLIER = 0.5
}
}
@@ -8,11 +8,7 @@
package com.cobblemon.mod.common.api.pokemon.evolution
import com.cobblemon.mod.common.Cobblemon.playerData
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
@@ -21,9 +17,7 @@ import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
@@ -31,7 +25,6 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.party
import net.minecraft.item.ItemStack
import net.minecraft.sound.SoundCategory
@@ -51,11 +44,6 @@ interface Evolution : EvolutionLike {
*/
val result: PokemonProperties
/**
* The shed result of this evolution.
*/
val shedder: PokemonProperties?
/**
* If this evolution allows the user to choose when to start it or not.
*/
@@ -107,36 +95,6 @@ interface Evolution : EvolutionLike {
return true
}
fun shed(pokemon: Pokemon): Boolean {
val innerShedder = shedder ?: return false
val owner = pokemon.getOwnerPlayer() ?: return false
// If the player has at least one Pokeball in their inventory.
var pokeballStack: ItemStack? = null
if (!owner.isCreative) {
for (i in 0 until owner.inventory.size()) {
val stackI = owner.inventory.getStack(i)
if (stackI.isIn(CobblemonItemTags.POKE_BALLS)) {
pokeballStack = stackI
}
}
if (pokeballStack == null) return false
}
// If the player has at least one empty spot in their party.
val emptySlot = owner.party().getFirstAvailablePosition() ?: return false
// Add shed Pokemon to player's party
val shedPokemon = pokemon.clone()
shedPokemon.removeHeldItem()
innerShedder.apply(shedPokemon)
shedPokemon.caughtBall = ((pokeballStack?.item ?: CobblemonItems.POKE_BALL) as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(shedPokemon)
CobblemonCriteria.EVOLVE_POKEMON.trigger(owner, EvolvePokemonContext(pokemon.preEvolution!!.species.resourceIdentifier, shedPokemon.species.resourceIdentifier, playerData.get(owner).advancementData.totalEvolvedCount))
// Consume one of the balls
pokeballStack?.decrement(1)
return true
}
/**
* Starts this evolution as soon as possible.
@@ -197,7 +155,6 @@ interface Evolution : EvolutionLike {
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
this.shed(pokemon)
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
}
@@ -10,7 +10,12 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.entity.Despawner
import com.cobblemon.mod.common.api.spawning.condition.*
import com.cobblemon.mod.common.api.spawning.condition.AreaSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.BasicSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.GroundedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.GroundedSpawningContext
import com.cobblemon.mod.common.api.spawning.context.LavafloorSpawningContext
@@ -86,7 +91,6 @@ object BestSpawner {
SpawningCondition.register(SubmergedSpawningCondition.NAME, SubmergedSpawningCondition::class.java)
SpawningCondition.register(GroundedSpawningCondition.NAME, GroundedSpawningCondition::class.java)
SpawningCondition.register(SurfaceSpawningCondition.NAME, SurfaceSpawningCondition::class.java)
SpawningCondition.register(SeafloorSpawningCondition.NAME, SeafloorSpawningCondition::class.java)
LOGGER.info("Loaded ${SpawningCondition.conditionTypes.size} spawning condition types.")
SpawningContextCalculator.register(GroundedSpawningContextCalculator)
@@ -96,7 +100,7 @@ object BestSpawner {
SpawningContextCalculator.register(SurfaceSpawningContextCalculator)
SpawningContext.register(name = "grounded", clazz = GroundedSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "seafloor", clazz = SeafloorSpawningContext::class.java, defaultCondition = SeafloorSpawningCondition.NAME)
SpawningContext.register(name = "seafloor", clazz = SeafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "lavafloor", clazz = LavafloorSpawningContext::class.java, defaultCondition = GroundedSpawningCondition.NAME)
SpawningContext.register(name = "submerged", clazz = SubmergedSpawningContext::class.java, defaultCondition = SubmergedSpawningCondition.NAME)
SpawningContext.register(name = "surface", clazz = SurfaceSpawningContext::class.java, defaultCondition = SurfaceSpawningCondition.NAME)
@@ -1,58 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.condition
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.spawning.context.SeafloorSpawningContext
import com.cobblemon.mod.common.util.Merger
import net.minecraft.block.Block
/**
* Base type for a spawning condition that applies to some kind of [SeafloorSpawningContext]. This
* can be extended for subclasses of [SeafloorSpawningContext].
*
* Borrowed the Grounded context code since it was unintentionally spawning Pokémon on the sea floor
* already. Seems to be working fine /shrug
*
* @author FrankTheFarmer
* @since May 22nd, 2024
*/
abstract class SeafloorTypeSpawningCondition<T : SeafloorSpawningContext> : AreaTypeSpawningCondition<T>() {
var neededBaseBlocks: MutableList<RegistryLikeCondition<Block>>? = null
override fun fits(ctx: T): Boolean {
return if (!super.fits(ctx)) {
false
} else if (minHeight != null && ctx.height < minHeight!!) {
return false
} else if (maxHeight != null && ctx.height > maxHeight!!) {
return false
} else !(neededBaseBlocks != null && neededBaseBlocks!!.none { it.fits(ctx.baseBlock.block, ctx.blockRegistry) })
}
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
super.copyFrom(other, merger)
if (other is SeafloorTypeSpawningCondition) {
neededBaseBlocks = merger.merge(neededBaseBlocks, other.neededBaseBlocks)?.toMutableList()
}
}
}
/**
* A spawning condition for a [SeafloorSpawningContext].
*
* @author FrankTheFarmer
* @since May 22nd, 2024
*/
open class SeafloorSpawningCondition : SeafloorTypeSpawningCondition<SeafloorSpawningContext>() {
override fun contextClass() = SeafloorSpawningContext::class.java
companion object {
const val NAME = "seafloor"
}
}
@@ -49,7 +49,7 @@ open class AreaSpawningContext(
* This is not considering the provided state as what the entity would be on top of,
* but rather the space its hitbox would fill.
*/
open fun isSafeSpace(world: ServerWorld, pos: BlockPos, state: BlockState): Boolean = !state.isSolid
open fun isSafeSpace(world: ServerWorld, pos: BlockPos, state: BlockState): Boolean = !state.isFullCube(world, pos)
override fun postFilter(detail: SpawnDetail): Boolean {
if (!super.postFilter(detail)) {
@@ -34,8 +34,7 @@ class BestSpawnerConfig {
val contextWeights = mutableMapOf(
"grounded" to 1F,
"submerged" to 0.99F,
"surface" to 0.01F,
"seafloor" to 1F
"surface" to 0.01F
)
val buckets = mutableListOf(
SpawnBucket("common", 93.8F),
@@ -24,7 +24,6 @@ object CobblemonBlockTags {
@JvmField val ALL_HANGING_SIGNS = createTag("all_hanging_signs")
@JvmField val ALL_SIGNS = createTag("all_signs")
@JvmField val ALL_SAPLINGS = createTag("all_saplings")
@JvmField val APRICORN_LEAVES = createTag("apricorn_leaves")
@JvmField val APRICORN_LOGS = createTag("apricorn_logs")
@JvmField val APRICORN_SAPLINGS = createTag("apricorn_saplings")
@@ -38,7 +37,6 @@ object CobblemonBlockTags {
@JvmField val DRIPSTONE_REPLACEABLES = createTag("dripstone_replaceables")
@JvmField val FLOWERS = createTag("flowers")
@JvmField val MEDICINAL_LEEK_PLANTABLE = createTag("medicinal_leek_plantable")
@JvmField val BUGWORT_PLANTABLE = createTag("bugwort_plantable")
@JvmField val MINTS = createTag("mints")
@JvmField val ROOTS_SPREADABLE = createTag("roots_spreadable")
@JvmField val SIGNS = createTag("signs")
@@ -46,9 +44,6 @@ object CobblemonBlockTags {
@JvmField val SEES_SKY = createTag("sees_sky")
@JvmField val SNOW_BLOCK = createTag("snow_block")
@JvmField val ROOTS = createTag("roots")
@JvmField val SACCHARINE_LEAVES = createTag("saccharine_leaves")
@JvmField val SACCHARINE_LOGS = createTag("saccharine_logs")
@JvmField val SACCHARINE_SAPLING = createTag("saccharine_sapling")
@JvmField val STANDING_SIGNS = createTag("standing_signs")
@JvmField val TUMBLESTONE_HEAT_SOURCE = createTag("tumblestone_heat_source")
@JvmField val WALL_HANGING_SIGNS = createTag("wall_hanging_signs")
@@ -64,7 +64,9 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
if (!SwitchInstruction.isVirtual) {
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
}
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
@@ -49,7 +49,9 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
val actionEffect = if (isBoost) BOOST_EFFECT else UNBOOST_EFFECT
val providers = mutableListOf<Any>(battle)
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
if (!SwitchInstruction.isVirtual) {
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
}
val context = ActionEffectContext(
actionEffect = actionEffect,
runtime = runtime,
@@ -53,7 +53,9 @@ class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
val status = Statuses.getStatus(effectID)
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
if (!SwitchInstruction.isVirtual) {
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
}
val context = ActionEffectContext(
actionEffect = actionEffect,
@@ -107,7 +107,9 @@ class DamageInstruction(
}
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
val providers = mutableListOf<Any>(battle)
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
if (!SwitchInstruction.isVirtual) {
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
}
val context = ActionEffectContext(
actionEffect = actionEffect,
@@ -132,7 +134,7 @@ class DamageInstruction(
val pokemonName = battlePokemon.getName()
val pokemonEntity = battlePokemon.entity
//Play recoil animation if the pokemon recoiling isnt dead
if (!causedFaint && pokemonEntity != null) {
if (!causedFaint && pokemonEntity != null && !SwitchInstruction.isVirtual) {
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
pkt.sendToPlayersAround(
x = pokemonEntity.x,
@@ -143,7 +145,7 @@ class DamageInstruction(
)
}
//Play hit particle
if (pokemonEntity != null) {
if (pokemonEntity != null && !SwitchInstruction.isVirtual) {
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
x = pokemonEntity.x,
y = pokemonEntity.y,
@@ -47,7 +47,7 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
setOf(
BattleDispatch {
if (entity != null) {
if (entity != null && !SwitchInstruction.isVirtual) {
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion, imposter)
} else {
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
@@ -38,7 +38,9 @@ class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
battle.minorBattleActions[battlePokemon.uuid] = message
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
if (message.hasOptionalArgument("eat")) {
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
if (!SwitchInstruction.isVirtual) {
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
}
}
}
}
@@ -86,6 +86,7 @@ class MoveInstruction(
battle.majorBattleActions[userPokemon.uuid] = message
val providers = mutableListOf<Any>(battle)
if (SwitchInstruction.isVirtual) return@dispatch GO
userPokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
targetPokemon?.effectedPokemon?.entity?.let { TargetsProvider(it) }?.let(providers::add)
val runtime = MoLangRuntime().also {
@@ -32,8 +32,10 @@ class ReplaceInstruction(val message: BattleMessage): InterpreterInstruction {
val pokemon = message.battlePokemon(0, battle) ?: return
battle.dispatchGo {
val entity = pokemon.entity
entity?.let { it.effects.mockEffect?.end(it) }
if (!SwitchInstruction.isVirtual) {
val entity = pokemon.entity
entity?.let { it.effects.mockEffect?.end(it) }
}
battle.sendSidedUpdate(
source = actor,
@@ -48,7 +48,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
activePokemon.battlePokemon = pokemon
activePokemon.illusion = illusion
val pokemonEntity = pokemon.entity
if (pokemonEntity == null && entity != null) {
if (pokemonEntity == null && entity != null && !isVirtual) {
val targetPos = battleActor.getSide().getOppositeSide().actors.filterIsInstance<EntityBackedBattleActor<*>>().firstOrNull()?.entity?.pos?.let { pos ->
val offset = pos.subtract(entity.pos)
val idealPos = entity.pos.add(offset.multiply(0.33))
@@ -87,7 +87,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
setOf(
BattleDispatch {
if (entity != null) {
if (entity != null && !isVirtual) {
createEntitySwitch(battle, actor, entity, pnx, activePokemon, pokemon, illusion, imposter)
} else {
createNonEntitySwitch(battle, actor, pnx, activePokemon, pokemon, illusion)
@@ -99,6 +99,8 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
}
companion object{
val isVirtual = true
fun createEntitySwitch(
battle: PokemonBattle,
actor: BattleActor,
@@ -40,22 +40,26 @@ class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
battle.dispatch {
if (SwitchInstruction.isVirtual) return@dispatch GO
val entity = pokemon.entity ?: return@dispatch GO
val future = TransformEffect(targetPokemon.effectedPokemon, battle.started).start(entity)
UntilDispatch { future?.isDone != false }
}
battle.dispatchWaiting {
val mock = pokemon.entity?.effects?.mockEffect?.mock
val pokemonName = pokemon.getName()
val targetPokemonName = targetPokemon.getName()
mock?.let {
battle.sendSidedUpdate(
source = actor,
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
)
if (!SwitchInstruction.isVirtual) {
val mock = pokemon.entity?.effects?.mockEffect?.mock
mock?.let {
battle.sendSidedUpdate(
source = actor,
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
)
}
}
val lang = battleLang("transform", pokemonName, targetPokemonName)
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.battles.runner
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.battles.runner.graal.GraalShowdownService
import com.cobblemon.mod.common.battles.runner.socket.SocketShowdownService
import com.google.gson.JsonArray
import java.util.UUID
@@ -36,6 +37,6 @@ interface ShowdownService {
companion object {
val service: ShowdownService by lazy { GraalShowdownService() }
val service: ShowdownService by lazy { SocketShowdownService() }
}
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.battles.runner.socket
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonImplementation
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.battles.BagItems
@@ -16,9 +17,11 @@ import com.cobblemon.mod.common.battles.ShowdownInterpreter
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.server
import com.google.gson.Gson
import com.google.gson.JsonArray
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.InetAddress
@@ -83,7 +86,9 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
private fun readMessage(): String {
val payloadSize = read(reader, 8).toInt()
println("Reading payload of size: $payloadSize")
val payload = read(reader, payloadSize)
println("Response: $payload")
return payload
}
@@ -113,7 +118,18 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
writer.write(">getCobbledMoves\n")
writer.flush()
val response = readMessage()
return gson.fromJson(response, JsonArray::class.java)
try {
return gson.fromJson(response, JsonArray::class.java)
}
catch (e: Exception) {
println("Error, JSON logged to logs/showdown.log")
File("./showdown.log").writer().use {
server()?.getFile("./logs/showdown.log")?.writer().use { writer ->
writer?.write(response)
}
}
}
return JsonArray()
}
override fun getItemIds(): JsonArray {
@@ -166,4 +182,4 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
acknowledge()
}
}
}
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.api.mulch.Mulchable
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import dev.lambdaurora.lambdynlights.util.SodiumDynamicLightHandler.pos
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
@@ -88,31 +87,22 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
init {
defaultState = this.stateManager.defaultState
.with(WAS_GENERATED, false)
.with(MULCH, MulchVariant.NONE)
.with(AGE, 0)
.with(IS_ROOTED, false)
.with(MULCH, MulchVariant.NONE)
}
override fun grow(world: ServerWorld, random: Random, pos: BlockPos, state: BlockState) {
growHelper(world, random, pos, state, true)
}
//grow, but cooler
fun growHelper(world: ServerWorld, random: Random, pos: BlockPos, state: BlockState, boneMealed: Boolean = false) {
val berry = berry() ?: return
if (boneMealed && random.nextFloat() > berry.boneMealChance) return
val curAge = state.get(AGE)
val newAge = curAge + 1
if (newAge > FRUIT_AGE) return
val newState = state.with(AGE, newAge)
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (curAge == MATURE_AGE) {
treeEntity.generateGrowthPoints(world, newState, pos, null)
determineMutation(world, random, pos, newState)
treeEntity.generateGrowthPoints(world, state, pos, null)
determineMutation(world, random, pos, state)
}
world.setBlockState(pos, newState, Block.NOTIFY_LISTENERS)
convertMulchToEntity(world, newState, pos)
treeEntity.goToNextStageTimer(FRUIT_AGE - curAge)
treeEntity.markDirty()
}
@@ -132,7 +122,7 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
CobblemonEvents.BERRY_MUTATION_OFFER.post(BerryMutationOfferEvent(berry, world, state, pos, mutations)) { berryMutationOffer ->
if (berryMutationOffer.mutations.isNotEmpty()) {
var mutateChance = 125
if (getMulch(treeEntity) == MulchVariant.SURPRISE) {
if (getMulch(state) == MulchVariant.SURPRISE) {
mutateChance *= 4
treeEntity.decrementMulchDuration(world, pos, state)
}
@@ -153,10 +143,7 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
state: BlockState,
variant: MulchVariant
): Boolean {
val underBlockState = world.getBlockState(pos.down())
val validSoil = state.get(IS_ROOTED) || underBlockState.isIn(CobblemonBlockTags.BERRY_SOIL)
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return false
return getMulch(treeEntity) == MulchVariant.NONE && state.get(AGE) < FLOWER_AGE && validSoil
return getMulch(state) == MulchVariant.NONE && state.get(AGE) < FLOWER_AGE && world.getBlockState(pos.down()).isOf(Blocks.FARMLAND)
}
override fun applyMulch(
@@ -167,15 +154,18 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
variant: MulchVariant
) {
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
treeEntity.setMulch(variant, world, state, pos)
setMulch(world, pos, state, variant)
treeEntity.mulchDuration = variant.duration
world.playSound(null, pos, CobblemonSounds.MULCH_PLACE, SoundCategory.BLOCKS, 0.6F, 1F)
treeEntity.refreshTimers(pos)
}
@Deprecated("Deprecated in Java")
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
if (player.getStackInHand(hand).item is ShovelItem && getMulch(treeEntity) != MulchVariant.NONE) {
treeEntity.setMulch(MulchVariant.NONE, world, state, pos)
if (player.getStackInHand(hand).item is ShovelItem && getMulch(state) != MulchVariant.NONE) {
setMulch(world, pos, state, MulchVariant.NONE)
treeEntity.markDirty()
world.playSound(null, pos, CobblemonSounds.MULCH_REMOVE, SoundCategory.BLOCKS, 0.6F, 1F)
this.spawnBreakParticles(world, player, pos, state.with(AGE, 0))
return ActionResult.SUCCESS
@@ -199,7 +189,7 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
val below = world.getBlockState(pos.down())
return (state.get(WAS_GENERATED) && below.isIn(CobblemonBlockTags.BERRY_WILD_SOIL))
|| below.isIn(CobblemonBlockTags.BERRY_SOIL)
|| state.get(IS_ROOTED)
|| below.block is FarmlandBlock
}
@Deprecated("Deprecated in Java")
@@ -218,7 +208,6 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
builder.add(AGE)
builder.add(WAS_GENERATED)
builder.add(MULCH)
builder.add(IS_ROOTED)
}
override fun getPickStack(world: BlockView?, pos: BlockPos?, state: BlockState?): ItemStack {
@@ -250,7 +239,6 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
val AGE: IntProperty = IntProperty.of("age", 0, FRUIT_AGE)
val MULCH: EnumProperty<MulchVariant> = EnumProperty.of("mulch", MulchVariant::class.java)
val WAS_GENERATED: BooleanProperty = BooleanProperty.of("generated")
val IS_ROOTED: BooleanProperty = BooleanProperty.of("rooted")
// val PLANTED_SHAPE = VoxelShapes.union(
// VoxelShapes.cuboid(0.3125, -0.0625, 0.3125, 0.6875, 0.0, 0.6875),
// VoxelShapes.cuboid(0.375, 0.0, 0.375, 0.625, 0.0625, 0.625)
@@ -313,14 +301,15 @@ class BerryBlock(private val berryIdentifier: Identifier, settings: Settings) :
val TALL_MATURE = listOf(Box(0.0, -1.0, 0.0, 16.0, 24.0, 16.0))
fun getMulch(entity: BerryBlockEntity) = entity.mulchVariant
fun convertMulchToEntity(world: ServerWorld, state: BlockState, pos: BlockPos) {
val entity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
if (state.get(MULCH) != MulchVariant.NONE && state.get(MULCH) != entity.mulchVariant) {
entity.mulchVariant = state.get(MULCH)
world.setBlockState(pos, state.with(MULCH, MulchVariant.NONE))
fun getMulch(state: BlockState): MulchVariant {
if (!state.contains(MULCH)) {
return MulchVariant.NONE
}
return state.get(MULCH)
}
fun setMulch(world: World, pos: BlockPos, state: BlockState, mulch: MulchVariant) {
world.setBlockState(pos, state.with(MULCH, mulch))
}
}
}
@@ -1,49 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.item.berry.BerryItem
import net.minecraft.block.AbstractBlock
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
/**
* @author Apion
* @since February 27, 2024
*/
class BindingSoilBlock(settings: Settings) : Block(settings) {
@Deprecated("Deprecated in Java")
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
if (!world.isClient) {
val itemStack = player.getStackInHand(hand)
val item = itemStack.item
if (item is BerryItem) {
world.setBlockState(pos, item.block.defaultState.with(BerryBlock.IS_ROOTED, true))
if (!player.isCreative) {
itemStack.decrement(1)
}
}
}
return ActionResult.SUCCESS
}
}
@@ -1,107 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.CobblemonItems
import net.minecraft.block.*
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemConvertible
import net.minecraft.item.ItemStack
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.IntProperty
import net.minecraft.state.property.Properties
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.ItemScatterer
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.random.Random
import net.minecraft.util.shape.VoxelShape
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldView
@Suppress("OVERRIDE_DEPRECATION")
class BugwortBlock(settings: Settings) : CropBlock(settings), Fertilizable {
override fun getAgeProperty(): IntProperty = AGE
override fun getMaxAge(): Int = MATURE_AGE
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(this.ageProperty)
}
override fun getSeedsItem(): ItemConvertible = CobblemonItems.BUGWORT
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape = AGE_TO_SHAPE[this.getAge(state)]
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, random: Random) {
// This is specified as growing fast like sugar cane
// They have 15 age stages until they grow upwards, this is an attempt at a chance based but likely event
if (this.isMature(state) || random.nextInt(4) != 0) {
return
}
this.applyGrowth(world, pos, state)
}
// These 3 are still around for the sake of compatibility, vanilla won't trigger it but some mods might
// We implement applyGrowth & getGrowthAmount for them
override fun isFertilizable(world: WorldView?, pos: BlockPos?, state: BlockState?, isClient: Boolean): Boolean = !this.isMature(state)
override fun applyGrowth(world: World, pos: BlockPos, state: BlockState) {
world.setBlockState(pos, state.with(this.ageProperty, (this.getAge(state) + 1).coerceAtMost(this.maxAge)), NOTIFY_LISTENERS)
}
override fun canPlantOnTop(floor: BlockState, world: BlockView?, pos: BlockPos?): Boolean {
return floor.isOf(Blocks.GRASS_BLOCK) || floor.isOf(Blocks.DIRT) || floor.isOf(Blocks.FARMLAND)
}
override fun canPlaceAt(state: BlockState?, world: WorldView?, pos: BlockPos?): Boolean {
val blockPos = pos!!.down()
return canPlantOnTop(world!!.getBlockState(blockPos), world, blockPos)
}
override fun onUse(
state: BlockState?,
world: World?,
pos: BlockPos?,
player: PlayerEntity?,
hand: Hand?,
hit: BlockHitResult?
): ActionResult {
if (state != null && world != null && pos != null) {
// if bugwort is at max age then revert age to 0 and drop items
if (state.get(AGE) == 3) {
world.setBlockState(pos, state.with(this.ageProperty, (0).coerceAtMost(this.maxAge)), NOTIFY_LISTENERS)
Block.dropStack(world, pos, ItemStack(CobblemonItems.BUGWORT, kotlin.random.Random.nextInt(2, 4)))
return ActionResult.SUCCESS
}
}
return super.onUse(state, world, pos, player, hand, hit)
}
override fun getGrowthAmount(world: World): Int = 1
companion object {
const val MATURE_AGE = 3
val AGE: IntProperty = Properties.AGE_3
val AGE_TO_SHAPE = arrayOf(
createCuboidShape(0.0, 0.0, 0.0, 16.0, 2.0, 16.0),
createCuboidShape(0.0, 0.0, 0.0, 16.0, 5.0, 16.0),
createCuboidShape(0.0, 0.0, 0.0, 16.0, 8.0, 16.0),
createCuboidShape(0.0, 0.0, 0.0, 16.0, 11.0, 16.0)
)
}
}
@@ -1,314 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.block.entity.CookingPotBlockEntity
import com.cobblemon.mod.common.gui.CookingPotScreenHandler
import net.minecraft.block.*
import net.minecraft.block.entity.BlockEntity
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.fluid.FluidState
import net.minecraft.fluid.Fluids
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.screen.NamedScreenHandlerFactory
import net.minecraft.screen.ScreenHandlerContext
import net.minecraft.screen.SimpleNamedScreenHandlerFactory
import net.minecraft.server.world.ServerWorld
import net.minecraft.stat.Stats
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.ActionResult
import net.minecraft.util.BlockMirror
import net.minecraft.util.BlockRotation
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
class CookingPotBlock(settings: Settings?) : BlockWithEntity(settings), Waterloggable, InventoryProvider {
companion object {
val COOKING: BooleanProperty = BooleanProperty.of("cooking")
val FACING = Properties.FACING
val TRIGGERED = Properties.TRIGGERED
val WATERLOGGED = Properties.WATERLOGGED
private val NORTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0, 1.0, 0.3125, 0.9375),
VoxelShapes.cuboid(0.0, 0.3125, 0.75, 1.0, 0.9375, 0.9375),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private val SOUTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0625, 1.0, 0.3125, 1.0),
VoxelShapes.cuboid(0.0, 0.3125, 0.0625, 1.0, 0.9375, 0.25),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private val WEST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.0, 0.9375, 0.3125, 1.0),
VoxelShapes.cuboid(0.75, 0.3125, 0.0, 0.9375, 0.9375, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private val EAST_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0625, 0.0, 0.0, 1.0, 0.3125, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0, 0.25, 0.9375, 1.0),
VoxelShapes.cuboid(0.0625, 0.3125, 0.0625, 0.9375, 0.875, 0.9375)
)
private val EMPTY_INVENTORY = object : SidedInventory {
override fun clear() {}
override fun size(): Int = 0
override fun isEmpty(): Boolean = true
override fun getStack(slot: Int) = ItemStack.EMPTY
override fun removeStack(slot: Int, amount: Int) = ItemStack.EMPTY
override fun removeStack(slot: Int) = ItemStack.EMPTY
override fun setStack(slot: Int, stack: ItemStack?) {}
override fun canPlayerUse(player: PlayerEntity?) = false
override fun getAvailableSlots(side: Direction?) = IntArray(0)
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?) = false
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?) = false
override fun markDirty() {}
}
}
private val TITLE: Text = Text.of("Campfire Pot")
init {
defaultState = this.stateManager.defaultState.with(FACING, Direction.NORTH)
.with(WATERLOGGED, false)
.with(COOKING, false)
.with(TRIGGERED, false)
}
@Deprecated("Deprecated in Java")
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
if (world.isClient) {
return ActionResult.SUCCESS
}
player.openHandledScreen(state.createScreenHandlerFactory(world, pos))
player.incrementStat(Stats.INTERACT_WITH_CRAFTING_TABLE)
return ActionResult.CONSUME
}
@Deprecated("Deprecated in Java")
override fun createScreenHandlerFactory(
state: BlockState,
world: World,
pos: BlockPos
): NamedScreenHandlerFactory {
return SimpleNamedScreenHandlerFactory({ syncId: Int, inventory: PlayerInventory, player: PlayerEntity ->
CookingPotScreenHandler(syncId, inventory, ScreenHandlerContext.create(world, pos))
}, TITLE)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
return CookingPotBlockEntity(pos, state)
}
override fun getInventory(state: BlockState, world: WorldAccess, pos: BlockPos): SidedInventory {
val cookingPotBlockEntity = world.getBlockEntity(pos) as? CookingPotBlockEntity
?: return EMPTY_INVENTORY
return cookingPotBlockEntity.cookingPotInventory
}
@Deprecated("Deprecated in Java")
override fun canPathfindThrough(
blockState: BlockState,
blockGetter: BlockView,
blockPos: BlockPos,
pathComputationType: NavigationType
) = false
@Deprecated("Deprecated in Java")
override fun hasComparatorOutput(state: BlockState): Boolean {
return true
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING, WATERLOGGED, COOKING, TRIGGERED)
}
@Deprecated("Deprecated in Java")
override fun rotate(blockState: BlockState, rotation: BlockRotation): BlockState {
return blockState.with(FACING, rotation.rotate(blockState[FACING]))
}
@Deprecated("Deprecated in Java")
override fun mirror(blockState: BlockState, mirror: BlockMirror): BlockState {
return blockState.rotate(mirror.getRotation(blockState[FACING]))
}
@Deprecated("Deprecated in Java")
override fun onStateReplaced(
state: BlockState,
world: World,
pos: BlockPos,
newState: BlockState,
moved: Boolean
) {
if (!state.isOf(newState.block)) {
super.onStateReplaced(state, world, pos, newState, moved)
}
}
@Deprecated("Deprecated in Java")
override fun scheduledTick(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: net.minecraft.util.math.random.Random?) {
val inventory = (world!!.getBlockEntity(pos) as CookingPotBlockEntity).cookingPotInventory
val cookingPotEntity = (world.getBlockEntity(pos) as CookingPotBlockEntity)
if(world == null || pos == null) {
return
}
//val tankEntity = world.getBlockEntity(pos) as MultiblockEntity
if (cookingPotEntity.blockState.get(COOKING)) {
//print("TMM is in use so scheduled Tick is disabled")
return
}
/*//this.onTriggerEvent(state, world, pos, random)
// todo if the output slot is empty then try to craft a TM to that slot
if (ItemStack.areItemsEqual(inventory.items!!.get(3), ItemStack.EMPTY)) {
if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack: ItemStack
itemStack = if (inventory.filterTM != null)
inventory.filterTM!!.copy()
else
ItemStack(CobblemonItems.BLANK_TM, 1)
val tm = TechnicalMachines.getTechnicalMachineFromStack(itemStack)
// todo use isReadyToCraftTM to finalize the creation
if (((inventory.filterTM != null && tm != null) && isReadyToCraftTM(state, world, pos, tm)) || isReadyToCraftBlankTM(state, world, pos)) {
// create TM item to the output slot
inventory.items!!.set(3, itemStack)
cookingPotEntity.markDirty()
// Play sound for TM creation
world.playSoundServer(cookingPotEntity.blockPos.toVec3d(), CobblemonSounds.TMM_CRAFT, SoundCategory.BLOCKS)
}
}
}*/
// todo if there is an item in the output slot then spit it out
else {
if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack = inventory.items!!.get(3)
// Get the direction the block is facing
val facingDirection = state.get(Properties.FACING)?.opposite ?: return
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, itemStack).copy()
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
world.spawnEntity(itemEntity)
//clear inventory of SidedInventory
inventory.items?.clear()
cookingPotEntity.markDirty()
//getInventory(state, world, pos).clear()
}
}
/*if (state?.let { getInventory(it, world, pos) } != null) {
val itemStack: ItemStack
itemStack = if (inventory.filterTM != null)
inventory.filterTM!!
else
ItemStack(CobblemonItems.BLANK_TM, 1)
val tm = TechnicalMachines.getTechnicalMachineFromStack(itemStack)
// todo use isReadyToCraftTM to finalize the creation
if ((inventory.filterTM != null && isReadyToCraftTM(state, world, pos, tm!!)) || isReadyToCraftBlankTM(state, world, pos)) {
// Get the direction the block is facing
val facingDirection = state.get(Properties.FACING)?.opposite ?: return
// Calculate the center position of the block
val frontOffset = 0.5 // Half block offset to the front
val spawnX = pos.x + 0.5 + facingDirection.offsetX * frontOffset
val spawnY = pos.y + 0.3 + facingDirection.offsetY * frontOffset
val spawnZ = pos.z + 0.5 + facingDirection.offsetZ * frontOffset
// Create the ItemEntity at the center of the block
val itemEntity = ItemEntity(world, spawnX, spawnY, spawnZ, itemStack).copy()
// Create the ItemEntity
itemEntity.setVelocity(0.0, 0.0, 0.0)
// Add the ItemEntity to the world
world.spawnEntity(itemEntity)
//clear inventory of SidedInventory
inventory.items?.clear()
//getInventory(state, world, pos).clear()
}
}*/
}override fun getRenderType(blockState: BlockState): BlockRenderType {
return BlockRenderType.MODEL
}
override fun getFluidState(state: BlockState): FluidState {
return if (state[WATERLOGGED]) {
Fluids.WATER.getStill(false)
} else super.getFluidState(state)
}
override fun getOutlineShape(
state: BlockState,
world: BlockView,
pos: BlockPos,
context: ShapeContext
): VoxelShape {
return when (state[FACING]) {
Direction.NORTH -> NORTH_OUTLINE
Direction.SOUTH -> SOUTH_OUTLINE
Direction.WEST -> WEST_OUTLINE
else -> EAST_OUTLINE
}
}
}
@@ -1,256 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.block.SaccharineStrippedLogBlock.Companion
import net.minecraft.block.*
import net.minecraft.block.BeehiveBlock.HONEY_LEVEL
import net.minecraft.entity.*
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.attribute.DefaultAttributeContainer
import net.minecraft.entity.attribute.EntityAttributes
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.Fluids
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.particle.ParticleTypes
import net.minecraft.registry.tag.BlockTags
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.IntProperty
import net.minecraft.state.property.Properties
import net.minecraft.util.ActionResult
import net.minecraft.util.Arm
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.hit.HitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.MathHelper
import net.minecraft.util.math.Vec3d
import net.minecraft.util.math.random.Random
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.*
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
class SaccharineLeafBlock(settings: Settings) : LeavesBlock(settings), Fertilizable {
init {
this.defaultState = this.stateManager.defaultState
.with(AGE, MIN_AGE)
.with(DISTANCE, DISTANCE_MAX)
.with(PERSISTENT, false)
.with(Properties.WATERLOGGED, false)
}
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
val blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
return if (blockState.canPlaceAt(worldView, blockPos)) {
blockState.with(PERSISTENT, true).with(Properties.WATERLOGGED, worldView.getFluidState(blockPos).isOf(Fluids.WATER))
} else null
}
override fun getStateForNeighborUpdate(state: BlockState, direction: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState? {
return if (!state.canPlaceAt(world, pos)) {
Blocks.AIR.defaultState
} else {
super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
}
override fun hasRandomTicks(state: BlockState) = state.get(AGE) != 2
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, random: Random) {
// todo if a honey soaked leaf block is the first block below this block then over time age that leaf block
if (random.nextInt(180) == 0) {
// todo if leaf block is within 10 blocks of a lead soaked block then age it
for (i in 1..10) {
val abovePos = pos.up(i)
val aboveState = world.getBlockState(abovePos)
val currentAge = state.get(AGE)
if (!aboveState.isAir) {
if ((aboveState.block is SaccharineLeafBlock && aboveState.get(AGE) > 0)/* ||
(aboveState.block is BeehiveBlock && aboveState.get(HONEY_LEVEL) == 5)*/) {
// todo -1 age from top block
world.setBlockState(abovePos, aboveState.with(AGE, aboveState.get(AGE) - 1), 2)
// todo +1 age the leaf bottom block
world.setBlockState(pos, state.with(AGE, currentAge + 1), 2)
}
break
}
}
}
super.randomTick(state, world, pos, random)
}
@Deprecated("Deprecated in Java")
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return SHAPE
}
// todo make block
@Deprecated("Deprecated in Java")
override fun getCollisionShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
if (context is EntityShapeContext && (context.entity as? ItemEntity)?.stack?.isIn(CobblemonItemTags.APRICORNS) == true) {
return VoxelShapes.empty()
}
return super.getCollisionShape(state, world, pos, context)
}
override fun isFertilizable(world: WorldView, pos: BlockPos, state: BlockState, isClient: Boolean) = false /*state.get(AGE) < MAX_AGE*/
override fun canGrow(world: World, random: Random, pos: BlockPos, state: BlockState) = true
override fun grow(world: ServerWorld, random: Random, pos: BlockPos, state: BlockState) {
world.setBlockState(pos, state.with(AGE, state.get(AGE) + 1), 2)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(AGE, DISTANCE, PERSISTENT, Properties.WATERLOGGED)
}
@Deprecated("Deprecated in Java")
override fun randomDisplayTick(state: BlockState, world: World, pos: BlockPos, random: Random) {
if (state.get(AGE) == 2) {
for (i in 0 until random.nextInt(1) + 1) {
this.spawnHoneyParticles(world, pos, state, .75f)
}
} else if (state.get(AGE) == 1) {
for (i in 0 until random.nextInt(1) + 1) {
this.spawnHoneyParticles(world, pos, state, .9f)
}
}
// this code was for them aging as time goes on
/* if (world.random.nextInt(5) == 0) {
val currentAge = state.get(AGE)
if (currentAge < MAX_AGE) {
world.setBlockState(pos, state.with(AGE, currentAge + 1), 2)
}
}*/
}
/*@Deprecated("Deprecated in Java")
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
val blockState = world.getBlockState(pos.down())
return blockState.isIn(CobblemonBlockTags.SACCHARINE_LEAVES)
}*/
private fun spawnHoneyParticles(world: World, pos: BlockPos, state: BlockState, rate: Float) {
if (state.fluidState.isEmpty && !(world.random.nextFloat() < rate)) {
val voxelShape = state.getCollisionShape(world, pos)
val d = voxelShape.getMax(Direction.Axis.Y)
if (d >= 1.0 && !state.isIn(BlockTags.IMPERMEABLE)) {
val e = voxelShape.getMin(Direction.Axis.Y)
if (e > 0.0) {
this.addHoneyParticle(world, pos, voxelShape, pos.y.toDouble() + e - 0.05)
} else {
val blockPos = pos.down()
val blockState = world.getBlockState(blockPos)
val voxelShape2 = blockState.getCollisionShape(world, blockPos)
val f = voxelShape2.getMax(Direction.Axis.Y)
if ((f < 1.0 || !blockState.isFullCube(world, blockPos)) && blockState.fluidState.isEmpty) {
this.addHoneyParticle(world, pos, voxelShape, pos.y.toDouble() - 0.05)
}
}
}
}
}
private fun addHoneyParticle(world: World, pos: BlockPos, shape: VoxelShape, height: Double) {
this.addHoneyParticle(
world, pos.x.toDouble() + shape.getMin(Direction.Axis.X), pos.x.toDouble() + shape.getMax(
Direction.Axis.X
), pos.z.toDouble() + shape.getMin(Direction.Axis.Z), pos.z.toDouble() + shape.getMax(
Direction.Axis.Z
), height
)
}
private fun addHoneyParticle(world: World, minX: Double, maxX: Double, minZ: Double, maxZ: Double, height: Double) {
world.addParticle(
ParticleTypes.DRIPPING_HONEY,
MathHelper.lerp(world.random.nextDouble(), minX, maxX),
height,
MathHelper.lerp(world.random.nextDouble(), minZ, maxZ),
0.0,
0.0,
0.0
)
}
override fun canPathfindThrough(state: BlockState, world: BlockView, pos: BlockPos, type: NavigationType) = false
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
// todo if item in players hand is glass bottle and AGE is more than 0
if (player.getStackInHand(hand).isOf(Items.GLASS_BOTTLE) && state.get(AGE) > 0)
{
// decrement stack if not in creative mode
if (!player.isCreative)
player.getStackInHand(hand).decrement(1)
// give player honey bottle for now
player.giveItemStack(Items.HONEY_BOTTLE.defaultStack)
// todo reset AGE
world.setBlockState(pos, state.with(AGE, 0), 2)
val currentAge = state.get(AGE)
} else if (player.getStackInHand(hand).isOf(Items.HONEY_BOTTLE) && state.get(AGE) != 2) {
// decrement stack if not in creative mode
if (!player.isCreative)
player.getStackInHand(hand).decrement(1)
// todo set age to 2
world.setBlockState(pos, state.with(AGE, 2), 2)
}
if (state.get(AGE) != MAX_AGE) {
return super.onUse(state, world, pos, player, hand, hit)
}
//doHarvest(world, state, pos, player)
return ActionResult.SUCCESS
}
/*override fun onBlockBreakStart(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity) {
if (state.get(AGE) != MAX_AGE) {
return super.onBlockBreakStart(state, world, pos, player)
}
//doHarvest(world, state, pos, player)
}*/
companion object {
val AGE: IntProperty = Properties.AGE_2
val DISTANCE: IntProperty = Properties.DISTANCE_1_7
val PERSISTENT: BooleanProperty = Properties.PERSISTENT
const val MAX_AGE = Properties.AGE_2_MAX
const val MIN_AGE = 0
const val DISTANCE_MAX = 7
private val SHAPE: VoxelShape = Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 16.0)
}
}
@@ -1,15 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.grower.ApricornTreeGrower
import com.cobblemon.mod.common.block.grower.SaccharineTreeGrower
import net.minecraft.block.SaplingBlock
class SaccharineSaplingBlock(properties : Settings) : SaplingBlock(SaccharineTreeGrower(), properties)
@@ -1,153 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import net.minecraft.block.*
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.EnumProperty
import net.minecraft.state.property.IntProperty
import net.minecraft.state.property.Properties
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.Direction.Axis
import net.minecraft.util.math.random.Random
import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
class SaccharineStrippedLogBlock(settings: Settings) : PillarBlock(settings) {
init {
this.defaultState = this.stateManager.defaultState
.with(AGE, MIN_AGE)
.with(AXIS, Axis.Y)
}
override fun onPlaced(world: World?, pos: BlockPos?, state: BlockState?, placer: LivingEntity?, itemStack: ItemStack?) {
owner = placer
super.onPlaced(world, pos, state, placer, itemStack)
}
override fun hasRandomTicks(state: BlockState) = state.get(AGE) < MAX_AGE
@Deprecated("Deprecated in Java")
override fun randomTick(state: BlockState, world: ServerWorld, pos: BlockPos, random: Random) {
// todo make it so that it only ages when connected to enough natural-tagged Saccharine Leaves (so, generated or grown, not player placed)
// this code was for them aging as time goes on
if (world.random.nextInt(5) == 0 && owner == null) {
val currentAge = state.get(AGE)
if (currentAge < MAX_AGE) {
world.setBlockState(pos, state.with(AGE, currentAge + 1), 2)
}
}
}
/*@Deprecated("Deprecated in Java")
override fun canPlaceAt(state: BlockState, world: WorldView, pos: BlockPos): Boolean {
val blockState = world.getBlockState(pos.down())
return blockState.isIn(CobblemonBlockTags.SACCHARINE_LEAVES)
}*/
@Deprecated("Deprecated in Java")
override fun getOutlineShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
return SHAPE
}
// todo make block
@Deprecated("Deprecated in Java")
override fun getCollisionShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape {
if (context is EntityShapeContext && (context.entity as? ItemEntity)?.stack?.isIn(CobblemonItemTags.APRICORNS) == true) {
return VoxelShapes.empty()
}
return super.getCollisionShape(state, world, pos, context)
}
/*override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
val blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
return defaultState.with(PillarBlock.AXIS, ctx.side.axis) as BlockState
return if (blockState.canPlaceAt(worldView, blockPos)) blockState else null
}*/
override fun getStateForNeighborUpdate(state: BlockState, direction: Direction, neighborState: BlockState, world: WorldAccess, pos: BlockPos, neighborPos: BlockPos): BlockState? {
return if (!state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(AGE, AXIS)
}
override fun canPathfindThrough(state: BlockState, world: BlockView, pos: BlockPos, type: NavigationType) = false
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
// todo if item in players hand is glass bottle and AGE is 1
if (player.getStackInHand(hand).isOf(Items.GLASS_BOTTLE) && state.get(AGE) == 1)
{
// decrement stack if not in creative mode
if (!player.isCreative)
player.getStackInHand(hand).decrement(1)
// todo give player Sweet Sap item
player.giveItemStack(CobblemonItems.SWEET_SAP.defaultStack)
// todo reset AGE
world.setBlockState(pos, state.with(AGE, 0), 2)
val currentAge = state.get(AGE)
}
if (state.get(AGE) != MAX_AGE) {
return super.onUse(state, world, pos, player, hand, hit)
}
//doHarvest(world, state, pos, player)
return ActionResult.SUCCESS
}
/*override fun onBlockBreakStart(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity) {
if (state.get(AGE) != MAX_AGE) {
return super.onBlockBreakStart(state, world, pos, player)
}
//doHarvest(world, state, pos, player)
}*/
companion object {
val AGE: IntProperty = Properties.AGE_1
val AXIS: EnumProperty<Axis> = Properties.AXIS
const val MAX_AGE = Properties.AGE_1_MAX
const val MIN_AGE = 0
var owner: LivingEntity? = null
private val SHAPE: VoxelShape = Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 16.0)
}
}
@@ -1,194 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import net.minecraft.block.*
import net.minecraft.block.HorizontalFacingBlock.*
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.Items
import net.minecraft.particle.ParticleTypes
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.DirectionProperty
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.random.Random
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
@Suppress("OVERRIDE_DEPRECATION")
class SweetIncenseBlock(settings: Settings) : BlockWithEntity(settings), Waterloggable {
/*
This item, when placed, acts like a candle. It must be lit with a Flint n Steel or Fire Charge, and it can be “put out” by right-clicking on it. Small blue smoke particles will rise from the nub on the top of the block when lit.
This incense block has special effects on Pokémon spawns, but only when lit. When lit, Sweet Incense increases Pokémon spawn & despawn rates by 1.5x and raises spawn density by 25% in a 16 block radius (32 block diameter) (this number will need to be playtested).
This essentially means that the player will see a larger number of Pokémon at once, and a higher variety of Pokémon in a given span of time.
*/
init {
this.defaultState = this.stateManager.defaultState
.with(FACING, Direction.NORTH)
.with(ITEM_DIRECTION, Direction.NORTH)
.with(LIT,false)
}
companion object {
val ITEM_DIRECTION = DirectionProperty.of("item_facing")
val LIT = BooleanProperty.of("false")
}
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
var blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
ctx.placementDirections.forEach { direction ->
if (direction.axis.isHorizontal) {
blockState = blockState
.with(FACING, direction)
.with(LIT, false)
.with(ITEM_DIRECTION, direction)
as BlockState
if (blockState.canPlaceAt(worldView, blockPos)) {
return blockState
}
}
}
return null
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING)
builder.add(ITEM_DIRECTION)
builder.add(LIT)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState): DisplayCaseBlockEntity {
return DisplayCaseBlockEntity(pos, state)
}
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
return if (direction == state.get(FACING) && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
// light the incense when flint and steel or fire charge is held
if (state.get(LIT) == false && (player.getStackInHand(hand).isOf(Items.FLINT_AND_STEEL.asItem()) ||
player.getStackInHand(hand).isOf(Items.FIRE_CHARGE.asItem()))) {
world.setBlockState(pos, state.with(LIT, true), 2)
return ActionResult.SUCCESS
}
// unlight the incense when used if it is on
if (state.get(LIT) == true && (player.getStackInHand(hand).isOf(Items.FLINT_AND_STEEL.asItem()) == false ||
player.getStackInHand(hand).isOf(Items.FIRE_CHARGE.asItem()) == false)) {
world.setBlockState(pos, state.with(LIT, false), 2)
return ActionResult.SUCCESS
}
return ActionResult.FAIL
}
override fun randomDisplayTick(state: BlockState, world: World, pos: BlockPos, random: Random) {
if (state.get(LIT)) {
spawnSmokeParticle(world, pos, true, false)
if (random.nextInt(10) == 0) {
world.playSound(
pos.x.toDouble() + 0.5,
pos.y.toDouble() + 0.5,
pos.z.toDouble() + 0.5,
SoundEvents.BLOCK_CAMPFIRE_CRACKLE,
SoundCategory.BLOCKS,
0.2f + random.nextFloat(),
random.nextFloat() * 0.7f + 0.6f,
false
)
}
/*if (random.nextInt(5) == 0) {
for (i in 0 until random.nextInt(1) + 1) {
world.addParticle(
ParticleTypes.LAVA, pos.x.toDouble() + 0.5, pos.y.toDouble() + 0.5, pos.z.toDouble() + 0.5,
(random.nextFloat() / 2.0f).toDouble(), 5.0E-5,
(random.nextFloat() / 2.0f).toDouble()
)
}
}*/
}
}
fun spawnSmokeParticle(world: World, pos: BlockPos, isSignal: Boolean, lotsOfSmoke: Boolean) {
val random = world.getRandom()
val defaultParticleType =
if (isSignal) ParticleTypes.CAMPFIRE_SIGNAL_SMOKE else ParticleTypes.CAMPFIRE_COSY_SMOKE
world.addImportantParticle(
defaultParticleType,
true,
pos.x.toDouble() + 0.5 + random.nextDouble() / 3.0 * (if (random.nextBoolean()) 1 else -1).toDouble(),
pos.y.toDouble() + random.nextDouble() + random.nextDouble(),
pos.z.toDouble() + 0.5 + random.nextDouble() / 3.0 * (if (random.nextBoolean()) 1 else -1).toDouble(),
0.0,
0.07,
0.0
)
if (lotsOfSmoke) {
world.addParticle(
ParticleTypes.SMOKE,
pos.x.toDouble() + 0.5 + random.nextDouble() / 4.0 * (if (random.nextBoolean()) 1 else -1).toDouble(),
pos.y.toDouble() + 0.4,
pos.z.toDouble() + 0.5 + random.nextDouble() / 4.0 * (if (random.nextBoolean()) 1 else -1).toDouble(),
0.0,
0.005,
0.0
)
}
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
/*val entity = world.getBlockEntity(pos) as DisplayCaseBlockEntity
if (!entity.getStack().isEmpty && !player.isCreative) {
ItemScatterer.spawn(world, pos, entity.inv)
}
super.onBreak(world, pos, state, player)*/
}
override fun getRenderType(state: BlockState?) = BlockRenderType.MODEL
override fun hasComparatorOutput(state: BlockState?) = true
override fun canPathfindThrough(state: BlockState, world: BlockView, pos: BlockPos, type: NavigationType) = false
}
@@ -131,6 +131,7 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
if (isFake() && (player is ServerPlayerEntity)) {
spawnPokemon(world, pos, state, player)
}
world.setBlockState(pos, if (state.fluidState.isOf(Fluids.WATER)) Blocks.WATER.defaultState else Blocks.AIR.defaultState)
val bEntity = world.getBlockEntity(pos) as? GildedChestBlockEntity
bEntity?.markRemoved()
} else super.onBreak(world, pos, state, player)
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.BerryBlock.Companion.getMulch
import com.cobblemon.mod.common.block.BerryBlock.Companion.setMulch
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
@@ -42,8 +43,8 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
lateinit var berryIdentifier: Identifier
private val ticksPerMinute = 1200
var renderState: RenderState? = null
//The time left for the tree until its either age 3 or age 5 (check block state, if we are at age 0<x<3 unti 3 otherwise until 5)
var growthTimer: Int = 0
//The time left for the tree to grow to stage 5
var growthTimer: Int = 72000
set(value) {
if (value < 0) {
throw IllegalArgumentException("You cannot set the growth time to less than zero")
@@ -54,7 +55,7 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
field = value
}
//The time left for the tree to grow to the next stage
var stageTimer: Int = 0
var stageTimer: Int = growthTimer / BerryBlock.MATURE_AGE
set(value) {
if (field != value) {
this.markDirty()
@@ -62,7 +63,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
field = value
}
private val growthPoints = arrayListOf<Identifier>()
var mulchVariant = MulchVariant.NONE
/**
* The idea behind the growth point sequence is it's a 16-long string of
@@ -85,6 +85,20 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
markDirty()
}
fun decrementMulchDuration(world: World, pos: BlockPos, state: BlockState) {
val currentMulch = getMulch(state)
if (currentMulch == MulchVariant.NONE || currentMulch.duration == -1) {
return
}
val newDuration = mulchDuration - 1
mulchDuration = if (newDuration <= 0) {
setMulch(world, pos, state, MulchVariant.NONE)
0
} else {
newDuration
}
}
constructor(pos: BlockPos, state: BlockState, berryIdentifier: Identifier): this(pos, state) {
this.berryIdentifier = berryIdentifier
resetGrowTimers(pos, state)
@@ -93,31 +107,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
}
}
fun decrementMulchDuration(world: World, pos: BlockPos, state: BlockState) {
if (mulchVariant == MulchVariant.NONE || mulchVariant.duration == -1) {
return
}
val newDuration = mulchDuration - 1
mulchDuration = if (newDuration <= 0) {
mulchVariant = MulchVariant.NONE
this.markDirty()
world.updateListeners(pos, state, state, Block.NOTIFY_LISTENERS)
0
} else {
newDuration
}
}
fun setMulch(mulch: MulchVariant, world: World, state: BlockState, pos: BlockPos) {
this.mulchVariant = mulch
this.mulchDuration = mulch.duration
refreshTimers(pos)
world.updateListeners(pos, state, state, Block.NOTIFY_LISTENERS)
this.markDirty()
}
//This function basically runs twice when the berry tree is growing, once when it starts, once when it hits age 3
//Why dont we just go 0-5? Design thinks its annoying to balance the numbers using 0-5 and 3-5
fun resetGrowTimers(pos: BlockPos, state: BlockState) {
val curAge = state.get(BerryBlock.AGE)
if (curAge == 5) {
@@ -130,15 +119,12 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
val upperGrowthLimit = (if (curAge == 0) berry.growthTime.last else berry.refreshRate.last) * multiplier / 10
val growthRange = lowerGrowthLimit..upperGrowthLimit
this.growthTimer = this.applyMulchModifier(pos, growthRange.random() * ticksPerMinute, true)
val stagesLeft = if (curAge < 3) BerryBlock.MATURE_AGE - curAge else BerryBlock.FRUIT_AGE - curAge
this.goToNextStageTimer(stagesLeft)
this.growthTimer = this.applyMulchModifier(pos, growthRange.random() * ticksPerMinute)
this.goToNextStageTimer(BerryBlock.FRUIT_AGE - curAge)
}
fun goToNextStageTimer(stagesLeft: Int) {
val avgStageTime = growthTimer / stagesLeft
//A number between 80% and 100% the average stage time
//So stages have some variance
stageTimer = this.world?.random?.nextBetween((avgStageTime * 8) / 10, avgStageTime) ?:
(((Math.random() * 0.2) + 0.8) * avgStageTime).toInt()
growthTimer -= stageTimer
@@ -151,7 +137,7 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
* @param timer Timer to be modified
* @return The modified timer
*/
private fun applyMulchModifier(pos: BlockPos, timer: Int, decrementMulch: Boolean = false): Int {
private fun applyMulchModifier(pos: BlockPos, timer: Int): Int {
val state = world?.getBlockState(pos) ?: return timer
val curAge = state.get(BerryBlock.AGE)
@@ -159,15 +145,11 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
return timer
}
if (mulchVariant != MulchVariant.GROWTH) {
if (getMulch(state) != MulchVariant.GROWTH) {
return timer
}
if (decrementMulch) {
world?.let {
decrementMulchDuration(it, pos, state)
}
}
return (timer * MulchVariant.GROWTH_TIME_MULTIPLIER).toInt()
return (timer * 0.66).toInt()
}
/**
@@ -175,8 +157,8 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
* @param pos The position of the block
*/
fun refreshTimers(pos: BlockPos) {
this.growthTimer = this.applyMulchModifier(pos, growthTimer, false)
this.stageTimer = this.applyMulchModifier(pos, stageTimer, false)
this.growthTimer = this.applyMulchModifier(pos, growthTimer)
this.stageTimer = this.applyMulchModifier(pos, stageTimer)
}
/**
@@ -266,9 +248,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
if (nbt.contains(GROWTH_POINTS_SEQUENCE)) {
growthPointSequence = nbt.getString(GROWTH_POINTS_SEQUENCE)
}
if (nbt.contains(MULCH_VARIANT)) {
mulchVariant = MulchVariant.valueOf(nbt.getString(MULCH_VARIANT))
}
this.renderState?.needsRebuild = true
}
@@ -281,7 +260,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
nbt.putString(BERRY, berryIdentifier.toString())
nbt.putInt(MULCH_DURATION, mulchDuration)
nbt.putString(GROWTH_POINTS_SEQUENCE, growthPointSequence)
nbt.putString(MULCH_VARIANT, mulchVariant.toString())
}
override fun markDirty() {
@@ -345,12 +323,11 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
companion object {
internal val TICKER = BlockEntityTicker<BerryBlockEntity> { world, pos, state, blockEntity ->
if (world.isClient) return@BlockEntityTicker
if (state.get(BerryBlock.IS_ROOTED)) return@BlockEntityTicker
if (blockEntity.stageTimer >= 0) {
blockEntity.stageTimer--
}
if (blockEntity.stageTimer == 0) {
(state.block as BerryBlock).growHelper(world as ServerWorld, world.random, pos, state)
(state.block as BerryBlock).grow(world as ServerWorld, world.random, pos, state)
}
}
//private const val LIFE_CYCLES = "life_cycles"
@@ -360,7 +337,6 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
private const val STAGE_TIMER = "StageTimer"
private const val BERRY = "Berry"
private const val MULCH_DURATION = "MulchDuration"
private const val MULCH_VARIANT = "MulchVariant"
}
}
@@ -1,214 +0,0 @@
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.block.CookingPotBlock
import com.cobblemon.mod.common.gui.CookingPotScreenHandler
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.entity.LockableContainerBlockEntity
import net.minecraft.block.entity.ViewerCountManager
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
import net.minecraft.screen.ScreenHandler
import net.minecraft.text.Text
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
class CookingPotBlockEntity(
val blockPos: BlockPos,
val blockState: BlockState
) : LockableContainerBlockEntity(CobblemonBlockEntities.COOKING_POT, blockPos, blockState) {
var cookingPotInventory = CookingPotBlockInventory(this)
var automationDelay: Int = AUTOMATION_DELAY
var partialTicks = 0.0f
val stateManager: ViewerCountManager = object : ViewerCountManager() {
override fun onContainerOpen(world: World, pos: BlockPos, state: BlockState) {
this@CookingPotBlockEntity.setOpen(state, true)
}
override fun onContainerClose(world: World, pos: BlockPos, state: BlockState) {
this@CookingPotBlockEntity.setOpen(state, false)
}
override fun onViewerCountUpdate(world: World, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {}
override fun isPlayerViewing(player: PlayerEntity): Boolean {
if (player.currentScreenHandler is CookingPotScreenHandler) {
val inventory = (player.currentScreenHandler as CookingPotScreenHandler).inventory
return inventory === this@CookingPotBlockEntity
}
return false
}
}
companion object {
const val AUTOMATION_DELAY = 4
const val FILTER_TM_NBT = "FilterTM"
}
override fun getPos(): BlockPos {
return blockPos
}
override fun getCachedState(): BlockState {
return blockState
}
fun setOpen(state: BlockState, open: Boolean) {
world!!.setBlockState(pos, state.with(CookingPotBlock.COOKING, open), Block.NOTIFY_ALL)
}
fun tick() {
if (!removed) {
stateManager.updateViewerCount(world, pos, cachedState)
}
}
override fun clear() {
cookingPotInventory.clear()
}
override fun size(): Int {
return this.cookingPotInventory.size()
}
override fun isEmpty(): Boolean {
return this.cookingPotInventory.isEmpty()
}
override fun getStack(slot: Int): ItemStack {
return this.cookingPotInventory.getStack(slot)
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
return this.cookingPotInventory.removeStack(slot, amount)
}
override fun removeStack(slot: Int): ItemStack {
return this.cookingPotInventory.removeStack(slot)
}
override fun setStack(slot: Int, stack: ItemStack?) {
return this.cookingPotInventory.setStack(slot, stack)
}
override fun canPlayerUse(player: PlayerEntity?): Boolean {
return this.cookingPotInventory.canPlayerUse(player)
}
override fun getContainerName(): Text {
return Text.translatable("container.brewing")
}
override fun createScreenHandler(syncId: Int, playerInventory: PlayerInventory?): ScreenHandler {
return CookingPotScreenHandler(syncId, playerInventory!!, this.cookingPotInventory, this)
}
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
return BlockEntityUpdateS2CPacket.create(this)
}
override fun markDirty() {
super.markDirty()
if (this.world != null && !this.world!!.isClient) {
val currentState = world!!.getBlockState(pos)
world!!.setBlockState(pos, currentState, 3) // Flags: 2 | 1 = Block update | Render update
this.world!!.updateNeighborsAlways(this.pos, this.cachedState.block)
}
}
class CookingPotBlockInventory(val cookingPotBlockEntity: CookingPotBlockEntity) : SidedInventory {
private val BLANK_DISC_SLOT_INDEX = 0
private val GEM_SLOT_INDEX = 1
private val MISC_SLOT_INDEX = 2
private val OUTPUT_SLOT_INDEX = 3
private val INPUT_SLOTS = intArrayOf(0, 1, 2, 3)
val entityPos = this.cookingPotBlockEntity.pos
val entityState = this.cookingPotBlockEntity.cachedState
val entityWorld = this.cookingPotBlockEntity.world
var filterTM: ItemStack? = null
var items: DefaultedList<ItemStack?>? = DefaultedList.ofSize(4, ItemStack.EMPTY)
fun hasFilterTM(): Boolean {
return filterTM != null
}
override fun clear() {
cookingPotBlockEntity.markDirty()
this.items?.clear()
}
override fun size(): Int {
return this.items?.size ?: 0
}
fun getInvStack(slot: Int): ItemStack {
return items?.get(slot) ?: ItemStack.EMPTY
}
override fun isEmpty(): Boolean {
for (i in 0 until size()) {
val stack: ItemStack = getInvStack(i)
if (!stack.isEmpty) {
return false
}
}
return true
}
override fun getStack(slot: Int): ItemStack {
return items?.get(slot) ?: ItemStack.EMPTY
}
override fun getAvailableSlots(side: Direction?): IntArray? {
return if (side == Direction.DOWN) {
return listOf(this.OUTPUT_SLOT_INDEX).toIntArray()
} else this.INPUT_SLOTS
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
cookingPotBlockEntity.markDirty()
return Inventories.splitStack(items, slot, amount)
}
override fun removeStack(slot: Int): ItemStack {
val slotStack = items?.get(slot)
items?.set(slot, ItemStack.EMPTY)
cookingPotBlockEntity.markDirty()
return slotStack ?: ItemStack.EMPTY
}
override fun setStack(slot: Int, stack: ItemStack?) {
items?.set(slot, stack)
cookingPotBlockEntity.markDirty()
}
override fun markDirty() {
if (cookingPotBlockEntity.world != null)
cookingPotBlockEntity.markDirty()
}
override fun canPlayerUse(player: PlayerEntity?): Boolean {
return Inventory.canPlayerUse(this.cookingPotBlockEntity, player)
}
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
return false
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
return dir == Direction.DOWN && slot == this.OUTPUT_SLOT_INDEX
}
}
}
@@ -1,18 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.grower
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.world.feature.CobblemonConfiguredFeatures
import net.minecraft.block.sapling.SaplingGenerator
import net.minecraft.util.math.random.Random
class SaccharineTreeGrower() : SaplingGenerator() {
override fun getTreeFeature(random: Random, bl: Boolean) = CobblemonConfiguredFeatures.SACCHARINE_TREE_KEY
}
@@ -62,46 +62,6 @@ object CobblemonBakingOverrides {
cobblemonModel("restoration_tank_connector", "none")
)
val COARSE_MULCH = registerOverride(
cobblemonResource("block/coarse_mulch"),
cobblemonModel("coarse_mulch", "none")
)
val GROWTH_MULCH = registerOverride(
cobblemonResource("block/growth_mulch"),
cobblemonModel("growth_mulch", "none")
)
val HUMID_MULCH = registerOverride(
cobblemonResource("block/humid_mulch"),
cobblemonModel("humid_mulch", "none")
)
val LOAMY_MULCH = registerOverride(
cobblemonResource("block/loamy_mulch"),
cobblemonModel("loamy_mulch", "none")
)
val PEAT_MULCH = registerOverride(
cobblemonResource("block/peat_mulch"),
cobblemonModel("peat_mulch", "none")
)
val RICH_MULCH = registerOverride(
cobblemonResource("block/rich_mulch"),
cobblemonModel("rich_mulch", "none")
)
val SANDY_MULCH = registerOverride(
cobblemonResource("block/sandy_mulch"),
cobblemonModel("sandy_mulch", "none")
)
val SURPRISE_MULCH = registerOverride(
cobblemonResource("block/surprise_mulch"),
cobblemonModel("surprise_mulch", "none")
)
fun registerOverride(modelLocation: Identifier, modelIdentifier: ModelIdentifier): BakingOverride {
val result = BakingOverride(modelLocation, modelIdentifier)
models.add(result)
@@ -50,14 +50,10 @@ import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.gui.CobblemonScreenHandlers
import com.cobblemon.mod.common.gui.CobblemonScreenHandlers.COOKING_POT_SCREEN
import com.cobblemon.mod.common.gui.cooking.CookingPotHandledScreen
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asTranslated
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.ingame.HandledScreens
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.HangingSignBlockEntityRenderer
import net.minecraft.client.render.block.entity.SignBlockEntityRenderer
@@ -114,7 +110,6 @@ object CobblemonClient {
//registerColors()
registerFlywheelRenderers()
this.registerEntityRenderers()
registerHandledScreens()
Berries.observable.subscribe {
BerryModelRepository.patchModels()
}
@@ -226,16 +221,7 @@ object CobblemonClient {
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE,
CobblemonBlocks.COOKING_POT,
CobblemonBlocks.SACCHARINE_DOOR,
CobblemonBlocks.SACCHARINE_TRAPDOOR,
CobblemonBlocks.SACCHARINE_SIGN,
CobblemonBlocks.SACCHARINE_WALL_SIGN,
CobblemonBlocks.SACCHARINE_HANGING_SIGN,
CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN,
CobblemonBlocks.SACCHARINE_SAPLING,
CobblemonBlocks.BUGWORT
CobblemonBlocks.DISPLAY_CASE
)
this.createBoatModelLayers()
@@ -267,7 +253,6 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.COOKING_POT, ::CookingPotRenderer)
}
private fun registerEntityRenderers() {
@@ -321,11 +306,4 @@ object CobblemonClient {
}
}
private fun registerHandledScreens() {
HandledScreens.register(
CobblemonScreenHandlers.COOKING_POT_SCREEN,
::CookingPotHandledScreen
)
}
}
@@ -16,7 +16,6 @@ class BerryBlockEntityRenderState : BerryBlockEntity.RenderState {
override var needsRebuild = true
val vbo: VertexBuffer = VertexBuffer(VertexBuffer.Usage.STATIC)
var vboLightLevel: Int = 0
var drawVbo: Boolean = false
override fun close() {
vbo.close()
@@ -23,7 +23,6 @@ import net.minecraft.client.gl.ShaderProgram
import net.minecraft.client.gl.VertexBuffer
import net.minecraft.client.render.GameRenderer
import net.minecraft.client.render.LightmapTextureManager
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.VertexFormat
@@ -34,7 +33,6 @@ import net.minecraft.client.util.math.MatrixStack
import net.minecraft.util.math.Box
import net.minecraft.util.math.Vec3d
import org.joml.Matrix4f
import org.joml.Vector3f
class BerryBlockRenderer(private val context: BlockEntityRendererFactory.Context) : BlockEntityRenderer<BerryBlockEntity> {
@@ -47,88 +45,33 @@ class BerryBlockRenderer(private val context: BlockEntityRendererFactory.Context
override fun render(entity: BerryBlockEntity, tickDelta: Float, matrices: MatrixStack, vertexConsumers: VertexConsumerProvider, light: Int, overlay: Int) {
if (!isInRenderDistance(entity, entity.pos.toVec3d())) return
val blockState = entity.cachedState
val age = blockState.get(BerryBlock.AGE)
if (age <= BerryBlock.MATURE_AGE) {
return
}
if (entity.renderState == null) {
entity.renderState = BerryBlockEntityRenderState()
}
val renderState = entity.renderState as BerryBlockEntityRenderState
if (renderState.needsRebuild || renderState.vboLightLevel != light) {
renderToBuffer(entity, light, overlay, renderState)
renderToBuffer(entity, light, overlay, renderState.vbo)
renderState.vboLightLevel = light
(entity.renderState as BerryBlockEntityRenderState).needsRebuild = false
}
if (renderState.drawVbo) {
matrices.push()
CobblemonRenderLayers.BERRY_LAYER.startDrawing()
renderState.vbo.bind()
renderState.vbo.draw(
matrices.peek().positionMatrix.mul(RenderSystem.getModelViewMatrix()),
RenderSystem.getProjectionMatrix(),
GameRenderer.getRenderTypeCutoutProgram()
)
VertexBuffer.unbind()
CobblemonRenderLayers.BERRY_LAYER.endDrawing()
matrices.pop()
}
drawMulch(matrices, vertexConsumers, entity, light, overlay)
}
private fun drawMulch(
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
entity: BerryBlockEntity,
light: Int,
overlay: Int
) {
matrices.push()
//Mulch is rendered on a different layer than the actual berries so
val mulchBuf = vertexConsumers.getBuffer(RenderLayer.getCutout())
val model = entity.mulchVariant.model
model?.let {
it.getModel().getQuads(entity.cachedState, null, entity.world?.random).forEach { quad ->
mulchBuf.quad(matrices.peek(), quad, 1F, 1F, 1F, light, overlay)
}
}
CobblemonRenderLayers.BERRY_LAYER.startDrawing()
renderState.vbo.bind()
renderState.vbo.draw(
matrices.peek().positionMatrix.mul(RenderSystem.getModelViewMatrix()),
RenderSystem.getProjectionMatrix(),
GameRenderer.getRenderTypeCutoutProgram()
)
VertexBuffer.unbind()
CobblemonRenderLayers.BERRY_LAYER.endDrawing()
matrices.pop()
}
fun renderToBuffer(entity: BerryBlockEntity, light: Int, overlay: Int, renderState: BerryBlockEntityRenderState) {
if (entity.cachedState.get(BerryBlock.AGE) == 0) {
renderBabyToBuffer(entity, light, overlay, renderState.vbo)
renderState.drawVbo = true
}
else if (entity.cachedState.get(BerryBlock.AGE) > BerryBlock.MATURE_AGE){
renderAdultToBuffer(entity, light, overlay, renderState.vbo)
renderState.drawVbo = true
}
else {
renderState.drawVbo = false
}
}
fun renderBabyToBuffer(entity: BerryBlockEntity, light: Int, overlay: Int, buffer: VertexBuffer) {
val bufferBuilder = Tessellator.getInstance().buffer
bufferBuilder.begin(CobblemonRenderLayers.BERRY_LAYER.drawMode, CobblemonRenderLayers.BERRY_LAYER.vertexFormat)
val berry = entity.berry() ?: return
val model = BerryModelRepository.modelOf(berry.fruitModelIdentifier) ?: return
val pos = berry.stageOnePositioning.position
model.setPosition(Axis.X_AXIS.ordinal, pos.x.toFloat())
model.setPosition(Axis.Y_AXIS.ordinal, pos.y.toFloat())
model.setPosition(Axis.Z_AXIS.ordinal, pos.z.toFloat())
val rot = berry.stageOnePositioning.rotation
model.setAngles(
Math.toRadians(180 - rot.x).toFloat(),
Math.toRadians(180 + rot.y).toFloat(),
Math.toRadians(rot.z).toFloat()
)
model.render(MatrixStack(), bufferBuilder, light, overlay)
val bufferBuilderFinal = bufferBuilder.end()
buffer.bind()
buffer.upload(bufferBuilderFinal)
VertexBuffer.unbind()
}
fun renderAdultToBuffer(entity: BerryBlockEntity, light: Int, overlay: Int, buffer: VertexBuffer) {
fun renderToBuffer(entity: BerryBlockEntity, light: Int, overlay: Int, buffer: VertexBuffer) {
val blockState = entity.cachedState
val age = blockState.get(BerryBlock.AGE)
if (age <= BerryBlock.MATURE_AGE) {
@@ -1,166 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.block.DisplayCaseBlock
import com.cobblemon.mod.common.block.entity.CookingPotBlockEntity
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.item.PokemonItem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.model.json.ModelTransformationMode
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.item.BannerItem
import net.minecraft.item.BedItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtInt
import net.minecraft.util.math.Direction
import net.minecraft.util.math.RotationAxis
import net.minecraft.world.World
class CookingPotRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEntityRenderer<CookingPotBlockEntity> {
//val coinPouchStack: ItemStack by lazy { ItemStack(CobblemonItems.RELIC_COIN_POUCH).also { it.setSubNbt("CustomModelData", NbtInt.of(1)) } }
override fun render(
entity: CookingPotBlockEntity,
tickDelta: Float,
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
overlay: Int
) {
/*val stack: ItemStack = if (entity.getStack().isOf(CobblemonItems.RELIC_COIN_POUCH)) {
coinPouchStack
} else {
entity.getStack()
}
val world = entity.world ?: return
val posType = getPositioningType(stack, world)
val blockState = if (entity.world != null) entity.cachedState
else (CobblemonBlocks.DISPLAY_CASE.defaultState.with(DisplayCaseBlock.ITEM_DIRECTION, Direction.NORTH))
val yRot = if (posType == PositioningType.ITEM_MODEL) blockState.get(DisplayCaseBlock.ITEM_DIRECTION).opposite.asRotation()
else blockState.get(DisplayCaseBlock.ITEM_DIRECTION).asRotation()
if (stack.item is PokemonItem) {
renderPokemon(
matrices,
vertexConsumers,
light,
stack,
yRot
)
return
}
matrices.push()
matrices.translate(0.5f, 0.4f, 0.5f)
matrices.scale(posType.scaleX, posType.scaleY, posType.scaleZ)
matrices.translate(posType.transX, posType.transY, posType.transZ)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yRot))
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(posType.rotY))
MinecraftClient.getInstance().itemRenderer.renderItem(
stack,
ModelTransformationMode.GROUND,
light,
overlay,
matrices,
vertexConsumers,
entity.world,
0
)
matrices.pop()*/
}
private fun renderPokemon(
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
stack: ItemStack,
yRot: Float
) {
val item = stack.item as? PokemonItem ?: return
val pokemon = item.asPokemon(stack) ?: return
val model = PokemonModelRepository.getPoser(pokemon.species.resourceIdentifier, pokemon.aspects)
val renderLayer = model.getLayer(PokemonModelRepository.getTexture(pokemon.species.resourceIdentifier, pokemon.aspects, 0F))
val tint = item.tint(stack)
val vertexConsumer: VertexConsumer = vertexConsumers.getBuffer(renderLayer)
val scale = 0.25f
matrices.push()
matrices.scale(1f, -1f, -1f)
matrices.translate(0.5f, -0.69f, -0.5f)
matrices.scale(scale, scale, scale)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yRot))
model.setupAnimStateless(PoseType.PROFILE)
model.withLayerContext(vertexConsumers, null, PokemonModelRepository.getLayers(pokemon.species.resourceIdentifier, pokemon.aspects)) {
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, tint.x, tint.y, tint.z, tint.w)
}
matrices.pop()
}
companion object {
private val mobHeads = listOf<Item>(
Items.SKELETON_SKULL,
Items.WITHER_SKELETON_SKULL,
Items.ZOMBIE_HEAD,
Items.PIGLIN_HEAD,
Items.PLAYER_HEAD,
Items.DRAGON_HEAD,
Items.CREEPER_HEAD
)
private fun getPositioningType(stack: ItemStack, world: World) = when {
mobHeads.contains(stack.item) -> PositioningType.MOB_HEAD
stack.item is BedItem -> PositioningType.BED
stack.item is BannerItem -> PositioningType.BANNER
stack.item is PokeBallItem -> PositioningType.POKE_BALL
stack.item == CobblemonItems.RELIC_COIN_POUCH -> PositioningType.COIN_POUCH
stack.item == CobblemonItems.PASTURE -> PositioningType.PASTURE
stack.item == CobblemonItems.POKEMON_MODEL -> PositioningType.ITEM_MODEL
stack.item == Items.SHIELD -> PositioningType.SHIELD
stack.item == Items.DECORATED_POT -> PositioningType.MOB_HEAD
MinecraftClient.getInstance().itemRenderer.getModel(stack, world, null, 0).hasDepth() -> PositioningType.BLOCK_MODEL
else -> PositioningType.ITEM_MODEL
}
}
private enum class PositioningType(
val scaleX: Float, val scaleY: Float, val scaleZ: Float,
val transX: Float, val transY: Float, val transZ: Float,
val rotY: Float = 0f
) {
POKE_BALL(1f, 1f, 1f, 0f, 0.04f, 0f),
BLOCK_MODEL(1f, 1f, 1f, 0f, -0.15f, 0f),
ITEM_MODEL(1f, 1f, 1f, 0f, 0.04f, 0f),
BED(1f, 1f, 1f, 0f, -0.02f, 0f),
BANNER(1f, 1f, 1f, 0f, -0.02f, 0f, 180f),
MOB_HEAD(1f, 1f, 1f, 0f, -0.025f, 0f, 180f),
SHIELD(1f, 1f, 1f, 0f, -0.045f, 0f, 180f),
PASTURE(1f, 1f, 1f, 0f, 0.0375f, 0f),
COIN_POUCH(1f, 1f, 1f, 0f, 0.415f, 0f)
}
}
@@ -36,7 +36,6 @@ class ConkeldurrModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, B
lateinit var battleidle: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("conkeldurr", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("conkeldurr", "blink") }
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFr
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -41,8 +40,6 @@ class GolettModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Biped
lateinit var walk: PokemonPose
lateinit var sleep: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("golett", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("golett", "blink") }
standing = registerPose(
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntitySt
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatefulAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
@@ -34,8 +33,6 @@ class GolurkModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
lateinit var walk: PokemonPose
lateinit var sleep: PokemonPose
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("golurk", "cry") }
override fun registerPoses() {
val blink = quirk { bedrockStateful("golurk", "blink") }
@@ -0,0 +1,35 @@
package com.cobblemon.mod.common.command
import com.cobblemon.mod.common.battles.BattleBuilder
import com.cobblemon.mod.common.util.party
import com.mojang.brigadier.Command
import com.mojang.brigadier.CommandDispatcher
import com.mojang.brigadier.context.CommandContext
import net.minecraft.command.argument.EntityArgumentType
import net.minecraft.server.command.CommandManager
import net.minecraft.server.command.ServerCommandSource
object ChallengeCommand {
fun register(dispatcher : CommandDispatcher<ServerCommandSource>) {
val command = CommandManager.literal("battle")
.then(
CommandManager
.argument("target", EntityArgumentType.player())
.executes(::execute)
)
dispatcher.register(command)
}
private fun execute(context: CommandContext<ServerCommandSource>) : Int {
val player = context.source.playerOrThrow
val target = EntityArgumentType.getPlayer(context, "target")
val leadingPlayerPokemon = player.party().filterNotNull().firstOrNull() ?: return 0
val leadingTargetPokemon = target.party().filterNotNull().firstOrNull() ?: return 0
BattleBuilder.pvp1v1(player, target, leadingPlayerPokemon.uuid, leadingTargetPokemon.uuid)
return Command.SINGLE_SUCCESS
}
}
@@ -24,6 +24,7 @@ import com.mojang.brigadier.context.CommandContext
import net.minecraft.server.command.CommandManager
import net.minecraft.server.command.CommandManager.literal
import net.minecraft.server.command.ServerCommandSource
import net.minecraft.text.Text
/**
* Spawn Pokemon From Surrounding Pool
@@ -83,15 +84,14 @@ object SpawnPokemonFromPool {
val spawnAction = result.second.doSpawn(ctx = result.first)
spawnAction.future
.thenApply {
if (it is EntitySpawnResult) {
for (entity in it.entities) {
player.sendMessage(commandLang("spawnpokemonfrompool", entity.displayName).green())
}
spawnAction.future.thenApply {
if (it is EntitySpawnResult) {
for (entity in it.entities) {
player.sendMessage(commandLang("spawnpokemonfrompool.success", entity.displayName).green())
}
}
spawnAction.complete()
}
spawnsTriggered++
}
@@ -171,6 +171,9 @@ class CobblemonConfig {
@NodeCategory(Category.Spawning)
var baseApricornTreeGenerationChance = 0.1F
@NodeCategory(Category.Pokemon)
var ninjaskCreatesShedinja = true
@NodeCategory(Category.Pokemon)
var displayEntityLevelLabel = true
@@ -21,15 +21,13 @@ import net.minecraft.util.StringIdentifiable
*/
enum class CobblemonBoatType(val mountedOffset: Double) : StringIdentifiable {
APRICORN(-0.1),
SACCHARINE(-.01);
APRICORN(-0.1);
/**
* The base [Item] form of this [CobblemonBoatType].
*/
val boatItem: Item get() = when (this) {
APRICORN -> CobblemonItems.APRICORN_BOAT
SACCHARINE -> CobblemonItems.SACCHARINE_BOAT
}
/**
@@ -37,7 +35,6 @@ enum class CobblemonBoatType(val mountedOffset: Double) : StringIdentifiable {
*/
val chestBoatItem: Item get() = when (this) {
APRICORN -> CobblemonItems.APRICORN_CHEST_BOAT
SACCHARINE -> CobblemonItems.SACCHARINE_CHEST_BOAT
}
/**
@@ -45,7 +42,6 @@ enum class CobblemonBoatType(val mountedOffset: Double) : StringIdentifiable {
*/
val baseBlock: Block get() = when (this) {
APRICORN -> CobblemonBlocks.APRICORN_PLANKS
SACCHARINE -> CobblemonBlocks.SACCHARINE_PLANKS
}
/**
@@ -53,7 +49,6 @@ enum class CobblemonBoatType(val mountedOffset: Double) : StringIdentifiable {
*/
val woodType: WoodType get() = when (this) {
APRICORN -> CobblemonBlocks.APRICORN_WOOD_TYPE
SACCHARINE -> CobblemonBlocks.SACCHARINE_WOOD_TYPE
}
override fun asString(): String = this.name.lowercase()
@@ -1,86 +0,0 @@
package com.cobblemon.mod.common.entity.throwable
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.mob.BlazeEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.thrown.ThrownItemEntity
import net.minecraft.item.Item
import net.minecraft.item.Items
import net.minecraft.particle.ItemStackParticleEffect
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleTypes
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.hit.EntityHitResult
import net.minecraft.util.hit.HitResult
import net.minecraft.world.World
class ScatterBangEntity : ThrownItemEntity {
constructor(entityType: EntityType<out ScatterBangEntity?>?, world: World?) : super(entityType, world)
constructor(world: World?, owner: LivingEntity?) : super(EntityType.SNOWBALL, owner, world)
constructor(world: World?, x: Double, y: Double, z: Double) : super(EntityType.SNOWBALL, x, y, z, world)
override fun getDefaultItem(): Item {
return Items.SNOWBALL
}
private val particleParameters: ParticleEffect
get() {
val itemStack = this.item
return (if (itemStack.isEmpty) ParticleTypes.ITEM_SNOWBALL else ItemStackParticleEffect(
ParticleTypes.ITEM,
itemStack
)) as ParticleEffect
}
override fun handleStatus(status: Byte) {
if (status.toInt() == 3) {
val particleEffect = this.particleParameters
for (i in 0..7) {
world.addParticle(particleEffect, this.x, this.y, this.z, 0.0, 0.0, 0.0)
}
}
}
override fun onEntityHit(entityHitResult: EntityHitResult) {
world.playSound(
null as PlayerEntity?,
this.x,
this.y,
this.z,
SoundEvents.ENTITY_GENERIC_EXPLODE,
SoundCategory.NEUTRAL,
0.6f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
super.onEntityHit(entityHitResult)
val entity = entityHitResult.entity
val i = if (entity is BlazeEntity) 3 else 0
entity.damage(this.damageSources.thrown(this, this.owner), i.toFloat())
}
override fun onCollision(hitResult: HitResult) {
world.playSound(
null as PlayerEntity?,
this.x,
this.y,
this.z,
SoundEvents.ENTITY_GENERIC_EXPLODE,
SoundCategory.NEUTRAL,
0.6f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
super.onCollision(hitResult)
if (!world.isClient) {
world.sendEntityStatus(this, 3.toByte())
this.discard()
}
}
}
@@ -1,86 +0,0 @@
package com.cobblemon.mod.common.entity.throwable
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.mob.BlazeEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.thrown.ThrownItemEntity
import net.minecraft.item.Item
import net.minecraft.item.Items
import net.minecraft.particle.ItemStackParticleEffect
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleTypes
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.util.hit.EntityHitResult
import net.minecraft.util.hit.HitResult
import net.minecraft.world.World
class StickyGlobEntity : ThrownItemEntity {
constructor(entityType: EntityType<out StickyGlobEntity?>?, world: World?) : super(entityType, world)
constructor(world: World?, owner: LivingEntity?) : super(EntityType.SNOWBALL, owner, world)
constructor(world: World?, x: Double, y: Double, z: Double) : super(EntityType.SNOWBALL, x, y, z, world)
override fun getDefaultItem(): Item {
return Items.SNOWBALL
}
private val particleParameters: ParticleEffect
get() {
val itemStack = this.item
return (if (itemStack.isEmpty) ParticleTypes.ITEM_SNOWBALL else ItemStackParticleEffect(
ParticleTypes.ITEM,
itemStack
)) as ParticleEffect
}
override fun handleStatus(status: Byte) {
if (status.toInt() == 3) {
val particleEffect = this.particleParameters
for (i in 0..7) {
world.addParticle(particleEffect, this.x, this.y, this.z, 0.0, 0.0, 0.0)
}
}
}
override fun onEntityHit(entityHitResult: EntityHitResult) {
world.playSound(
null as PlayerEntity?,
this.x,
this.y,
this.z,
SoundEvents.ENTITY_SLIME_SQUISH,
SoundCategory.NEUTRAL,
0.6f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
super.onEntityHit(entityHitResult)
val entity = entityHitResult.entity
val i = if (entity is BlazeEntity) 3 else 0
entity.damage(this.damageSources.thrown(this, this.owner), i.toFloat())
}
override fun onCollision(hitResult: HitResult) {
world.playSound(
null as PlayerEntity?,
this.x,
this.y,
this.z,
SoundEvents.ENTITY_SLIME_SQUISH,
SoundCategory.NEUTRAL,
0.6f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
super.onCollision(hitResult)
if (!world.isClient) {
world.sendEntityStatus(this, 3.toByte())
this.discard()
}
}
}
@@ -1,201 +0,0 @@
package com.cobblemon.mod.common.gui
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.SimpleInventory
import net.minecraft.item.ItemStack
import net.minecraft.recipe.*
import net.minecraft.recipe.book.RecipeBookCategory
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.screen.ArrayPropertyDelegate
import net.minecraft.screen.PropertyDelegate
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.screen.slot.FurnaceOutputSlot
import net.minecraft.screen.slot.Slot
import net.minecraft.world.World
abstract class AbstractCookingPotScreenHandler(
type: ScreenHandlerType<*>?,
private val recipeType: RecipeType<out AbstractCookingRecipe?>,
private val category: RecipeBookCategory,
syncId: Int,
playerInventory: PlayerInventory?,
inventory: Inventory? = SimpleInventory(3),
propertyDelegate: PropertyDelegate? = ArrayPropertyDelegate(
4
)
) :
AbstractRecipeScreenHandler<Inventory?>(type, syncId) {
lateinit var inventory: Inventory
lateinit var propertyDelegate: PropertyDelegate
lateinit var world: World
init {
checkSize(inventory, 3)
checkDataCount(propertyDelegate, 4)
if (inventory != null) {
this.inventory = inventory
}
if (propertyDelegate != null) {
this.propertyDelegate = propertyDelegate
}
if (playerInventory != null) {
this.world = playerInventory.player.world
}
this.addSlot(Slot(inventory, 0, 56, 17))
//this.addSlot(FurnaceFuelSlot(this, inventory, 1, 56, 53))
if (playerInventory != null) {
this.addSlot(FurnaceOutputSlot(playerInventory.player, inventory, 2, 116, 35))
}
var i = 0
while (i < 3) {
for (j in 0..8) {
this.addSlot(Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18))
}
++i
}
i = 0
while (i < 9) {
this.addSlot(Slot(playerInventory, i, 8 + i * 18, 142))
++i
}
this.addProperties(propertyDelegate)
}
override fun populateRecipeFinder(finder: RecipeMatcher) {
if (inventory is RecipeInputProvider) {
(inventory as RecipeInputProvider).provideRecipeInputs(finder)
}
}
override fun clearCraftingSlots() {
getSlot(0).setStackNoCallbacks(ItemStack.EMPTY)
getSlot(2).setStackNoCallbacks(ItemStack.EMPTY)
}
override fun matches(recipe: Recipe<in Inventory?>): Boolean {
return recipe.matches(this.inventory, this.world)
}
override fun getCraftingResultSlotIndex(): Int {
return 2
}
override fun getCraftingWidth(): Int {
return 1
}
override fun getCraftingHeight(): Int {
return 1
}
override fun getCraftingSlotCount(): Int {
return 3
}
override fun canUse(player: PlayerEntity): Boolean {
return inventory.canPlayerUse(player)
}
override fun quickMove(player: PlayerEntity, slot: Int): ItemStack {
var itemStack = ItemStack.EMPTY
val slot2 = slots[slot]
if (slot2 != null && slot2.hasStack()) {
val itemStack2 = slot2.stack
itemStack = itemStack2.copy()
if (slot == 2) {
if (!this.insertItem(itemStack2, 3, 39, true)) {
return ItemStack.EMPTY
}
slot2.onQuickTransfer(itemStack2, itemStack)
} else if (slot != 1 && slot != 0) {
/*if (this.isSmeltable(itemStack2)) {
if (!this.insertItem(itemStack2, 0, 1, false)) {
return ItemStack.EMPTY
}
}*/ /*else if (this.isFuel(itemStack2)) {
if (!this.insertItem(itemStack2, 1, 2, false)) {
return ItemStack.EMPTY
}
}*/ if (slot >= 3 && slot < 30) {
if (!this.insertItem(itemStack2, 30, 39, false)) {
return ItemStack.EMPTY
}
} else if (slot >= 30 && slot < 39 && !this.insertItem(itemStack2, 3, 30, false)) {
return ItemStack.EMPTY
}
} else if (!this.insertItem(itemStack2, 3, 39, false)) {
return ItemStack.EMPTY
}
if (itemStack2.isEmpty) {
slot2.stack = ItemStack.EMPTY
} else {
slot2.markDirty()
}
if (itemStack2.count == itemStack.count) {
return ItemStack.EMPTY
}
slot2.onTakeItem(player, itemStack2)
}
return itemStack
}
/*fun isSmeltable(itemStack: ItemStack): Boolean {
return world.recipeManager.getFirstMatch(
this.recipeType, SimpleInventory(*arrayOf(itemStack)),
this.world
).isPresent
}*/
/*protected fun isFuel(itemStack: ItemStack?): Boolean {
return AbstractFurnaceBlockEntity.canUseAsFuel(itemStack)
}*/
val cookProgress: Int
get() {
val i = propertyDelegate[2]
val j = propertyDelegate[3]
return if (j != 0 && i != 0) i * 24 / j else 0
}
val fuelProgress: Int
get() {
var i = propertyDelegate[1]
if (i == 0) {
i = 200
}
return propertyDelegate[0] * 13 / i
}
val isBurning: Boolean
get() = propertyDelegate[0] > 0
override fun getCategory(): RecipeBookCategory {
return this.category
}
override fun canInsertIntoSlot(index: Int): Boolean {
return index != 1
}
companion object {
const val field_30738: Int = 0
const val field_30739: Int = 1
const val field_30740: Int = 2
const val field_30741: Int = 3
const val field_30742: Int = 4
private const val field_30743 = 3
private const val field_30744 = 30
private const val field_30745 = 30
private const val field_30746 = 39
}
}
@@ -1,27 +0,0 @@
package com.cobblemon.mod.common.gui
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.mixin.invoker.ScreenHandlerTypeInvoker
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.screen.ScreenHandlerType.Factory
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerContext
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.text.Text
import net.minecraft.util.Identifier
object CobblemonScreenHandlers {
//val TMM_SCREEN = register(cobblemonResource("tmm_screen"), ::TMMScreenHandler)
val COOKING_POT_SCREEN = register(cobblemonResource("cooking_pot_screen")) { syncId, playerInventory ->
CookingPotScreenHandler(syncId, playerInventory, ScreenHandlerContext.EMPTY)
}
fun <T : ScreenHandler> register(identifier: Identifier, factory: Factory<T>): ScreenHandlerType<T> {
val result = ScreenHandlerTypeInvoker.`cobblemon$create`(factory, FeatureFlags.VANILLA_FEATURES)
Cobblemon.implementation.registerScreenHandlerType(identifier, result)
return result
}
}
@@ -1,206 +0,0 @@
package com.cobblemon.mod.common.gui
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.block.entity.CookingPotBlockEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.CraftingInventory
import net.minecraft.inventory.CraftingResultInventory
import net.minecraft.inventory.Inventory
import net.minecraft.inventory.RecipeInputInventory
import net.minecraft.item.ItemStack
import net.minecraft.network.packet.s2c.play.ScreenHandlerSlotUpdateS2CPacket
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.RecipeMatcher
import net.minecraft.recipe.RecipeType
import net.minecraft.recipe.book.RecipeBookCategory
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.ScreenHandlerContext
import net.minecraft.screen.slot.CraftingResultSlot
import net.minecraft.screen.slot.Slot
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.MutableText
import net.minecraft.world.World
class CookingPotScreenHandler : AbstractRecipeScreenHandler<RecipeInputInventory> {
val input: CraftingInventory
val result: CraftingResultInventory
val context: ScreenHandlerContext
val player: PlayerEntity
var inventory: Inventory? = null
companion object {
const val RESULT_ID = 0
private const val INPUT_START = 1
private const val INPUT_END = 10
private const val INVENTORY_START = 10
private const val INVENTORY_END = 37
private const val HOTBAR_START = 37
private const val HOTBAR_END = 46
fun updateResult(
handler: ScreenHandler,
world: World,
player: PlayerEntity,
craftingInventory: RecipeInputInventory,
resultInventory: CraftingResultInventory
) {
if (world.isClient) return
val serverPlayerEntity = player as ServerPlayerEntity
var itemStack = ItemStack.EMPTY
val optional = world.server?.recipeManager?.getFirstMatch(
RecipeType.CRAFTING, craftingInventory, world
)
if (optional != null) {
if (optional.isPresent) {
val craftingRecipe = optional.get()
val itemStack2 = craftingRecipe.craft(craftingInventory, world.registryManager)
if (itemStack2.isItemEnabled(world.enabledFeatures)) {
itemStack = itemStack2
}
}
}
resultInventory.setStack(0, itemStack)
handler.setPreviousTrackedSlot(0, itemStack)
serverPlayerEntity.networkHandler.sendPacket(
ScreenHandlerSlotUpdateS2CPacket(handler.syncId, handler.nextRevision(), 0, itemStack)
)
}
}
constructor(syncId: Int, playerInventory: PlayerInventory, context: ScreenHandlerContext) :
super(CobblemonScreenHandlers.COOKING_POT_SCREEN, syncId) {
this.context = context
this.player = playerInventory.player
this.input = CraftingInventory(this, 3, 3)
this.result = CraftingResultInventory()
initializeSlots(playerInventory)
}
constructor(syncId: Int, playerInventory: PlayerInventory, cookingPotInventory: CookingPotBlockEntity.CookingPotBlockInventory, cookingPotBlockEntity: CookingPotBlockEntity) :
super(CobblemonScreenHandlers.COOKING_POT_SCREEN, syncId) {
this.context = ScreenHandlerContext.EMPTY
this.player = playerInventory.player
this.input = CraftingInventory(this, 3, 3)
this.result = CraftingResultInventory()
this.inventory = cookingPotInventory
initializeSlots(playerInventory)
}
private fun initializeSlots(playerInventory: PlayerInventory) {
val craftingGridOffsetX = 14
val craftingGridOffsetY = 10
val craftingOutputOffsetX = 16
val craftingOutputOffsetY = 10
val playerInventoryOffsetX = 0
val playerInventoryOffsetY = 16
addSlot(CraftingResultSlot(playerInventory.player, input, result, 0, 124 + craftingOutputOffsetX, 35 + craftingOutputOffsetY))
for (i in 0..2) {
for (j in 0..2) {
addSlot(Slot(input, j + i * 3, 30 + craftingGridOffsetX + j * 18, 17 + craftingGridOffsetY + i * 18))
}
}
for (i in 0..2) {
for (j in 0..8) {
addSlot(Slot(playerInventory, j + i * 9 + 9, 8 + playerInventoryOffsetX + j * 18, 84 + playerInventoryOffsetY+ i * 18))
}
}
for (i in 0..8) {
addSlot(Slot(playerInventory, i, 8 + playerInventoryOffsetX + i * 18, 142 + playerInventoryOffsetY))
}
}
override fun onContentChanged(inventory: Inventory) {
context.run { world, pos -> updateResult(this@CookingPotScreenHandler, world, player, input, result) }
}
override fun populateRecipeFinder(finder: RecipeMatcher) {
input.provideRecipeInputs(finder)
}
override fun clearCraftingSlots() {
input.clear()
result.clear()
}
override fun matches(recipe: Recipe<in RecipeInputInventory>): Boolean {
return recipe.matches(input, player.world)
}
override fun onClosed(player: PlayerEntity) {
super.onClosed(player)
context.run { world, pos -> dropInventory(player, input) }
}
override fun canUse(player: PlayerEntity): Boolean {
return canUse(context, player, CobblemonBlocks.COOKING_POT)
}
override fun quickMove(player: PlayerEntity, slot: Int): ItemStack {
var itemStack = ItemStack.EMPTY
val slot2 = slots[slot] as Slot
if (slot2.hasStack()) {
val itemStack2 = slot2.stack
itemStack = itemStack2.copy()
if (slot == 0) {
context.run { world, pos -> itemStack2.item.onCraft(itemStack2, world, player) }
if (!insertItem(itemStack2, 10, 46, true)) {
return ItemStack.EMPTY
}
slot2.onQuickTransfer(itemStack2, itemStack)
} else if (slot in 10 until 46) {
if (!insertItem(itemStack2, 1, 10, false) && (slot < 37 && !insertItem(itemStack2, 37, 46, false) || !insertItem(itemStack2, 10, 37, false))) {
return ItemStack.EMPTY
}
} else if (!insertItem(itemStack2, 10, 46, false)) {
return ItemStack.EMPTY
}
if (itemStack2.isEmpty) {
slot2.stack = ItemStack.EMPTY
} else {
slot2.markDirty()
}
if (itemStack2.count == itemStack.count) {
return ItemStack.EMPTY
}
slot2.onTakeItem(player, itemStack2)
if (slot == 0) {
player.dropItem(itemStack2, false)
}
}
return itemStack
}
override fun canInsertIntoSlot(stack: ItemStack, slot: Slot): Boolean {
return slot.inventory !== result && super.canInsertIntoSlot(stack, slot)
}
override fun getCraftingResultSlotIndex(): Int {
return RESULT_ID
}
override fun getCraftingWidth(): Int {
return input.width
}
override fun getCraftingHeight(): Int {
return input.height
}
override fun getCraftingSlotCount(): Int {
return 10
}
override fun getCategory(): RecipeBookCategory {
return RecipeBookCategory.CRAFTING
}
override fun canInsertIntoSlot(index: Int): Boolean {
return index != craftingResultSlotIndex
}
}
@@ -1,120 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.HashBasedTable
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.common.collect.Lists
import com.google.common.collect.Maps
import com.google.common.collect.Table
import com.mojang.logging.LogUtils
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.gui.screen.recipebook.RecipeResultCollection
import net.minecraft.recipe.AbstractCookingRecipe
import net.minecraft.recipe.CraftingRecipe
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.RecipeType
import net.minecraft.recipe.book.CookingRecipeCategory
import net.minecraft.recipe.book.CraftingRecipeCategory
import net.minecraft.recipe.book.RecipeBook
import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.registry.Registries
import org.slf4j.Logger
import java.util.*
@Environment(EnvType.CLIENT)
class ClientCookBook : RecipeBook() {
private val logger: Logger = LogUtils.getLogger()
private var resultsByGroup: Map<CookBookGroup, List<RecipeResultCollection>> = ImmutableMap.of()
private var orderedResults: List<RecipeResultCollection> = ImmutableList.of()
fun reload(recipes: Iterable<Recipe<*>>, registryManager: DynamicRegistryManager) {
val groupedMap = toGroupedMap(recipes)
val map2 = Maps.newHashMap<CookBookGroup, List<RecipeResultCollection>>()
val builder = ImmutableList.builder<RecipeResultCollection>()
groupedMap.forEach { (recipeBookGroup, list) ->
val var10002 = list.stream().map { recipes ->
RecipeResultCollection(registryManager, recipes)
}
map2[recipeBookGroup] = var10002.peek { builder.add(it) }.collect(ImmutableList.toImmutableList())
}
CookBookGroup.SEARCH_MAP.forEach { (group, searchGroups) ->
map2[group] = searchGroups.stream().flatMap { searchGroup ->
map2.getOrDefault(searchGroup, ImmutableList.of()).stream()
}.collect(ImmutableList.toImmutableList())
}
resultsByGroup = ImmutableMap.copyOf(map2)
orderedResults = builder.build()
}
private fun toGroupedMap(recipes: Iterable<Recipe<*>>): Map<CookBookGroup, List<List<Recipe<*>>>> {
val map = Maps.newHashMap<CookBookGroup, MutableList<List<Recipe<*>>>>()
val table: Table<CookBookGroup, String, MutableList<Recipe<*>>> = HashBasedTable.create()
for (recipe in recipes) {
if (!recipe.isIgnoredInRecipeBook && !recipe.isEmpty) {
val recipeBookGroup = getGroupForRecipe(recipe)
val group = recipe.group
if (group.isEmpty()) {
map.computeIfAbsent(recipeBookGroup) { Lists.newArrayList() }.add(ImmutableList.of(recipe))
} else {
val list = table.get(recipeBookGroup, group) ?: Lists.newArrayList<Recipe<*>>().also { newList ->
table.put(recipeBookGroup, group, newList)
map.computeIfAbsent(recipeBookGroup) { Lists.newArrayList() }.add(newList)
}
list.add(recipe)
}
}
}
return map
}
private fun getGroupForRecipe(recipe: Recipe<*>): CookBookGroup {
return when {
recipe is CraftingRecipe -> {
when (recipe.category) {
CraftingRecipeCategory.BUILDING -> CookBookGroup.CRAFTING_BUILDING_BLOCKS
CraftingRecipeCategory.EQUIPMENT -> CookBookGroup.CRAFTING_EQUIPMENT
CraftingRecipeCategory.REDSTONE -> CookBookGroup.CRAFTING_REDSTONE
CraftingRecipeCategory.MISC -> CookBookGroup.CRAFTING_MISC
else -> throw IncompatibleClassChangeError()
}
}
recipe is AbstractCookingRecipe -> {
val cookingRecipeCategory = recipe.category
when (recipe.type) {
RecipeType.SMELTING -> {
when (cookingRecipeCategory) {
CookingRecipeCategory.BLOCKS -> CookBookGroup.FURNACE_BLOCKS
CookingRecipeCategory.FOOD -> CookBookGroup.FURNACE_FOOD
CookingRecipeCategory.MISC -> CookBookGroup.FURNACE_MISC
else -> throw IncompatibleClassChangeError()
}
}
RecipeType.BLASTING -> {
if (cookingRecipeCategory == CookingRecipeCategory.BLOCKS) CookBookGroup.BLAST_FURNACE_BLOCKS else CookBookGroup.BLAST_FURNACE_MISC
}
RecipeType.SMOKING -> CookBookGroup.SMOKER_FOOD
RecipeType.CAMPFIRE_COOKING -> CookBookGroup.CAMPFIRE
else -> {
logger.warn("Unknown recipe category: {}/{}", LogUtils.defer { Registries.RECIPE_TYPE.getId(recipe.type) }, LogUtils.defer { recipe.id })
CookBookGroup.UNKNOWN
}
}
}
recipe.type == RecipeType.STONECUTTING -> CookBookGroup.STONECUTTER
recipe.type == RecipeType.SMITHING -> CookBookGroup.SMITHING
else -> {
logger.warn("Unknown recipe category: {}/{}", LogUtils.defer { Registries.RECIPE_TYPE.getId(recipe.type) }, LogUtils.defer { recipe.id })
CookBookGroup.UNKNOWN
}
}
}
fun getOrderedResults(): List<RecipeResultCollection> {
return orderedResults
}
fun getResultsForGroup(category: CookBookGroup): List<RecipeResultCollection> {
return resultsByGroup.getOrDefault(category, Collections.emptyList())
}
}
@@ -1,100 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.Sets
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.book.RecipeBook
import net.minecraft.recipe.book.RecipeBookCategory
import net.minecraft.recipe.book.RecipeBookOptions
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.util.Identifier
import org.jetbrains.annotations.Nullable
class CookBook : RecipeBook() {
protected val recipes: MutableSet<Identifier> = Sets.newHashSet()
protected val toBeDisplayed: MutableSet<Identifier> = Sets.newHashSet()
private val options = RecipeBookOptions()
fun copyFrom(book: CookBook) {
recipes.clear()
toBeDisplayed.clear()
options.copyFrom(book.options)
recipes.addAll(book.recipes)
toBeDisplayed.addAll(book.toBeDisplayed)
}
override fun add(recipe: Recipe<*>) {
if (!recipe.isIgnoredInRecipeBook) {
add(recipe.id)
}
}
override fun add(id: Identifier) {
recipes.add(id)
}
override fun contains(@Nullable recipe: Recipe<*>?): Boolean {
return recipe?.let { recipes.contains(it.id) } ?: false
}
override fun contains(id: Identifier): Boolean {
return recipes.contains(id)
}
override fun remove(recipe: Recipe<*>) {
remove(recipe.id)
}
override fun remove(id: Identifier) {
recipes.remove(id)
toBeDisplayed.remove(id)
}
override fun shouldDisplay(recipe: Recipe<*>): Boolean {
return toBeDisplayed.contains(recipe.id)
}
override fun onRecipeDisplayed(recipe: Recipe<*>) {
toBeDisplayed.remove(recipe.id)
}
override fun display(recipe: Recipe<*>) {
display(recipe.id)
}
override fun display(id: Identifier) {
toBeDisplayed.add(id)
}
override fun isGuiOpen(category: RecipeBookCategory): Boolean {
return options.isGuiOpen(category)
}
override fun setGuiOpen(category: RecipeBookCategory, open: Boolean) {
options.setGuiOpen(category, open)
}
override fun isFilteringCraftable(handler: AbstractRecipeScreenHandler<*>): Boolean {
return isFilteringCraftable(handler.category)
}
override fun isFilteringCraftable(category: RecipeBookCategory): Boolean {
return options.isFilteringCraftable(category)
}
override fun setFilteringCraftable(category: RecipeBookCategory, filteringCraftable: Boolean) {
options.setFilteringCraftable(category, filteringCraftable)
}
override fun setOptions(options: RecipeBookOptions) {
this.options.copyFrom(options)
}
override fun getOptions(): RecipeBookOptions {
return options.copy()
}
override fun setCategoryOptions(category: RecipeBookCategory, guiOpen: Boolean, filteringCraftable: Boolean) {
options.setGuiOpen(category, guiOpen)
options.setFilteringCraftable(category, filteringCraftable)
}
}
@@ -1,136 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.Lists
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
import net.minecraft.client.gui.screen.narration.NarrationPart
import net.minecraft.client.gui.screen.recipebook.RecipeBookResults
import net.minecraft.client.gui.screen.recipebook.RecipeResultCollection
import net.minecraft.client.gui.tooltip.Tooltip
import net.minecraft.client.gui.widget.ClickableWidget
import net.minecraft.item.ItemStack
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.book.RecipeBook
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.screen.ScreenTexts
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.math.MathHelper
@Environment(EnvType.CLIENT)
class CookBookAnimatedResultButton : ClickableWidget(0, 0, 25, 25, ScreenTexts.EMPTY) {
val BACKGROUND_TEXTURE = Identifier("textures/gui/recipe_book.png")
val field_32414 = 15.0f
val field_32415 = 25
val field_32413 = 30
val MORE_RECIPES_TEXT = Text.translatable("gui.recipebook.moreRecipes")
lateinit var craftingScreenHandler: AbstractRecipeScreenHandler<*>
lateinit var recipeBook: RecipeBook
lateinit var resultCollection: RecipeResultCollection
var time = 0f
var bounce = 0f
var currentResultIndex = 0
fun showResultCollection(resultCollection: RecipeResultCollection, results: CookBookResults) {
this.resultCollection = resultCollection
this.craftingScreenHandler = results.getClientValue().player?.currentScreenHandler as AbstractRecipeScreenHandler<*>
this.recipeBook = results.getCookBookValue()
val list = resultCollection.getResults(this.recipeBook.isFilteringCraftable(this.craftingScreenHandler))
for (recipe in list) {
if (this.recipeBook.shouldDisplay(recipe)) {
results.onRecipesDisplayed(list)
this.bounce = 15.0f
break
}
}
}
fun getResultCollectionValue(): RecipeResultCollection {
return this.resultCollection
}
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
if (!Screen.hasControlDown()) {
this.time += delta
}
val minecraftClient = MinecraftClient.getInstance()
var i = 29
if (!this.resultCollection.hasCraftableRecipes()) {
i += 25
}
var j = 206
if (this.resultCollection.getResults(this.recipeBook.isFilteringCraftable(this.craftingScreenHandler)).size > 1) {
j += 25
}
val bl = this.bounce > 0.0f
if (bl) {
val f = 1.0f + 0.1f * Math.sin((this.bounce / 15.0f * Math.PI).toDouble()).toFloat()
context.matrices.push()
context.matrices.translate((this.x + 8).toFloat(), (this.y + 12).toFloat(), 0.0f)
context.matrices.scale(f, f, 1.0f)
context.matrices.translate(-(this.x + 8).toFloat(), -(this.y + 12).toFloat(), 0.0f)
this.bounce -= delta
}
context.drawTexture(BACKGROUND_TEXTURE, this.x, this.y, i, j, this.width, this.height)
val list = this.results
this.currentResultIndex = MathHelper.floor(this.time / 30.0f) % list.size
val itemStack = list[this.currentResultIndex].getOutput(this.resultCollection.registryManager)
var k = 4
if (this.resultCollection.hasSingleOutput() && this.results.size > 1) {
context.drawItem(itemStack, this.x + k + 1, this.y + k + 1, 0, 10)
k--
}
context.drawItemWithoutEntity(itemStack, this.x + k, this.y + k)
if (bl) {
context.matrices.pop()
}
}
private val results: List<Recipe<*>>
get() {
val list = this.resultCollection.getRecipes(true)
if (!this.recipeBook.isFilteringCraftable(this.craftingScreenHandler)) {
list.addAll(this.resultCollection.getRecipes(false))
}
return list
}
fun hasResults(): Boolean {
return this.results.size == 1
}
fun currentRecipe(): Recipe<*> {
return this.results[this.currentResultIndex]
}
fun getRecipeTooltip(): List<Text> {
val itemStack = this.results[this.currentResultIndex].getOutput(this.resultCollection.registryManager)
val list = Lists.newArrayList(Screen.getTooltipFromItem(MinecraftClient.getInstance(), itemStack))
if (this.resultCollection.getResults(this.recipeBook.isFilteringCraftable(this.craftingScreenHandler)).size > 1) {
list.add(MORE_RECIPES_TEXT)
}
return list
}
override fun appendClickableNarrations(builder: NarrationMessageBuilder) {
val itemStack = this.results[this.currentResultIndex].getOutput(this.resultCollection.registryManager)
builder.put(NarrationPart.TITLE, Text.translatable("narration.recipe", itemStack.name))
if (this.resultCollection.getResults(this.recipeBook.isFilteringCraftable(this.craftingScreenHandler)).size > 1) {
builder.put(NarrationPart.USAGE, Text.translatable("narration.button.usage.hovered"), Text.translatable("narration.recipe.usage.more"))
} else {
builder.put(NarrationPart.USAGE, Text.translatable("narration.button.usage.hovered"))
}
}
override fun getWidth(): Int {
return 25
}
override fun isValidClickButton(button: Int): Boolean {
return button == 0 || button == 1
}
}
@@ -1,61 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.block.Blocks
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.recipe.book.RecipeBookCategory
@Environment(EnvType.CLIENT)
enum class CookBookGroup(vararg entries: ItemStack) {
CRAFTING_SEARCH(ItemStack(Items.COMPASS)),
CRAFTING_BUILDING_BLOCKS(ItemStack(Blocks.BRICKS)),
CRAFTING_REDSTONE(ItemStack(Items.REDSTONE)),
CRAFTING_EQUIPMENT(ItemStack(Items.IRON_AXE), ItemStack(Items.GOLDEN_SWORD)),
CRAFTING_MISC(ItemStack(Items.LAVA_BUCKET), ItemStack(Items.APPLE)),
FURNACE_SEARCH(ItemStack(Items.COMPASS)),
FURNACE_FOOD(ItemStack(Items.PORKCHOP)),
FURNACE_BLOCKS(ItemStack(Blocks.STONE)),
FURNACE_MISC(ItemStack(Items.LAVA_BUCKET), ItemStack(Items.EMERALD)),
BLAST_FURNACE_SEARCH(ItemStack(Items.COMPASS)),
BLAST_FURNACE_BLOCKS(ItemStack(Blocks.REDSTONE_ORE)),
BLAST_FURNACE_MISC(ItemStack(Items.IRON_SHOVEL), ItemStack(Items.GOLDEN_LEGGINGS)),
SMOKER_SEARCH(ItemStack(Items.COMPASS)),
SMOKER_FOOD(ItemStack(Items.PORKCHOP)),
STONECUTTER(ItemStack(Items.CHISELED_STONE_BRICKS)),
SMITHING(ItemStack(Items.NETHERITE_CHESTPLATE)),
CAMPFIRE(ItemStack(Items.PORKCHOP)),
UNKNOWN(ItemStack(Items.BARRIER));
val icons: List<ItemStack> = ImmutableList.copyOf(entries)
companion object {
val SMOKER: List<CookBookGroup> = ImmutableList.of(SMOKER_SEARCH, SMOKER_FOOD)
val BLAST_FURNACE: List<CookBookGroup> = ImmutableList.of(BLAST_FURNACE_SEARCH, BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC)
val FURNACE: List<CookBookGroup> = ImmutableList.of(FURNACE_SEARCH, FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC)
val CRAFTING: List<CookBookGroup> = ImmutableList.of(CRAFTING_SEARCH, CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE)
val SEARCH_MAP: Map<CookBookGroup, List<CookBookGroup>> = ImmutableMap.of(
CRAFTING_SEARCH, ImmutableList.of(CRAFTING_EQUIPMENT, CRAFTING_BUILDING_BLOCKS, CRAFTING_MISC, CRAFTING_REDSTONE),
FURNACE_SEARCH, ImmutableList.of(FURNACE_FOOD, FURNACE_BLOCKS, FURNACE_MISC),
BLAST_FURNACE_SEARCH, ImmutableList.of(BLAST_FURNACE_BLOCKS, BLAST_FURNACE_MISC),
SMOKER_SEARCH, ImmutableList.of(SMOKER_FOOD)
)
fun getGroups(category: RecipeBookCategory): List<CookBookGroup> {
return when (category) {
RecipeBookCategory.CRAFTING -> CRAFTING
RecipeBookCategory.FURNACE -> FURNACE
RecipeBookCategory.BLAST_FURNACE -> BLAST_FURNACE
RecipeBookCategory.SMOKER -> SMOKER
else -> throw IncompatibleClassChangeError()
}
}
}
fun getIconsValue(): List<ItemStack> {
return this.icons
}
}
@@ -1,12 +0,0 @@
package com.cobblemon.mod.common.gui.cooking;
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget
@Environment(EnvType.CLIENT)
interface CookBookProvider {
fun refreshCookBook()
fun getCookBookWidget(): CookBookWidget
}
@@ -1,193 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.recipebook.AnimatedResultButton
import net.minecraft.client.gui.screen.recipebook.RecipeAlternativesWidget
import net.minecraft.client.gui.screen.recipebook.RecipeDisplayListener
import net.minecraft.client.gui.screen.recipebook.RecipeResultCollection
import net.minecraft.client.gui.widget.ClickableWidget
import net.minecraft.client.gui.widget.ToggleButtonWidget
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.book.RecipeBook
import org.jetbrains.annotations.Nullable
import java.util.function.Consumer
@Environment(EnvType.CLIENT)
class CookBookResults {
val resultButtons = Lists.newArrayListWithCapacity<CookBookAnimatedResultButton>(20)
@Nullable
var hoveredResultButton: CookBookAnimatedResultButton? = null
val alternatesWidget = RecipeAlternativesWidget()
lateinit var client: MinecraftClient
val recipeDisplayListeners = Lists.newArrayList<RecipeDisplayListener>()
var resultCollections = ImmutableList.of<RecipeResultCollection>()
lateinit var nextPageButton: ToggleButtonWidget
lateinit var prevPageButton: ToggleButtonWidget
var pageCount = 0
var currentPage = 0
lateinit var recipeBook: RecipeBook
@Nullable
var lastClickedRecipe: Recipe<*>? = null
@Nullable
var resultCollection: RecipeResultCollection? = null
init {
for (i in 0 until 20) {
resultButtons.add(CookBookAnimatedResultButton())
/*resultButtons.add(CookBookAnimatedResultButton().apply {
// Initialize resultCollection with a default or dummy value if possible
this.resultCollection = RecipeResultCollection()
})*/
}
}
fun initialize(client: MinecraftClient, parentLeft: Int, parentTop: Int) {
this.client = client
this.recipeBook = client.player?.recipeBook ?: return
for (i in resultButtons.indices) {
resultButtons[i].setPosition(parentLeft + 11 + 25 * (i % 5), parentTop + 31 + 25 * (i / 5))
}
nextPageButton = ToggleButtonWidget(parentLeft + 93, parentTop + 137, 12, 17, false)
nextPageButton.setTextureUV(1, 208, 13, 18, CookBookWidget.TEXTURE)
prevPageButton = ToggleButtonWidget(parentLeft + 38, parentTop + 137, 12, 17, true)
prevPageButton.setTextureUV(1, 208, 13, 18, CookBookWidget.TEXTURE)
}
fun setGui(widget: CookBookWidget) {
recipeDisplayListeners.remove(widget)
recipeDisplayListeners.add(widget)
}
fun setResults(resultCollections: List<RecipeResultCollection>, resetCurrentPage: Boolean) {
this.resultCollections = ImmutableList.copyOf(resultCollections)
this.pageCount = Math.ceil(resultCollections.size / 20.0).toInt()
if (this.pageCount <= this.currentPage || resetCurrentPage) {
this.currentPage = 0
}
refreshResultButtons()
}
fun refreshResultButtons() {
val i = 20 * this.currentPage
for (j in resultButtons.indices) {
val animatedResultButton = resultButtons[j]
if (i + j < resultCollections.size) {
val recipeResultCollection = resultCollections[i + j]
animatedResultButton.showResultCollection(recipeResultCollection, this)
animatedResultButton.visible = true
} else {
animatedResultButton.visible = false
}
}
hideShowPageButtons()
}
fun hideShowPageButtons() {
nextPageButton.visible = pageCount > 1 && currentPage < pageCount - 1
prevPageButton.visible = pageCount > 1 && currentPage > 0
}
fun draw(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int, delta: Float) {
if (pageCount > 1) {
val string = "${currentPage + 1}/$pageCount"
val i = client.textRenderer.getWidth(string)
context.drawText(client.textRenderer, string, x - i / 2 + 73, y + 141, -1, false)
}
hoveredResultButton = null
for (animatedResultButton in resultButtons) {
animatedResultButton.render(context, mouseX, mouseY, delta)
if (animatedResultButton.visible && animatedResultButton.isSelected()) {
hoveredResultButton = animatedResultButton
}
}
prevPageButton.render(context, mouseX, mouseY, delta)
nextPageButton.render(context, mouseX, mouseY, delta)
alternatesWidget.render(context, mouseX, mouseY, delta)
}
fun drawTooltip(context: DrawContext, x: Int, y: Int) {
if (client.currentScreen != null && hoveredResultButton != null && !alternatesWidget.isVisible()) {
context.drawTooltip(client.textRenderer, hoveredResultButton!!.getRecipeTooltip(), x, y)
}
}
@Nullable
fun getLastClickedRecipeValue(): Recipe<*>? {
return lastClickedRecipe
}
@Nullable
fun getLastClickedResults(): RecipeResultCollection? {
return resultCollection
}
fun hideAlternates() {
alternatesWidget.isVisible = false
}
fun mouseClicked(mouseX: Double, mouseY: Double, button: Int, areaLeft: Int, areaTop: Int, areaWidth: Int, areaHeight: Int): Boolean {
lastClickedRecipe = null
resultCollection = null
if (alternatesWidget.isVisible()) {
if (alternatesWidget.mouseClicked(mouseX, mouseY, button)) {
lastClickedRecipe = alternatesWidget.getLastClickedRecipe()
resultCollection = alternatesWidget.getResults()
} else {
alternatesWidget.isVisible = false
}
return true
} else if (nextPageButton.mouseClicked(mouseX, mouseY, button)) {
currentPage++
refreshResultButtons()
return true
} else if (prevPageButton.mouseClicked(mouseX, mouseY, button)) {
currentPage--
refreshResultButtons()
return true
} else {
for (animatedResultButton in resultButtons) {
if (animatedResultButton.mouseClicked(mouseX, mouseY, button)) {
if (button == 0) {
lastClickedRecipe = animatedResultButton.currentRecipe()
resultCollection = animatedResultButton.getResultCollectionValue()
} else if (button == 1 && !alternatesWidget.isVisible() && !animatedResultButton.hasResults()) {
alternatesWidget.showAlternativesForResult(client, animatedResultButton.getResultCollectionValue(), animatedResultButton.x, animatedResultButton.y, areaLeft + areaWidth / 2, areaTop + 13 + areaHeight / 2, animatedResultButton.width.toFloat())
}
return true
}
}
}
return false
}
fun onRecipesDisplayed(recipes: List<Recipe<*>>) {
for (recipeDisplayListener in recipeDisplayListeners) {
recipeDisplayListener.onRecipesDisplayed(recipes)
}
}
fun getClientValue(): MinecraftClient {
return client
}
fun getCookBookValue(): RecipeBook {
return recipeBook
}
fun forEachButton(consumer: Consumer<ClickableWidget>) {
consumer.accept(nextPageButton)
consumer.accept(prevPageButton)
resultButtons.forEach(consumer)
}
companion object {
const val field_32411 = 20
}
}
@@ -1,499 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.google.common.collect.Lists
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectSet
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.font.TextRenderer
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.Drawable
import net.minecraft.client.gui.Element
import net.minecraft.client.gui.Selectable
import net.minecraft.client.gui.Selectable.SelectionType
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder
import net.minecraft.client.gui.screen.recipebook.RecipeBookGhostSlots
import net.minecraft.client.gui.screen.recipebook.RecipeDisplayListener
import net.minecraft.client.gui.screen.recipebook.RecipeGroupButtonWidget
import net.minecraft.client.gui.tooltip.Tooltip
import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.gui.widget.ToggleButtonWidget
import net.minecraft.client.recipebook.ClientRecipeBook
import net.minecraft.client.recipebook.RecipeBookGroup
import net.minecraft.client.resource.language.LanguageDefinition
import net.minecraft.client.resource.language.LanguageManager
import net.minecraft.client.search.SearchManager
import net.minecraft.item.ItemStack
import net.minecraft.network.packet.c2s.play.RecipeCategoryOptionsC2SPacket
import net.minecraft.recipe.Ingredient
import net.minecraft.recipe.Recipe
import net.minecraft.recipe.RecipeGridAligner
import net.minecraft.recipe.RecipeMatcher
import net.minecraft.recipe.book.RecipeBookCategory
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.screen.slot.Slot
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import net.minecraft.util.Identifier
import org.jetbrains.annotations.Nullable
import java.util.*
@Environment(EnvType.CLIENT)
class CookBookWidget : RecipeGridAligner<Ingredient>, Drawable, Element, Selectable, RecipeDisplayListener {
//val SEARCH_HINT_TEXT: Text
val field_32408 = 147
val field_32409 = 166
val field_32410 = 86
//val TOGGLE_CRAFTABLE_RECIPES_TEXT: Text
//val TOGGLE_ALL_RECIPES_TEXT: Text
var leftOffset = 0
var parentWidth = 0
var parentHeight = 0
val ghostSlots = RecipeBookGhostSlots()
val tabButtons: ArrayList<CookingRecipeGroupButtonWidget> = Lists.newArrayList<CookingRecipeGroupButtonWidget>()
@Nullable
var currentTab: CookingRecipeGroupButtonWidget? = null
lateinit var toggleCraftableButton: ToggleButtonWidget
lateinit var craftingScreenHandler: AbstractRecipeScreenHandler<*>
lateinit var client: MinecraftClient
@Nullable
var searchField: TextFieldWidget? = null
var searchText = ""
lateinit var recipeBook: ClientRecipeBook
val recipesArea = CookBookResults()
val recipeFinder = RecipeMatcher()
var cachedInvChangeCount = 0
var searching = false
var open = false
var narrow = false
fun initialize(parentWidth: Int, parentHeight: Int, client: MinecraftClient?, narrow: Boolean, craftingScreenHandler: AbstractRecipeScreenHandler<*>) {
if (client != null) {
this.client = client
}
this.parentWidth = parentWidth
this.parentHeight = parentHeight
this.craftingScreenHandler = craftingScreenHandler
this.narrow = narrow
client?.player?.currentScreenHandler = craftingScreenHandler
this.recipeBook = client?.player?.recipeBook ?: return
this.cachedInvChangeCount = client?.player?.inventory?.changeCount ?: 0
this.open = isGuiOpen()
if (this.open) {
reset()
}
}
fun reset() {
leftOffset = if (narrow) 0 else 86
val i = (parentWidth - 147) / 2 - leftOffset
val j = (parentHeight - 166) / 2
recipeFinder.clear()
client.player?.inventory?.populateRecipeFinder(recipeFinder)
craftingScreenHandler.populateRecipeFinder(recipeFinder)
val string = searchField?.text ?: ""
val var10003 = client.textRenderer
val var10004 = i + 26
val var10005 = j + 14
Objects.requireNonNull(client.textRenderer)
searchField = TextFieldWidget(var10003, var10004, var10005, 79, 9 + 3, Text.translatable("itemGroup.search"))
searchField?.setMaxLength(50)
searchField?.isVisible = true
searchField?.setEditableColor(16777215)
searchField?.text = string
searchField?.setPlaceholder(SEARCH_HINT_TEXT)
recipesArea.initialize(client, i, j)
recipesArea.setGui(this)
toggleCraftableButton = ToggleButtonWidget(i + 110, j + 12, 26, 16, recipeBook.isFilteringCraftable(craftingScreenHandler))
updateTooltip()
setBookButtonTexture()
tabButtons.clear()
val var4 = RecipeBookGroup.getGroups(craftingScreenHandler.category).iterator()
while (var4.hasNext()) {
val recipeBookGroup = var4.next() as RecipeBookGroup
tabButtons.add(CookingRecipeGroupButtonWidget(recipeBookGroup))
}
if (currentTab != null) {
currentTab = tabButtons.stream().filter { button ->
button.category == currentTab?.getCategoryValue()
}.findFirst().orElse(null)
}
if (currentTab == null) {
currentTab = tabButtons[0]
}
currentTab?.setToggled(true)
refreshResults(false)
refreshTabButtons()
}
private fun updateTooltip() {
toggleCraftableButton.setTooltip(if (toggleCraftableButton.isToggled) Tooltip.of(getToggleCraftableButtonText()) else Tooltip.of(TOGGLE_ALL_RECIPES_TEXT))
}
fun setBookButtonTexture() {
toggleCraftableButton.setTextureUV(152, 41, 28, 18, TEXTURE)
}
fun findLeftEdge(width: Int, backgroundWidth: Int): Int {
return if (isOpen() && !narrow) {
177 + (width - backgroundWidth - 200) / 2
} else {
(width - backgroundWidth) / 2
}
}
fun toggleOpen() {
setOpenValue(!isOpen())
}
fun isOpen(): Boolean {
return open
}
fun isGuiOpen(): Boolean {
return recipeBook.isGuiOpen(craftingScreenHandler.category)
}
fun setOpenValue(opened: Boolean) {
if (opened) {
reset()
}
open = opened
recipeBook.setGuiOpen(craftingScreenHandler.category, opened)
if (!opened) {
recipesArea.hideAlternates()
}
sendBookDataPacket()
}
fun slotClicked(@Nullable slot: Slot?) {
if (slot != null && slot.id < craftingScreenHandler.craftingSlotCount) {
ghostSlots.reset()
if (isOpen()) {
refreshInputs()
}
}
}
fun refreshResults(resetCurrentPage: Boolean) {
val list = recipeBook.getResultsForGroup(currentTab?.category ?: return)
list.forEach { resultCollection ->
resultCollection.computeCraftables(recipeFinder, craftingScreenHandler.craftingWidth, craftingScreenHandler.craftingHeight, recipeBook)
}
val list2 = Lists.newArrayList(list)
list2.removeIf { !it.isInitialized }
list2.removeIf { !it.hasFittingRecipes() }
val string = searchField?.text ?: ""
if (string.isNotEmpty()) {
val objectSet = ObjectLinkedOpenHashSet(client.getSearchProvider(SearchManager.RECIPE_OUTPUT).findAll(string.lowercase(Locale.ROOT)))
list2.removeIf { !objectSet.contains(it) }
}
if (recipeBook.isFilteringCraftable(craftingScreenHandler)) {
list2.removeIf { !it.hasCraftableRecipes() }
}
recipesArea.setResults(list2, resetCurrentPage)
}
fun refreshTabButtons() {
val i = (parentWidth - 147) / 2 - leftOffset - 30
val j = (parentHeight - 166) / 2 + 3
var l = 0
val var5 = tabButtons.iterator()
while (true) {
while (var5.hasNext()) {
val recipeGroupButtonWidget = var5.next()
val recipeBookGroup = recipeGroupButtonWidget.category
if (recipeBookGroup != RecipeBookGroup.CRAFTING_SEARCH && recipeBookGroup != RecipeBookGroup.FURNACE_SEARCH) {
if (recipeGroupButtonWidget.hasKnownRecipes(recipeBook)) {
recipeGroupButtonWidget.setPosition(i, j + 27 * l++)
recipeGroupButtonWidget.checkForNewRecipes(client)
}
} else {
recipeGroupButtonWidget.visible = true
recipeGroupButtonWidget.setPosition(i, j + 27 * l++)
}
}
return
}
}
fun update() {
val bl = isGuiOpen()
if (isOpen() != bl) {
setOpenValue(bl)
}
if (isOpen()) {
if (cachedInvChangeCount != client.player?.inventory?.changeCount) {
refreshInputs()
cachedInvChangeCount = client.player?.inventory?.changeCount ?: 0
}
searchField?.tick()
}
}
fun refreshInputs() {
recipeFinder.clear()
client.player?.inventory?.populateRecipeFinder(recipeFinder)
craftingScreenHandler.populateRecipeFinder(recipeFinder)
refreshResults(false)
}
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
if (isOpen()) {
context.matrices.push()
context.matrices.translate(0.0F, 0.0F, 100.0F)
val i = (parentWidth - 147) / 2 - leftOffset
val j = (parentHeight - 166) / 2
context.drawTexture(TEXTURE, i, j, 1, 1, 147, 166)
searchField?.render(context, mouseX, mouseY, delta)
for (recipeGroupButtonWidget in tabButtons) {
recipeGroupButtonWidget.render(context, mouseX, mouseY, delta)
}
toggleCraftableButton.render(context, mouseX, mouseY, delta)
recipesArea.draw(context, i, j, mouseX, mouseY, delta)
context.matrices.pop()
}
}
fun drawTooltip(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int) {
if (isOpen()) {
recipesArea.drawTooltip(context, mouseX, mouseY)
drawGhostSlotTooltip(context, x, y, mouseX, mouseY)
}
}
fun getToggleCraftableButtonText(): Text {
return TOGGLE_CRAFTABLE_RECIPES_TEXT
}
fun drawGhostSlotTooltip(context: DrawContext, x: Int, y: Int, mouseX: Int, mouseY: Int) {
var itemStack: ItemStack? = null
for (i in 0 until ghostSlots.slotCount) {
val ghostInputSlot = ghostSlots.getSlot(i)
val j = ghostInputSlot.x + x
val k = ghostInputSlot.y + y
if (mouseX >= j && mouseY >= k && mouseX < j + 16 && mouseY < k + 16) {
itemStack = ghostInputSlot.currentItemStack
}
}
if (itemStack != null && client.currentScreen != null) {
context.drawTooltip(client.textRenderer, Screen.getTooltipFromItem(client, itemStack), mouseX, mouseY)
}
}
fun drawGhostSlots(context: DrawContext, x: Int, y: Int, notInventory: Boolean, delta: Float) {
ghostSlots.draw(context, client, x, y, notInventory, delta)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (isOpen() && !client.player?.isSpectator()!!) {
if (recipesArea.mouseClicked(mouseX, mouseY, button, (parentWidth - 147) / 2 - leftOffset, (parentHeight - 166) / 2, 147, 166)) {
val recipe = recipesArea.getLastClickedRecipeValue()
val recipeResultCollection = recipesArea.getLastClickedResults()
if (recipe != null && recipeResultCollection != null) {
if (!recipeResultCollection.isCraftable(recipe) && ghostSlots.recipe == recipe) {
return false
}
ghostSlots.reset()
client.interactionManager?.clickRecipe(client.player?.currentScreenHandler?.syncId ?: 0, recipe, Screen.hasShiftDown())
if (!isWide()) {
setOpenValue(false)
}
}
return true
} else if (searchField?.mouseClicked(mouseX, mouseY, button) == true) {
searchField?.setFocused(true)
return true
} else {
searchField?.setFocused(false)
if (toggleCraftableButton.mouseClicked(mouseX, mouseY, button)) {
val bl = toggleFilteringCraftable()
toggleCraftableButton.setToggled(bl)
updateTooltip()
sendBookDataPacket()
refreshResults(false)
return true
} else {
for (recipeGroupButtonWidget in tabButtons) {
if (recipeGroupButtonWidget.mouseClicked(mouseX, mouseY, button)) {
if (currentTab != recipeGroupButtonWidget) {
currentTab?.setToggled(false)
currentTab = recipeGroupButtonWidget
currentTab?.setToggled(true)
refreshResults(true)
}
return true
}
}
}
}
} else {
return false
}
return false
}
private fun toggleFilteringCraftable(): Boolean {
val recipeBookCategory = craftingScreenHandler.category
val bl = !recipeBook.isFilteringCraftable(recipeBookCategory)
recipeBook.setFilteringCraftable(recipeBookCategory, bl)
return bl
}
fun isClickOutsideBounds(mouseX: Double, mouseY: Double, x: Int, y: Int, backgroundWidth: Int, backgroundHeight: Int, button: Int): Boolean {
return if (!isOpen()) {
true
} else {
val bl = mouseX < x.toDouble() || mouseY < y.toDouble() || mouseX >= (x + backgroundWidth).toDouble() || mouseY >= (y + backgroundHeight).toDouble()
val bl2 = (x - 147).toDouble() < mouseX && mouseX < x.toDouble() && y.toDouble() < mouseY && mouseY < (y + backgroundHeight).toDouble()
bl && !bl2 && !currentTab?.isSelected()!!
}
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
searching = false
if (isOpen() && !client.player?.isSpectator()!!) {
return if (keyCode == 256 && !isWide()) {
setOpenValue(false)
true
} else if (searchField?.keyPressed(keyCode, scanCode, modifiers) == true) {
refreshSearchResults()
true
} else if (searchField?.isFocused == true && searchField?.isVisible == true && keyCode != 256) {
true
} else if (client.options.chatKey.matchesKey(keyCode, scanCode) && searchField?.isFocused == false) {
searching = true
searchField?.setFocused(true)
true
} else {
false
}
} else {
false
}
return false
}
override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
searching = false
return super.keyReleased(keyCode, scanCode, modifiers)
}
override fun charTyped(chr: Char, modifiers: Int): Boolean {
return if (searching) {
false
} else if (isOpen() && !client.player?.isSpectator()!!) {
if (searchField?.charTyped(chr, modifiers) == true) {
refreshSearchResults()
true
} else {
super.charTyped(chr, modifiers)
}
} else {
false
}
}
override fun isMouseOver(mouseX: Double, mouseY: Double): Boolean {
return false
}
override fun setFocused(focused: Boolean) {}
override fun isFocused(): Boolean {
return false
}
fun refreshSearchResults() {
val string = searchField?.text?.lowercase(Locale.ROOT) ?: ""
triggerPirateSpeakEasterEgg(string)
if (string != searchText) {
refreshResults(false)
searchText = string
}
}
fun triggerPirateSpeakEasterEgg(search: String) {
if ("excitedze" == search) {
val languageManager = client.languageManager
val string = "en_pt"
val languageDefinition = languageManager.getLanguage("en_pt")
if (languageDefinition == null || languageManager.language == "en_pt") {
return
}
languageManager.language = "en_pt"
client.options.language = "en_pt"
client.reloadResources()
client.options.write()
}
}
fun isWide(): Boolean {
return leftOffset == 86
}
fun refresh() {
refreshTabButtons()
if (isOpen()) {
refreshResults(false)
}
}
override fun onRecipesDisplayed(recipes: List<Recipe<*>>) {
for (recipe in recipes) {
client.player?.onRecipeDisplayed(recipe)
}
}
fun showGhostRecipe(recipe: Recipe<*>, slots: List<Slot>) {
val itemStack = recipe.getOutput(client.world?.registryManager)
ghostSlots.setRecipe(recipe)
ghostSlots.addSlot(Ingredient.ofStacks(itemStack), slots[0].x, slots[0].y)
alignRecipeToGrid(craftingScreenHandler.craftingWidth, craftingScreenHandler.craftingHeight, craftingScreenHandler.craftingResultSlotIndex, recipe, recipe.ingredients.iterator(), 0)
}
override fun acceptAlignedInput(inputs: Iterator<Ingredient>, slot: Int, amount: Int, gridX: Int, gridY: Int) {
val ingredient = inputs.next()
if (!ingredient.isEmpty) {
val slot2 = craftingScreenHandler.slots[slot]
ghostSlots.addSlot(ingredient, slot2.x, slot2.y)
}
}
fun sendBookDataPacket() {
if (client.networkHandler != null) {
val recipeBookCategory = craftingScreenHandler.category
val bl = recipeBook.options.isGuiOpen(recipeBookCategory)
val bl2 = recipeBook.options.isFilteringCraftable(recipeBookCategory)
client.networkHandler?.sendPacket(RecipeCategoryOptionsC2SPacket(recipeBookCategory, bl, bl2))
}
}
override fun getType(): SelectionType {
return if (open) SelectionType.HOVERED else SelectionType.NONE
}
override fun appendNarrations(builder: NarrationMessageBuilder) {
val list = Lists.newArrayList<Selectable>()
recipesArea.forEachButton { button ->
if (button.isNarratable) {
list.add(button)
}
}
searchField?.let { list.add(it) } // not sure if this is the right way
list.add(toggleCraftableButton)
list.addAll(tabButtons)
val selectedElementNarrationData = Screen.findSelectedElementData(list, null)
selectedElementNarrationData?.selectable?.appendNarrations(builder.nextMessage())
}
companion object {
val TEXTURE = Identifier("textures/gui/recipe_book.png")
val SEARCH_HINT_TEXT: Text = Text.translatable("gui.recipebook.search_hint").formatted(Formatting.ITALIC).formatted(Formatting.GRAY)
val TOGGLE_CRAFTABLE_RECIPES_TEXT: Text = Text.translatable("gui.recipebook.toggleRecipes.craftable")
val TOGGLE_ALL_RECIPES_TEXT: Text = Text.translatable("gui.recipebook.toggleRecipes.all")
}
}
@@ -1,125 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.gui.CookingPotScreenHandler
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget
import net.minecraft.client.gui.widget.TexturedButtonWidget
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.screen.AbstractRecipeScreenHandler
import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class CookingPotHandledScreen(
handler: CookingPotScreenHandler,
inventory: PlayerInventory,
title: Text?
) : HandledScreen<CookingPotScreenHandler>(handler, inventory, title), CookBookProvider {
private val recipeBook = CookBookWidget()
private var narrow = false
companion object {
//private val TEXTURE = Identifier("textures/gui/container/crafting_table.png")
val TEXTURE = cobblemonResource("textures/gui/cooking/cooking_pot.png")
private val RECIPE_BUTTON_TEXTURE = Identifier("textures/gui/recipe_button.png")
val TEXTURE_HEIGHT = 198
val TEXTURE_WIDTH = 176
}
override fun init() {
super.init()
narrow = width < 379
val recipeBookOffsetX = 12
val recipeBookOffsetY = 40
recipeBook.initialize(width, height, client, narrow, handler as AbstractRecipeScreenHandler<*>)
x = recipeBook.findLeftEdge(width, TEXTURE_WIDTH)
addDrawableChild(
TexturedButtonWidget(x + recipeBookOffsetX, height / 2 - recipeBookOffsetY, 20, 18, 0, 0, 19, RECIPE_BUTTON_TEXTURE) {
recipeBook.toggleOpen()
x = recipeBook.findLeftEdge(width, TEXTURE_WIDTH)
it.setPosition(x + recipeBookOffsetX, height / 2 - recipeBookOffsetY)
}
)
addSelectableChild(recipeBook)
setInitialFocus(recipeBook)
titleX = 39
titleY = -10
playerInventoryTitleX = 8
playerInventoryTitleY = 88
}
override fun handledScreenTick() {
super.handledScreenTick()
recipeBook.update()
}
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
renderBackground(context)
if (recipeBook.isOpen() && narrow) {
drawBackground(context, delta, mouseX, mouseY)
recipeBook.render(context, mouseX, mouseY, delta)
} else {
recipeBook.render(context, mouseX, mouseY, delta)
super.render(context, mouseX, mouseY, delta)
recipeBook.drawGhostSlots(context, x, y, true, delta)
}
drawMouseoverTooltip(context, mouseX, mouseY)
recipeBook.drawTooltip(context, x, y, mouseX, mouseY)
}
override fun drawBackground(context: DrawContext, delta: Float, mouseX: Int, mouseY: Int) {
val i = x
val j = (height - TEXTURE_HEIGHT) / 2
blitk(
matrixStack = context.matrices,
texture = TEXTURE,
x = x, // horizontal placement of GUI
y = (height - TEXTURE_HEIGHT) / 2, // vertical placement of GUI
width = TEXTURE_WIDTH * 1.0, // scale of the GUI width
height = TEXTURE_HEIGHT * 1.0 // scale of the GUI height
)
//context.drawTexture(TEXTURE, i, j, 0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT)
}
override fun isPointWithinBounds(x: Int, y: Int, width: Int, height: Int, pointX: Double, pointY: Double): Boolean {
return (!narrow || !recipeBook.isOpen()) && super.isPointWithinBounds(x, y, width, height, pointX, pointY)
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (recipeBook.mouseClicked(mouseX, mouseY, button)) {
focused = recipeBook
return true
}
return if (narrow && recipeBook.isOpen()) {
true
} else super.mouseClicked(mouseX, mouseY, button)
}
override fun isClickOutsideBounds(mouseX: Double, mouseY: Double, left: Int, top: Int, button: Int): Boolean {
val bl = mouseX < left.toDouble() || mouseY < top.toDouble() || mouseX >= (left + backgroundWidth).toDouble() || mouseY >= (top + backgroundHeight).toDouble()
return recipeBook.isClickOutsideBounds(mouseX, mouseY, x, y, backgroundWidth, backgroundHeight, button) && bl
}
override fun onMouseClick(slot: Slot?, slotId: Int, button: Int, actionType: SlotActionType?) {
super.onMouseClick(slot, slotId, button, actionType)
recipeBook.slotClicked(slot)
}
override fun refreshCookBook() {
recipeBook.refresh()
}
override fun getCookBookWidget(): CookBookWidget {
return recipeBook
}
}
@@ -1,102 +0,0 @@
package com.cobblemon.mod.common.gui.cooking
import com.mojang.blaze3d.systems.RenderSystem
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget
import net.minecraft.client.gui.widget.ToggleButtonWidget
import net.minecraft.client.recipebook.ClientRecipeBook
import net.minecraft.client.recipebook.RecipeBookGroup
import net.minecraft.client.render.item.ItemRenderer
import net.minecraft.item.ItemStack
import net.minecraft.recipe.Recipe
import net.minecraft.screen.AbstractRecipeScreenHandler
@Environment(EnvType.CLIENT)
class CookingRecipeGroupButtonWidget(val category: RecipeBookGroup) : ToggleButtonWidget(0, 0, 35, 27, false) {
private var bounce = 0f
init {
setTextureUV(153, 2, 35, 0, CookBookWidget.TEXTURE)
}
fun checkForNewRecipes(client: MinecraftClient) {
val clientRecipeBook = client.player?.recipeBook ?: return
val list = clientRecipeBook.getResultsForGroup(this.category)
if (client.player?.currentScreenHandler is AbstractRecipeScreenHandler<*>) {
for (recipeResultCollection in list) {
for (recipe in recipeResultCollection.getResults(clientRecipeBook.isFilteringCraftable(client.player!!.currentScreenHandler as AbstractRecipeScreenHandler<*>))) {
if (clientRecipeBook.shouldDisplay(recipe)) {
this.bounce = 15.0f
return
}
}
}
}
}
override fun renderButton(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
if (this.bounce > 0.0f) {
val f = 1.0f + 0.1f * Math.sin((this.bounce / 15.0f * Math.PI).toDouble()).toFloat()
context.matrices.push()
context.matrices.translate((this.x + 8).toFloat(), (this.y + 12).toFloat(), 0.0f)
context.matrices.scale(1.0f, f, 1.0f)
context.matrices.translate(-(this.x + 8).toFloat(), -(this.y + 12).toFloat(), 0.0f)
}
val minecraftClient = MinecraftClient.getInstance()
RenderSystem.disableDepthTest()
var i = this.u
var j = this.v
if (this.toggled) {
i += this.pressedUOffset
}
if (this.isSelected) {
j += this.hoverVOffset
}
var k = this.x
if (this.toggled) {
k -= 2
}
context.drawTexture(this.texture, k, this.y, i, j, this.width, this.height)
RenderSystem.enableDepthTest()
this.renderIcons(context, minecraftClient.itemRenderer)
if (this.bounce > 0.0f) {
context.matrices.pop()
this.bounce -= delta
}
}
private fun renderIcons(context: DrawContext, itemRenderer: ItemRenderer) {
val list = this.category.getIcons()
val i = if (this.toggled) -2 else 0
if (list.size == 1) {
context.drawItemWithoutEntity(list[0], this.x + 9 + i, this.y + 5)
} else if (list.size == 2) {
context.drawItemWithoutEntity(list[0], this.x + 3 + i, this.y + 5)
context.drawItemWithoutEntity(list[1], this.x + 14 + i, this.y + 5)
}
}
fun getCategoryValue(): RecipeBookGroup {
return this.category
}
fun hasKnownRecipes(recipeBook: ClientRecipeBook): Boolean {
val list = recipeBook.getResultsForGroup(this.category)
this.visible = false
if (list != null) {
for (recipeResultCollection in list) {
if (recipeResultCollection.isInitialized && recipeResultCollection.hasFittingRecipes()) {
this.visible = true
break
}
}
}
return this.visible
}
}
@@ -10,9 +10,10 @@ package com.cobblemon.mod.common.integration.jei.berry
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.integration.jei.CobblemonJeiProvider
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.item.BerryItem
import mezz.jei.api.registration.IRecipeCategoryRegistration
import mezz.jei.api.registration.IRecipeRegistration
import net.minecraft.item.ItemStack
class BerryMutationProvider : CobblemonJeiProvider {
override fun registerCategory(registration: IRecipeCategoryRegistration) {
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.integration.jei.berry
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.item.BerryItem
//Dont make these ItemStacks, they do not have consistent hash codes, breaks stuff
data class BerryMutationRecipe(
@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item.berry
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.block.BerryBlock
import net.minecraft.item.AliasedBlockItem
@@ -1,24 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.block.BugwortBlock
import com.cobblemon.mod.common.block.SaccharineSaplingBlock
import net.minecraft.block.BlockState
import net.minecraft.item.AliasedBlockItem
import net.minecraft.item.ItemPlacementContext
class BugwortItem(block: BugwortBlock) : AliasedBlockItem(block, Settings()) {
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
return super.getPlacementState(context)
}
}
@@ -1,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.block.SaccharineSaplingBlock
import net.minecraft.block.BlockState
import net.minecraft.item.AliasedBlockItem
import net.minecraft.item.ItemPlacementContext
class SaccharineSaplingItem(block: SaccharineSaplingBlock) : AliasedBlockItem(block, Settings()) {
override fun getPlacementState(context: ItemPlacementContext): BlockState? {
return super.getPlacementState(context)
}
}
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.entity.throwable.ScatterBangEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.thrown.SnowballEntity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
class ScatterBangItem(settings: Settings?) : Item(settings) {
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
world.playSound(
null as PlayerEntity?,
user.x,
user.y,
user.z,
SoundEvents.ENTITY_SNOWBALL_THROW,
SoundCategory.NEUTRAL,
0.5f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
if (!world.isClient) {
val scatterBangEntity = ScatterBangEntity(world, user)
scatterBangEntity.setItem(itemStack)
scatterBangEntity.setVelocity(user, user.pitch, user.yaw, 0.0f, 1.5f, 1.0f)
world.spawnEntity(scatterBangEntity)
}
user.incrementStat(Stats.USED.getOrCreateStat(this))
if (!user.abilities.creativeMode) {
itemStack.decrement(1)
}
return TypedActionResult.success(itemStack, world.isClient())
}
}
@@ -1,52 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.item
import com.cobblemon.mod.common.entity.throwable.ScatterBangEntity
import com.cobblemon.mod.common.entity.throwable.StickyGlobEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.projectile.thrown.SnowballEntity
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvents
import net.minecraft.stat.Stats
import net.minecraft.util.Hand
import net.minecraft.util.TypedActionResult
import net.minecraft.world.World
class StickyGlobItem(settings: Settings?) : Item(settings) {
override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> {
val itemStack = user.getStackInHand(hand)
world.playSound(
null as PlayerEntity?,
user.x,
user.y,
user.z,
SoundEvents.ENTITY_SNOWBALL_THROW,
SoundCategory.NEUTRAL,
0.5f,
0.4f / (world.getRandom().nextFloat() * 0.4f + 0.8f)
)
if (!world.isClient) {
val stickyGlobEntity = StickyGlobEntity(world, user)
stickyGlobEntity.setItem(itemStack)
stickyGlobEntity.setVelocity(user, user.pitch, user.yaw, 0.0f, 1.5f, 1.0f)
world.spawnEntity(stickyGlobEntity)
}
user.incrementStat(Stats.USED.getOrCreateStat(this))
if (!user.abilities.creativeMode) {
itemStack.decrement(1)
}
return TypedActionResult.success(itemStack, world.isClient())
}
}
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.pokemon.stats.Stat
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.genericRuntime
import com.cobblemon.mod.common.util.resolveInt
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.genericRuntime
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.api.item.PokemonAndMoveSelectingItem
import com.cobblemon.mod.common.api.moves.Move
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.genericRuntime
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.genericRuntime
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.api.pokemon.status.Status
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.player.PlayerEntity
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.item.PokemonSelectingItem
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.item.BerryItem
import com.cobblemon.mod.common.item.battle.BagItem
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.item.ItemStack
@@ -89,11 +89,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.VIVICHOKE)
entries.add(CobblemonItems.VIVICHOKE_SEEDS)
entries.add(CobblemonItems.SWEET_SAP)
entries.add(CobblemonItems.BUGWORT)
entries.add(CobblemonItems.SCATTER_BANG)
entries.add(CobblemonItems.STICKY_GLOB)
entries.add(CobblemonItems.RED_APRICORN)
entries.add(CobblemonItems.YELLOW_APRICORN)
entries.add(CobblemonItems.GREEN_APRICORN)
@@ -109,8 +104,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.BLACK_APRICORN_SEED)
entries.add(CobblemonItems.WHITE_APRICORN_SEED)
entries.add(CobblemonItems.SACCHARINE_SAPLING)
entries.add(CobblemonItems.RED_MINT_SEEDS)
entries.add(CobblemonItems.RED_MINT_LEAF)
entries.add(CobblemonItems.BLUE_MINT_SEEDS)
@@ -238,8 +231,6 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.RELIC_COIN_POUCH)
entries.add(CobblemonItems.RELIC_COIN_SACK)
entries.add(CobblemonItems.COOKING_POT)
entries.add(CobblemonItems.SWEET_INCENSE)
entries.add(CobblemonItems.DISPLAY_CASE)
entries.add(CobblemonItems.APRICORN_LOG)
entries.add(CobblemonItems.APRICORN_WOOD)
@@ -258,58 +249,10 @@ object CobblemonItemGroups {
entries.add(CobblemonItems.APRICORN_HANGING_SIGN)
entries.add(CobblemonItems.APRICORN_LEAVES)
entries.add(CobblemonItems.SACCHARINE_LOG)
entries.add(CobblemonItems.SACCHARINE_WOOD)
entries.add(CobblemonItems.STRIPPED_SACCHARINE_LOG)
entries.add(CobblemonItems.STRIPPED_SACCHARINE_WOOD)
entries.add(CobblemonItems.SACCHARINE_PLANKS)
entries.add(CobblemonItems.SACCHARINE_STAIRS)
entries.add(CobblemonItems.SACCHARINE_SLAB)
entries.add(CobblemonItems.SACCHARINE_FENCE)
entries.add(CobblemonItems.SACCHARINE_FENCE_GATE)
entries.add(CobblemonItems.SACCHARINE_DOOR)
entries.add(CobblemonItems.SACCHARINE_TRAPDOOR)
entries.add(CobblemonItems.SACCHARINE_BUTTON)
entries.add(CobblemonItems.SACCHARINE_PRESSURE_PLATE)
entries.add(CobblemonItems.SACCHARINE_SIGN)
entries.add(CobblemonItems.SACCHARINE_HANGING_SIGN)
entries.add(CobblemonItems.SACCHARINE_LEAVES)
entries.add(CobblemonItems.TUMBLESTONE_BLOCK)
entries.add(CobblemonItems.BLACK_TUMBLESTONE_BLOCK)
entries.add(CobblemonItems.SKY_TUMBLESTONE_BLOCK)
entries.add(CobblemonItems.POLISHED_TUMBLESTONE)
entries.add(CobblemonItems.POLISHED_TUMBLESTONE_STAIRS)
entries.add(CobblemonItems.POLISHED_TUMBLESTONE_SLAB)
entries.add(CobblemonItems.POLISHED_TUMBLESTONE_WALL)
entries.add(CobblemonItems.CHISELED_POLISHED_TUMBLESTONE)
entries.add(CobblemonItems.TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.TUMBLESTONE_BRICK_STAIRS)
entries.add(CobblemonItems.TUMBLESTONE_BRICK_SLAB)
entries.add(CobblemonItems.TUMBLESTONE_BRICK_WALL)
entries.add(CobblemonItems.CHISELED_TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.POLISHED_BLACK_TUMBLESTONE)
entries.add(CobblemonItems.POLISHED_BLACK_TUMBLESTONE_STAIRS)
entries.add(CobblemonItems.POLISHED_BLACK_TUMBLESTONE_SLAB)
entries.add(CobblemonItems.POLISHED_BLACK_TUMBLESTONE_WALL)
entries.add(CobblemonItems.CHISELED_POLISHED_BLACK_TUMBLESTONE)
entries.add(CobblemonItems.BLACK_TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.BLACK_TUMBLESTONE_BRICK_STAIRS)
entries.add(CobblemonItems.BLACK_TUMBLESTONE_BRICK_SLAB)
entries.add(CobblemonItems.BLACK_TUMBLESTONE_BRICK_WALL)
entries.add(CobblemonItems.CHISELED_BLACK_TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.POLISHED_SKY_TUMBLESTONE)
entries.add(CobblemonItems.POLISHED_SKY_TUMBLESTONE_STAIRS)
entries.add(CobblemonItems.POLISHED_SKY_TUMBLESTONE_SLAB)
entries.add(CobblemonItems.POLISHED_SKY_TUMBLESTONE_WALL)
entries.add(CobblemonItems.CHISELED_POLISHED_SKY_TUMBLESTONE)
entries.add(CobblemonItems.SKY_TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.SKY_TUMBLESTONE_BRICK_STAIRS)
entries.add(CobblemonItems.SKY_TUMBLESTONE_BRICK_SLAB)
entries.add(CobblemonItems.SKY_TUMBLESTONE_BRICK_WALL)
entries.add(CobblemonItems.CHISELED_SKY_TUMBLESTONE_BRICKS)
entries.add(CobblemonItems.DAWN_STONE_ORE)
entries.add(CobblemonItems.DEEPSLATE_DAWN_STONE_ORE)
entries.add(CobblemonItems.DUSK_STONE_ORE)
@@ -31,7 +31,6 @@ import net.minecraft.world.World
open class BlockClickEvolution(
override val id: String,
override val result: PokemonProperties,
override val shedder: PokemonProperties?,
override val requiredContext: RegistryLikeCondition<Block>,
override var optional: Boolean,
override var consumeHeldItem: Boolean,
@@ -41,7 +40,6 @@ open class BlockClickEvolution(
constructor(): this(
id = "id",
result = PokemonProperties(),
shedder = null,
requiredContext = BlockIdentifierCondition(Identifier("minecraft", "dirt")),
optional = true,
consumeHeldItem = true,
@@ -19,7 +19,6 @@ internal class DummyEvolution : Evolution {
override val id = "dummy"
override val result: PokemonProperties = PokemonProperties()
override val shedder: PokemonProperties? = null
override var optional = false
override var consumeHeldItem = false
override val requirements: MutableSet<EvolutionRequirement> = mutableSetOf()
@@ -32,7 +32,6 @@ import net.minecraft.world.World
open class ItemInteractionEvolution(
override val id: String,
override val result: PokemonProperties,
override val shedder: PokemonProperties?,
override val requiredContext: NbtItemPredicate,
override var optional: Boolean,
override var consumeHeldItem: Boolean,
@@ -42,7 +41,6 @@ open class ItemInteractionEvolution(
constructor(): this(
id = "id",
result = PokemonProperties(),
shedder = null,
requiredContext = NbtItemPredicate(ItemIdentifierCondition(Identifier("minecraft", "fish")), NbtPredicate.ANY),
optional = true,
consumeHeldItem = true,
@@ -25,7 +25,6 @@ import com.cobblemon.mod.common.pokemon.Pokemon
open class LevelUpEvolution(
override val id: String,
override val result: PokemonProperties,
override val shedder: PokemonProperties?,
override var optional: Boolean,
override var consumeHeldItem: Boolean,
override val requirements: MutableSet<EvolutionRequirement>,
@@ -37,7 +36,6 @@ open class LevelUpEvolution(
constructor(): this(
id = "id",
result = PokemonProperties(),
shedder = null,
optional = true,
consumeHeldItem = true,
requirements = mutableSetOf(),
@@ -26,7 +26,6 @@ import com.cobblemon.mod.common.pokemon.Pokemon
open class TradeEvolution(
override val id: String,
override val result: PokemonProperties,
override val shedder: PokemonProperties?,
override val requiredContext: PokemonProperties,
override var optional: Boolean,
override var consumeHeldItem: Boolean,
@@ -36,7 +35,6 @@ open class TradeEvolution(
constructor(): this(
id = "id",
result = PokemonProperties(),
shedder = null,
requiredContext = PokemonProperties(),
optional = true,
consumeHeldItem = true,
@@ -30,9 +30,6 @@ object CobblemonConfiguredFeatures {
@JvmField
val YELLOW_APRICORN_TREE_KEY = of("yellow_apricorn_tree")
@JvmField
val SACCHARINE_TREE_KEY = of("saccharine_tree")
@JvmField
val MINTS_KEY = of("mints")
@JvmField
@@ -23,8 +23,6 @@ object CobblemonFeatures : PlatformRegistry<Registry<Feature<*>>, RegistryKey<Re
@JvmField
val APRICORN_TREE_FEATURE = create("apricorn_tree", ApricornTreeFeature())
@JvmField
val SACCHARINE_TREE_FEATURE = create("saccharine_tree", SaccharineTreeFeature())
@JvmField
val MINT_FEATURE = create("mint", MintBlockFeature())
@JvmField
val BERRY_GROVE_FEATURE = CobblemonFeatures.create("berry_grove", BerryGroveFeature())
@@ -29,7 +29,6 @@ object CobblemonPlacedFeatures {
val APRICORN_TREES = of("apricorn_trees")
val SACCHARINE_TREE = of("saccharine_tree")
val MINTS = of("mints")
@@ -43,7 +42,6 @@ object CobblemonPlacedFeatures {
fun register() {
// We don't need to pass in any tags, the feature implementation handles it, while not a perfect system it works
Cobblemon.implementation.addFeatureToWorldGen(APRICORN_TREES, GenerationStep.Feature.VEGETAL_DECORATION, null)
Cobblemon.implementation.addFeatureToWorldGen(SACCHARINE_TREE, GenerationStep.Feature.VEGETAL_DECORATION, null)
Cobblemon.implementation.addFeatureToWorldGen(MINTS, GenerationStep.Feature.VEGETAL_DECORATION, null)
Cobblemon.implementation.addFeatureToWorldGen(MEDICINAL_LEEK, GenerationStep.Feature.VEGETAL_DECORATION, null)
Cobblemon.implementation.addFeatureToWorldGen(BIG_ROOT, GenerationStep.Feature.VEGETAL_DECORATION, BiomeTags.IS_OVERWORLD)
@@ -1,287 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.world.feature
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.api.tags.CobblemonBiomeTags
import com.cobblemon.mod.common.block.SaccharineLeafBlock
import com.cobblemon.mod.common.util.randomNoCopy
import com.google.common.collect.Lists
import kotlin.random.Random
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.block.LeavesBlock
import net.minecraft.registry.tag.BlockTags
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.Direction.*
import net.minecraft.world.StructureWorldAccess
import net.minecraft.world.TestableWorld
import net.minecraft.world.chunk.ChunkStatus
import net.minecraft.world.gen.feature.Feature
import net.minecraft.world.gen.feature.SingleStateFeatureConfig
import net.minecraft.world.gen.feature.TreeFeature
import net.minecraft.world.gen.feature.util.FeatureContext
class SaccharineTreeFeature : Feature<SingleStateFeatureConfig>(SingleStateFeatureConfig.CODEC) {
override fun generate(context: FeatureContext<SingleStateFeatureConfig>): Boolean {
val worldGenLevel: StructureWorldAccess = context.world
val random = context.random
val origin = context.origin
val isGenerating = worldGenLevel.getChunk(origin).status != ChunkStatus.FULL
if (isGenerating) {
val biome = worldGenLevel.getBiome(origin)
val multiplier = if (biome.isIn(CobblemonBiomeTags.HAS_APRICORNS_SPARSE)) {
0.1F
} else if (biome.isIn(CobblemonBiomeTags.HAS_APRICORNS_DENSE)) {
10F
} else if (biome.isIn(CobblemonBiomeTags.HAS_APRICORNS_NORMAL)) {
1.0F
} else {
return false
}
if (random.nextFloat() > multiplier * Cobblemon.config.baseApricornTreeGenerationChance) {
return false
}
}
if (!worldGenLevel.getBlockState(origin.down()).isIn(BlockTags.DIRT)) {
return false
}
val potentialBeehivePositions = mutableListOf<BlockPos>()
// Create trunk (1 or 2 blocks tall)
val logState = CobblemonBlocks.SACCHARINE_LOG.defaultState
val trunkHeight = if (random.nextBoolean()) 1 else 2
for (y in 0 until trunkHeight) {
val logPos = origin.offset(UP, y)
worldGenLevel.setBlockState(logPos, logState, 2)
}
val saccharineLeaf = CobblemonBlocks.SACCHARINE_LEAVES.defaultState // SaccharineLeafBlock
var currentHeight = trunkHeight
// Top Trunk Pattern
placeTopTrunkPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, potentialBeehivePositions)
currentHeight++
// Leaf Start Pattern
placeLeafStartPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState, potentialBeehivePositions, Random)
currentHeight++
// Big Leaf Pattern
placeBigLeafPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState)
currentHeight++
// Small Leaf Pattern
placeSmallLeafPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState, Blocks.AIR.defaultState, Random)
currentHeight++
// Big Leaf Pattern
placeBigLeafPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState)
currentHeight++
// Random extension or Leaf Topper Pattern
if (random.nextBoolean()) {
placeLeafTopperPattern(worldGenLevel, origin.offset(UP, currentHeight), CobblemonBlocks.SACCHARINE_LEAVES.defaultState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState, Random)
} else {
// Small Leaf Pattern
placeSmallLeafPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState, Blocks.AIR.defaultState, Random)
currentHeight++
// Big Leaf Pattern
placeBigLeafPattern(worldGenLevel, origin.offset(UP, currentHeight), logState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState)
currentHeight++
// Leaf Topper Pattern
placeLeafTopperPattern(worldGenLevel, origin.offset(UP, currentHeight), CobblemonBlocks.SACCHARINE_LEAVES.defaultState, CobblemonBlocks.SACCHARINE_LEAVES.defaultState, Random)
}
// Check for flowers within a 5-block radius to place a beehive
if (isFlowerNearby(worldGenLevel, origin)) {
placeBeehive(worldGenLevel, Random, potentialBeehivePositions)
}
return true
}
private fun placeBigLeafPattern(worldGenLevel: StructureWorldAccess, origin: BlockPos, logBlock: BlockState, leafBlock: BlockState) {
val positions = listOf(
origin.add(-2, 0, 0),
origin.add(2, 0, 0),
origin.add(0, 0, -2),
origin.add(0, 0, 2),
origin.add(-1, 0, -2),
origin.add(1, 0, -2),
origin.add(-1, 0, 2),
origin.add(1, 0, 2),
origin.add(-2, 0, -1),
origin.add(-2, 0, 1),
origin.add(2, 0, -1),
origin.add(2, 0, 1),
origin.add(-1, 0, -1),
origin.add(1, 0, 1),
origin.add(-1, 0, 1),
origin.add(1, 0, -1),
origin.add(0, 0, 0), // Add center position
origin.add(1, 0, 0),
origin.add(-1, 0, 0),
origin.add(0, 0, 1),
origin.add(0, 0, -1),
origin.add(0, 0, 0)
)
for (pos in positions) {
setBlockIfClear(worldGenLevel, pos, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
// Center trunk
worldGenLevel.setBlockState(origin, logBlock, 2)
}
private fun placeSmallLeafPattern(worldGenLevel: StructureWorldAccess, origin: BlockPos, logBlock: BlockState, leafBlock: BlockState, specialBlock: BlockState, random: Random) {
val positions = listOf(
origin.add(-1, 0, 0),
origin.add(1, 0, 0),
origin.add(0, 0, -1),
origin.add(0, 0, 1)
)
for (pos in positions) {
setBlockIfClear(worldGenLevel, pos, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
val specialPositions = listOf(
origin.add(-1, 0, -1),
origin.add(1, 0, 1),
origin.add(-1, 0, 1),
origin.add(1, 0, -1)
)
for (pos in specialPositions) {
if (random.nextFloat() < 0.25f) {
setBlockIfClear(worldGenLevel, pos, specialBlock)
} else {
setBlockIfClear(worldGenLevel, pos, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
}
// Center trunk
worldGenLevel.setBlockState(origin, logBlock, 2)
}
private fun placeLeafTopperPattern(worldGenLevel: StructureWorldAccess, origin: BlockPos, leafBlock: BlockState, specialBlock: BlockState, random: Random) {
val positions = listOf(
origin.add(-1, 0, 0),
origin.add(1, 0, 0),
origin.add(0, 0, -1),
origin.add(0, 0, 1),
origin.add(-1, 0, -1),
origin.add(1, 0, 1),
origin.add(-1, 0, 1),
origin.add(1, 0, -1)
)
for (pos in positions) {
if (random.nextFloat() < 0.25f) {
setBlockIfClear(worldGenLevel, pos, specialBlock)
} else {
setBlockIfClear(worldGenLevel, pos, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
}
// Center leaf
setBlockIfClear(worldGenLevel, origin, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
private fun placeLeafStartPattern(worldGenLevel: StructureWorldAccess, origin: BlockPos, logBlock: BlockState, leafBlock: BlockState, potentialBeehivePositions: MutableList<BlockPos>, random: Random) {
val positions = listOf(
origin.add(-1, 0, 0),
origin.add(1, 0, 0),
origin.add(0, 0, -1),
origin.add(0, 0, 1),
origin.add(-1, 0, -1),
origin.add(1, 0, 1),
origin.add(-1, 0, 1),
origin.add(1, 0, -1)
)
for (pos in positions) {
if (random.nextFloat() < 0.25f) {
potentialBeehivePositions.add(pos)
} else {
setBlockIfClear(worldGenLevel, pos, leafBlock.with(LeavesBlock.DISTANCE, 2))
}
}
// Center trunk
worldGenLevel.setBlockState(origin, logBlock, 2)
}
private fun placeTopTrunkPattern(worldGenLevel: StructureWorldAccess, origin: BlockPos, logBlock: BlockState, potentialBeehivePositions: MutableList<BlockPos>) {
val positions = listOf(
origin.add(-1, 0, 0),
origin.add(1, 0, 0),
origin.add(0, 0, -1),
origin.add(0, 0, 1)
)
for (pos in positions) {
potentialBeehivePositions.add(pos)
}
// Center trunk
worldGenLevel.setBlockState(origin, logBlock, 2)
}
private fun isFlowerNearby(worldGenLevel: StructureWorldAccess, origin: BlockPos): Boolean {
for (dx in -5..5) {
for (dz in -5..5) {
for (dy in -5..5) {
val pos = origin.add(dx, dy, dz)
if (worldGenLevel.getBlockState(pos).isIn(BlockTags.FLOWERS)) {
return true
}
}
}
}
return false
}
private fun placeBeehive(worldGenLevel: StructureWorldAccess, random: Random, potentialBeehivePositions: MutableList<BlockPos>) {
if (potentialBeehivePositions.isNotEmpty()) {
val hivePos = potentialBeehivePositions[random.nextInt(potentialBeehivePositions.size)]
setBlockIfClear(worldGenLevel, hivePos, Blocks.BEE_NEST.defaultState)
}
}
private fun setBlockIfClear(worldGenLevel: StructureWorldAccess, blockPos: BlockPos, blockState: BlockState) {
if (!TreeFeature.isAirOrLeaves(worldGenLevel, blockPos)) {
return
}
worldGenLevel.setBlockState(blockPos, blockState, 3)
}
private fun isAir(testableWorld: TestableWorld, blockPos: BlockPos?): Boolean {
return testableWorld.testBlockState(
blockPos
) { blockState: BlockState ->
blockState.isOf(
Blocks.AIR
)
}
}
}
@@ -1,5 +1,5 @@
{
"maxScale": 0.8,
"maxScale": 1.0,
"yTranslation": 0.1,
"yGrowthPoint": 0.5625,
"animations": [
@@ -169,11 +169,6 @@
},
"animation.cubone.cry": {
"animation_length": 1.16667,
"sound_effects": {
"0.04": {
"effect": "pokemon.cubone.cry"
}
},
"bones": {
"upper_torso": {
"rotation": {
@@ -445,11 +445,6 @@
},
"animation.golett.cry": {
"animation_length": 1.5,
"sound_effects": {
"0.0417": {
"effect": "pokemon.golett.cry"
}
},
"bones": {
"neck": {
"rotation": {
@@ -782,11 +782,6 @@
},
"animation.golurk.cry": {
"animation_length": 1.5,
"sound_effects": {
"0.0417": {
"effect": "pokemon.golurk.cry"
}
},
"bones": {
"neck": {
"rotation": {
@@ -2,14 +2,7 @@
"multipart": [
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": false
}
]
"age": "0"
},
"apply": {
"model": "cobblemon:block/berries/planted",
@@ -18,62 +11,16 @@
},
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": true
}
]
"age": "1"
},
"apply": {
"model": "cobblemon:block/berries/planted_bound",
"model": "cobblemon:block/berries/sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": false
}
]
"age": "2"
},
"apply": {
"model": "cobblemon:block/berries/aguav_young",
@@ -82,30 +29,7 @@
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_young",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": false
}
]
"age": "3"
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
@@ -114,14 +38,7 @@
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": true
}
]
"age": "4"
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
@@ -130,62 +47,7 @@
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": true
}
]
"age": "5"
},
"apply": {
"model": "cobblemon:block/berries/aguav_mature",
@@ -2,14 +2,7 @@
"multipart": [
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": false
}
]
"age": "0"
},
"apply": {
"model": "cobblemon:block/berries/planted",
@@ -18,62 +11,16 @@
},
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": true
}
]
"age": "1"
},
"apply": {
"model": "cobblemon:block/berries/planted_bound",
"model": "cobblemon:block/berries/sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": false
}
]
"age": "2"
},
"apply": {
"model": "cobblemon:block/berries/apicot_young",
@@ -82,30 +29,7 @@
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_young",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": false
}
]
"age": "3"
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
@@ -114,14 +38,7 @@
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": true
}
]
"age": "4"
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
@@ -130,62 +47,7 @@
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": true
}
]
"age": "5"
},
"apply": {
"model": "cobblemon:block/berries/apicot_mature",
@@ -2,14 +2,7 @@
"multipart": [
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": false
}
]
"age": "0"
},
"apply": {
"model": "cobblemon:block/berries/planted",
@@ -18,62 +11,16 @@
},
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": true
}
]
"age": "1"
},
"apply": {
"model": "cobblemon:block/berries/planted_bound",
"model": "cobblemon:block/berries/sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": false
}
]
"age": "2"
},
"apply": {
"model": "cobblemon:block/berries/aspear_young",
@@ -82,30 +29,7 @@
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_young",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": false
}
]
"age": "3"
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
@@ -114,14 +38,7 @@
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": true
}
]
"age": "4"
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
@@ -130,62 +47,7 @@
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": true
}
]
"age": "5"
},
"apply": {
"model": "cobblemon:block/berries/aspear_mature",
@@ -2,14 +2,7 @@
"multipart": [
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": false
}
]
"age": "0"
},
"apply": {
"model": "cobblemon:block/berries/planted",
@@ -18,62 +11,16 @@
},
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": true
}
]
"age": "1"
},
"apply": {
"model": "cobblemon:block/berries/planted_bound",
"model": "cobblemon:block/berries/sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": false
}
]
"age": "2"
},
"apply": {
"model": "cobblemon:block/berries/babiri_young",
@@ -82,30 +29,7 @@
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_young",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": false
}
]
"age": "3"
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
@@ -114,14 +38,7 @@
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": true
}
]
"age": "4"
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
@@ -130,62 +47,7 @@
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": true
}
]
"age": "5"
},
"apply": {
"model": "cobblemon:block/berries/babiri_mature",
@@ -2,14 +2,7 @@
"multipart": [
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": false
}
]
"age": "0"
},
"apply": {
"model": "cobblemon:block/berries/planted",
@@ -18,62 +11,16 @@
},
{
"when": {
"AND": [
{
"age": 0
},
{
"rooted": true
}
]
"age": "1"
},
"apply": {
"model": "cobblemon:block/berries/planted_bound",
"model": "cobblemon:block/berries/sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 1
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_sprout",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": false
}
]
"age": "2"
},
"apply": {
"model": "cobblemon:block/berries/belue_young",
@@ -82,30 +29,7 @@
},
{
"when": {
"AND": [
{
"age": 2
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_young",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": false
}
]
"age": "3"
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
@@ -114,14 +38,7 @@
},
{
"when": {
"AND": [
{
"age": 3
},
{
"rooted": true
}
]
"age": "4"
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
@@ -130,62 +47,7 @@
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 4
},
{
"rooted": true
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": false
}
]
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
"uvlock": false
}
},
{
"when": {
"AND": [
{
"age": 5
},
{
"rooted": true
}
]
"age": "5"
},
"apply": {
"model": "cobblemon:block/berries/belue_mature",
Loaded 100 of 987 files, more files were not shown because too many files have changed in this diff. Show more