Compare commits

..
Author SHA1 Message Date
Nick a0ffa4c565 Work on form registry appender 2022-12-20 17:06:26 -08:00
9579 changed files with 207984 additions and 578135 deletions
+1 -2
View File
@@ -31,5 +31,4 @@ forge*changelog.txt
common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
*/generated/resources/*
+10 -31
View File
@@ -7,14 +7,12 @@ stages:
#TODO add client reference test process, search for import com.cobblemon.mod.common.client
build:
build-job:
stage: build
only:
- branches@cable-mc/cobblemon
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew build
- export GRADLE_OPTS="-Xmx3G -Xms3G"
- chmod +x ./gradlew
- ./gradlew build
cache:
key: "$CI_COMMIT_REF_NAME"
policy: push
@@ -22,28 +20,9 @@ build:
- forge/build/libs
- fabric/build/libs
publish:
stage: deploy
dependencies:
- build
cache:
key: "CI_COMMIT_REF_NAME"
policy: pull
paths:
- forge/build/libs/*.jar
- fabric/build/libs/*.jar
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- export GRADLE_OPTS="-Xmx4G -Xms4G"
- chmod +x ./gradlew
- ./gradlew publish
# Separate step to deploy the artifacts, save Norry the headache of keeping even more shit around
deploy:
deploy-job:
stage: deploy
dependencies:
- build
when: manual
cache:
key: "$CI_COMMIT_REF_NAME"
@@ -53,12 +32,12 @@ deploy:
- fabric/build/libs/*.jar
script:
- echo "Collecting artifacts..."
- mv forge/build/libs/*+*.jar ./
- mv fabric/build/libs/*+*.jar ./
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/)"; done
- mv forge/build/libs/*-remap.jar ./
- mv fabric/build/libs/*-remap.jar ./
- for f in *.jar; do mv "$f" "$(echo "$f" | sed s/+/b$CI_PIPELINE_IID+/ | sed s/-remap//)"; done
artifacts:
expire_in: 28 days
paths:
- ./*.jar
# - forge/build/libs/*+*.jar
# - fabric/build/libs/*+*.jar
# - forge/build/libs/*-forge.jar
# - fabric/build/libs/*-remap.jar
+14 -543
View File
@@ -1,558 +1,30 @@
# Changelog
## [1.4.0](#1-4-0)
## 1.1.2
### Additions
- Added nicknaming.
- Added mints, found on mountains.
- Added revival herbs, with pep-up flowers if fully grown, growing in lush caves.
- Added medicinal leeks, growing on the surface of rivers and ponds. It is a potion ingredient!
- Added big roots, generating from cave ceiling dirt and sometimes spreading into energy roots.
- Added trading between players. Press R while looking at another player, you'll figure it out.
- Added pasture blocks, used to let your PC Pokémon roam around your base.
- Added support for scale in animations.
- Added support for jump keyframes (i.e. pre and post keyframes)
- Made Nosepass point towards world spawn while idle.
- Added structure spawn conditions
- Added Pokémon cry system for battles and sending out.
- Added cries for Gen 1-9 starters and their evolutions.
- Added cries for Chatot, Darmanitan, Darumaka, Lucario, Mimikyu, Quagsire, Riolu, Wooper, Caterpie, Metapod, Butterfree, Weedle, Kakuna, Beedrill, Pidgey, Pidgeotto, Pidgeot, Rattata, Raticate, Cleffa, Clefairy, Clefable, Tauros, Miltank, Buneary, Lopunny, Wooloo, Dubwool.
- Added recipes for Berry Juice, Heal Powder, Remedy, Fine Remedy, Superb Remedy, Revive, Max Revive, HP Up, Protein, Iron, Calcium, Zinc, Carbos, PP Up, PP Max, Pasture, Medicinal Leek to Magenta Dye, Roasted Leek, Leek and Potato Stew, Braised Vivichoke, Vivichoke Dip, Mulch Base, Growth Mulch, Surprise Mulch, Coarse Mulch, Humid Mulch, Rich Mulch, Loamy Mulch, Peat Mulch, Sandy Mulch, Health Feather, Muscle Feather, Resist Feather, Genius Feather, Clever Feather, Genius Feather
- Added a shoulder mount for Mimikyu
- Added Advancement trigger for defeating Pokémon and collecting varieties of Pokémon.
- Added sleep animations to Arcanine, Jigglypuff, Wigglytuff, Vulpix and Ninetales.
- Added flying placeholder animations to Pidgey, Pidgeotto, Pidgeot, Golbat, Crobat, Scyther, Scizor, Zapdos, Moltres, Articuno, Dragonite, Rowlet, Dartrix, and Decidueye.
- Added loot to various vanilla chest loot tables (Link Cable in Ancient Cities, Woodland Mansions, End Cities, and Igloos, Vivichoke Seeds in Jungle Temples, Dungeons, and Plains, Savanna, Snowy, and Taiga Villages, and all 7 Apricorn Sprouts in Desert, Plains, Savanna, Snowy, and Taiga Villages, as well as the Bonus Chest)
- Added the `/teststore <player> <store> <properties>` command allowing command block/mcfunction users to query a party, PC or both for Pokémon matching specific properties and returning the match count, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.teststore` if a permission mod is present.
- Added the `/querylearnset <player> <slot> <move>` command allowing command block/mcfunction users to query a party slot and check if the Pokémon can learn a specific move returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.querylearnset` if a permission mod is present.
- Added the `/testpcslot <player> <slot> <properties>` command allowing command block/mcfunction users to query a pc slot and check if the Pokémon matches specific properties returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.testpcslot` if a permission mod is present.
- Added the `/testpartyslot <player> <slot> <properties>` command allowing command block/mcfunction users to query a party slot and check if the Pokémon matches a specific properties returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.testpartyslot` if a permission mod is present.
- Added the `/clearparty <player>` command for emptying a player's party.
- Added the `/pokemonrestart <reset_starters>` and the `/pokemonrestartother <player> <reset_starters>` command allowing command block/mcfunction users to reset a players Pokémon data.
- Added support for "isBattle" and "isTouchingWater" properties on resource pack Pokémon poses. This allows your custom Pokémon to be posed differently when in battle.
- Added support for "isVisible" on a transformed part on resource pack Pokémon poses. This allows your custom Pokémon to have bones disappear in specific poses, such as hiding Greninja's throwing star when not in a battle pose.
- Added the `doPokemonLoot` gamerule to toggle Pokémon dropping items/exp on death.
### Pokémon Added
#### Gen 2
- Spinarak
- Ariados
- Shuckle
- Chinchou
- Lanturn
- Aipom
- Gligar
- Hoothoot
- Noctowl
- Mareep
- Flaaffy
- Ampharos
- Sudowoodo
#### Gen 3
- Taillow
- Swellow
- Relicanth
- Duskull
- Dusclops
- Shroomish
- Breloom
- Cacnea
- Cacturne
- Poochyena
- Mightyenna
- Wingull
- Pelipper
- Numel
- Camerupt
- Clamperl
- Huntail
- Gorebyss
- Surskit
- Masquerain
- Chimecho
- Barboach
- Whiscash
#### Gen 4
- Cherubi (Planned)
- Cherrim (Planned)
- Carnivine
- Shinx
- Luxio
- Luxray
- Ambipom
- Gliscor
- Dusknoir
- Chingling
- Bonsly
- Chatot
- Combee
- Vespiquen
#### Gen 5
- Bouffolant
- Roggenrola
- Boldore
- Gigalith
- Venepede
- Whirlpede
- Scolipede
- Yamask (Planned)
- Cofagrigus (Planned)
- Patrat (Planned)
- Watchog (Planned)
- Lillipup
- Herdier
- Stoutland
#### Gen 6
- Scatterbug
- Spewpa
- Vivillion
- Skrelp (Planned)
- Dragalge (Planned)
- Bunnelby (Planned)
- Diggersby (Planned)
#### Gen 7
- Wishiwashi (Planned)
- Cutiefly
- Ribombee
- Stufful
- Bewear
- Comfey
- Alolan Exeggutor
#### Gen 8
- Arrokuda (Planned)
- Barraskewda (Planned)
- Nickit
- Thievul
- Falinks
- Galarian Farfetch'd
- Sirfetch'd
- Rookidee
- Corvisquire
- Corviknight
#### Gen 9
- Sprigatitto
- Floragato
- Meowscarada
- Flittle
- Espathra
- Garganacl
- Fidough
- Dachsbun
- Armarouge
- Ceruledge
- Cetoddle
- Cetitan
- Shroodle (Planned)
- Grafaiai (Planned)
- Tandemaus
- Maushold
- Varoom
- Revavroom
- Squawkabilly (Planned)
- Glimmet
- Glimmora
- Reworked customisation of models, textures, and animations to make fakemon very easy to create.
- Added 'nature' and 'pokeball' options to commands such as /spawnpokemon and /givepokemon.
- Added support for datapack spawn files and spawn file presets.
### Changes
- Updated model and textures of Arcanine, Magnemite, Magneton, Magnezone, Exeggcute, Exeggutor, Farfetchd, Elekid, Electabuzz, Electivire, Pichu, Pikachu, Raichu, Gengar, Wooper Drowzee, Hypno, Aerodactyl, Spearow, Fearow, Lickitung, Pidgeotto, Pidgeot, Scyther, Scizor, Kleavor, Popplio, Brionne, Primarina, Torchic, Combusken, Blaziken, Aerodacyl, Scyther, Scizor, Kleavor, Lickitung, Lickilicky, Happiny, Chansey, Pidgey, Pidgeotto, Pidgeot, Spearow, Fearow, Drowzee, Hypno, Arcanine, Magnemite, Magneton, Magnezone, Exeggcute, Exeggutor, Farfetchd, Elekid, Electabuzz, Electivire, Pichu, Pikachu, Raichu, and Gengar.
- Updated models of Sceptile and Shuckle.
- Updated sprites for EV medicines, the rare candy, and the apricorn door item.
- Updated textures for apricorn doors and all the evolution stone ores.
- Updated Apricorn Leaves color.
- Wild Pokémon now heal if you are defeated by them or flee from them.
- Doubled the default time between ambient Pokémon cries (they have cries if you're using a resource pack to add them)
- Moved spawn attempts per tick to a config option (ticksBetweenSpawnAttempts)
- PCs can now be waterlogged
- Starter selection prompt now appears as a tutorial-esque toast instead of plain text
- Cobblemon items can now all have their own tooltips via resourcepacks, to add a tooltip simply add a lang entry like "item.cobblemon.{item_id}.tooltip", if you want to add multiple tooltip lines you can do so with "item.cobblemon.{item_id}.tooltip_1" and upwards.
- Updated texture of Weedle.
- Updated shiny texture of Dwebble and Crustle.
- Updated Animations for Piplup, Prinplup, Empoleon, Drowzee, Hypno, Farfetch'd, Exeggcute, Exeggutor, Bidoof, Chimecho, Lickytung, Lickilicky, Popplio, Brionne, Luvdisc, Chimchar, Monferno, Infernape, Sobble, Drizzile, Inteleon, Greninja, Heatmor, Aerodactyl, Ditto, Lotad, Lombre, Ludicolo, Pumpkaboo, Gourgeist.
- Reorganised the advancements recipes folder
- Pokeedit command now supports IVs and EVs.
- Reorganised creative categories
- Pokemon can now wander into non-solid blocks such as foliage
- Pokeballs now despawn after 30 seconds
- Dive Balls will now have the same motion speed underwater as if they were thrown in the air.
- Hardcoded potion shoulder effects have been removed, you can now use any potion vanilla or otherwise with the parameters you'd like, for more information see the [Datapack & Resourcepack Creators](#datapack-&-resourcepack-creators) section.
- Clicking categories of the Stat sub-section or the party reorder button in the Summary screen will now produce a click sound.
- Updated PC Recipe.
- Improved Pokémon AI and movement.
- Friendship will slowly increase when Pokémon are shoulder-mounted.
### Fixes
- Fixed spawning moon phase dependent Pokémon only when the moon phase is wrong
- Fixed large Pokémon spawning partially inside walls where they suffocate.
- Fixed messages for entry hazards, screens, Tailwind, Perish Song, Destiny Bond, Shed Skin, Uproar, Forewarn, Disguise, Arena Trap, Yawn, Curse, Clamp, Whirlpool, Liquid Ooze, Miracle Eye and Safeguard.
- Fixed Porygon not evolving with an Upgrade.
- Fixed super sized Pumpkaboo not having any moves.
- Fixed Infernape look animation.
- Fixed Garchomp t-posing while swimming.
- Fixed a bug that caused sleeping Pokémon to stay asleep.
- Fixed a bug that would freeze a battle when a Pokémon gets trapped due to an ability.
- Fixed the Poké Ball close animation canceling whenever colliding with a block.
- Fixed faint animations not working properly in add-ons.
- Fixed lighting and Pokémon label issues when a Pokémon item frame is nearby.
- Fixed Pokémon being able to spawn outside the world border as a tease.
- Fixed deepslate water stone ore items looking like deepslate fire stone ores.
- Fixed a bunch of client-side logging errors when Pokémon are shoulder mounted.
- Fixed a crash when wild Pokémon have to struggle under specific circumstances.
- Fixed uncolored pixels on Yanma's shiny texture.
- Fixed apricorn tree leaves looking gross on Fast graphics mode.
- Fixed hoes not breaking apricorn tree leaves any faster.
- Fixed Shiftry's PC model position.
- Fixed the /pc command not playing the opening sound.
- Fixed Shedinja not being able to recover naturally.
- Fixed different forms of Pokémon not being able to appear as different sizes.
- Fixed the Healing Machine soft locking you from using others when removed by non-players.
- Fixed animations being sped up when using the Replay Mod.
- Fixed particle animations not running when a Pokémon is off-screen.
- Fixed Pokémon variants and layers not rendering correctly when shouldered and playing on a dedicated server, existing shoulders affected will need to be retrieved and shouldered again.
- Shoulder effects will now stay applied through situations that remove potion effects such as drinking milk.
- Fixed Shedninja evolving to use the consumed Pokeball and removed the held item.
- Fixed non-existent species in spawn pool file causing random species to spawn.
- Fixed shearing Pokémon dropping 0-2 wool instead of 1-3.
- Fixed some alignment issues in the stat hexagon of the summary menu.
### Developer
- Added SpawnEvent
- Added persistent NBT property inside Pokemon to store quick and simple data.
- Species and FormData have had their evolutions, pre-evolution and labels properties exposed. It is still recommended to work using a Pokémon instance when possible.
- Added capture check to BattleVictoryEvent
- Added ThownPokeballHitEvent
- The various hardcoded potion shoulder effects have been removed, make use of PotionBaseEffect.
### Datapack & Resourcepack Creators
- All potion related shoulder effects have had their IDs changed, they now all share the same type being `potion_effect` and use the vanilla Potion data [parameters](https://minecraft.fandom.com/wiki/Potion#Item_data), take for example the default Pidgey asset:
- ```json
{
"type": "potion_effect",
"effect": "minecraft:slow_falling",
"amplifier": 0,
"ambient": true,
"showParticles": false,
"showIcon": false
}
```
## [1.3.1 (March 31st, 2023)](#1-3-1)
### Additions
- Added Slugma, Magcargo, Nosepass, and Probopass.
- Elgyem family now drops Chorus Fruit, Geodude family now drops Black Augurite.
- Added missing spawn files for Golett and Bergmite family.
- Apricorns can now be smelted into dyes.
- Added animations to Staryu line and Porygon line.
- Added faint animations to Klink line.
- Add lava surface spawn preset.
- Added an ``any`` evolution requirement allowing you to define ``possibilities`` of other evolution requirements, for example, this allows you to create an evolution that requires the Pokémon to be shiny or a female.
- Added the `/spawnpokemonfrompool [amount]` or `/forcespawn [amount]` command to spawn Pokémon(s) in the surrounding area using the natural spawn rates/pool of that area, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.spawnpokemon` if a permission mod is present. On a successful execution of the command, the amount of Pokémon spawned will be the output.
- Added the `/pokebox` and `/pokeboxall` commands to move Pokemon(s) to the PC from a Player's party, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pokebox` if a permission mod is present. On a successful execution of the command the output will be the number of pokemon moved to the Player's PC.
- Added the `/pc` command which opens up the PC UI the same way interacting with the block would, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pc` if a permission mod is present.
### Changes
- You can now click the portraits of other Pokémon in the starter selection screen to navigate directly to them.
- You can now click the right and left arrow keys to navigate PC boxes.
- Link Cables will now require Pokémon to hold any held item normally required for their evolution.
- After a battle, the last Pokémon used now becomes the selected one in your party.
- The `/teach` command can now only allow the Pokémon to be given moves in their learnset, this can be controlled with the permission `cobblemon.command.teach.bypass`, to account for that change the base command now requires the permission `cobblemon.command.teach.base`, this change is meant only for people using a mod capable of providing permissions such as [LuckPerms](https://luckperms.net/).
- Apricorns will no longer collide with their block form when picked, this should improve the experience in automatic farms.
- Increased spawn chances for many Pokémon requiring specific blocks to be nearby.
- Put Cryogonal in more snowy biomes.
- Ditto as well as the Eevee, Gible, and Riolu families have been made more common.
- Lowered spawn rate of Gyarados on the surface of water.
- Apricorn leaves can now be used in the [Composter](https://minecraft.fandom.com/wiki/Composter) block, these have the same chance to raise the compost pile the Minecraft leaves do.
- Updated Gengar's model and texture.
- Updated Swinub line model and animations.
- Tweaked portrait frames for the Pidgey line and for Walking Wake.
- Changed all buff shoulder effects to only give a level 1 buff instead of level 2.
- Made Weavile a little bigger.
- Changed the recipes for Mystic Water, Miracle Seed, and Charcoal Stick to utilise the evolution stones, as well as Never-Melt Ice having an alternate recipe using the Ice Stone.
- Replaced the `Failed to handle` battle messages to `Missing interpretation` to make it more clear that mechanics do work just still pending dedicated messages.
- Healing Machine and PC are now mine-able with pickaxes and Apricorn leaves are mine-able using hoes.
- Updated Pokéball, UI and evolution sounds.
### Fixes
- Fixed killing a Dodrio killing your game. Dodrio will never look the same to us.
- Fixed non-Fire-type Pokémon being immune to lava.
- Fixed custom Pokémon not being usable in battle, properly. A last minute fix caused this to break again; what are these devs not paid for?
- Fixed being locked in an endless healing queue if you broke the healing machine during use.
- Fixed an issue with the experience calculation when the Exp. Share is held.
- Fixed Friendship-based attacks not using friendship values from your Pokémon.
- Fixed Link Cables consuming held items they shouldn't due to not validating the held item of a Pokémon.
- Fixed a crash when Aromatherapy cured the status of party members.
- Fixed moves learnt on evolution not being given when said evolution happens. If you were affected by this issue your existing Pokémon will now be able to relearn those moves.
- Fixed console spam when rendering Pokémon model items.
- Fixed battle messages for 50+ moves and abilities and items.
- Fixed the possible duplicate when capturing Pokémon (probably, this one's hard to reproduce to confirm it's fixed).
- Previously duplicated Pokémon are cleaned from PCs and parties on restart.
- Fixed an issue with some particle effects applying after a Pokémon has died or on top of the wrong Pokémon when using specific mods.
- Fixed Pokémon not looking at each other in battle.
- Fixed Experience Candy and Experience Share attempting to bring Pokémon above level cap causing crashes.
- Fixed level 100 Pokémon having experience go over the cap total amount they should have.
- Fixed `/pokemonspawnat` having the argument positions reverted making it impossible for Brigadier to understand when to suggest coordinates. It is now the intended `/spawnpokemonat <pos> <properties>`.
- Fixed performance issues with shouldered Pokémon in certain systems.
- Fixed learnset issues for Pokémon whose only modern debut was LGPE/BDSP/LA.
- Fixed shiny Zubat, Grimer, Omanyte, Elgyem, Delphox and Aegislash displaying their normal texture.
- Fixed sleeping in beds allowing fainted Pokémon to receive experience after a battle ends somehow.
- Fixed an issue where a Pokémon will claim to have learnt a new move they already have in their moveset when learnt at an earlier level in their previous evolution. I realize that's confusing.
- Fixed Dispensers not being able to shear Wooloo. This will also extend to other mods that check if an entity is valid to shear.
- Fixed the currently held item of your Pokémon not dropping to the ground when removing it if your inventory was full.
- Fixed creative mode allowing you to make your Pokémon hold more than 1 of the same item.
- Fixed a Pokémon duplication glitch when teleporting between worlds.
- Fixed dedicated servers being able to reload Cobblemon data with the vanilla `/reload` command causing unintended behavior for clients.
- Fixed underground Pokémon spawning above ground.
- Fixed Pokémon portrait not reverting back to the Pokémon after a failed capture during battle.
- Fixed edge texture artifacts on pane elements for Tentacool and Tentacruel models.
- Fixed crash caused by Pokémon pathing
- Fixed Pokémon not returning to their balls when being healed in a healing machine
- Fixed all Gen IX Pokémon as well as forms added in PLA and Wyrdeer, Kleavor, Ursaluna, Basculegion, Sneasler, Overqwil, and Enamorus having 0 exp yields.
- Fixed Irons Leaves having bluetooth back legs. If you saw it, you know what I mean.
- Fixed Golurk not having shoulder plates on its shoulders.
- Fixed some water Pokémon walking onto land from the water even though they are fish.
- Fixed Porygon2 and PorygonZ being too small.
- Fixed Snivy line head look animation.
- Fixed Staryu line not being able to swim.
- Fixed an incompatibility with [Thorium](https://modrinth.com/mod/thorium) patch for [MC-84873](https://bugs.mojang.com/browse/MC-84873).
- Fixed Pidgeotto wings when walking.
- Fixed Delphox walk animation.
- Fixed Froakie line sleep animations in battle.
- Fixed Pokémon missing the non-level up moves they could relearn when rejoining a world until a new move was added to their relearn list.
- Fixed instantly fleeing from Pokémon set to be unfleeable.
- Fixed Pumpkaboo line forms not working. (Currently sizes aren't visual but check base stats to see which size you have.)
- Fixed a bug that caused already interpreted messages for moves to be mistaken as uninterpreted.
- Fixed a Pokémon spawner bug that caused Pokémon to not spawn due to dropped item entities.
- Fixed a bug that causes Pokémon model items to be invisible.
### Developer
- Add events that are fired just before and after a Pokémon is released (ReleasePokemonEvent.Pre and .Post)
### Localization
- Added complete translations for Japanese, Thai, and Canadian French.
- Added partial translations for Russian, Ukrainian, Mexican Spanish, and Korean.
- Updated every existing language's translation.
- All the translators that contributed are amazing.
## [1.3.0 - The Foundation Update (March 17th, 2023)](#1-3-0)
### Dependencies
- Upgraded Fabric API dependence to 0.75.1+1.19.2
- Upgraded Architectury API dependence to 6.5.69
- Cobblemon Forge now depends on Kotlin for Forge.
### Additions
- Added new models and animations for Poké Balls and reworked their mechanics to feel much smoother instead of being pure frustration.
- Added party scrolling via holding R and using the mouse wheel so you don't need to take your hand off your mouse.
- Added a cap of Pokémon spawns in an area because waiting a while made things insane. This is controlled by a new `pokemonPerChunk` config option.
- Added models and animations for heaps of Pokémon (101): Riolu, Lucario, Chimchar, Monferno, Infernape, Turtwig, Grotle, Torterra, Popplio, Brionne, Primarina, Treeko, Grovyle, Sceptile, Snivy, Servine, Serperior, Tepig, Pignite, Emboar, Oshawott, Dewott, Samurott, Grookey, Thwackey, Rillaboom, Scorbunny, Raboot, Cinderace, Sobble, Drizzile, Inteleon, Fennekin, Braixen, Delphox, Froakie, Frogadier, Greninja, Chespin, Quilladin, Chesnaught, Miltank, Torkoal, Kricketot, Kricketune, Heatmor, Durant, Wooloo, Dubwool, Pumpkaboo, Gourgeist, Sigilyph, Cryogonal, Whismur, Loudred, Exploud, Misdreavus, Mismagius, Tatsugiri, Eiscue, Luvdisc, Stantler, Wyrdeer, Gible, Gabite, Garchomp, Sneasel, Weavile, Elgyem, Beheeyem, Baltoy, Claydol, Nacli, Naclstack, Alcremie, Milcery, Dhelmise, Morelull, Shiinotic, Xerneas, Klink, Klang, Klinklang, Joltik, Galvantula, Honedge, Duoblade, Aegislash, Spiritomb, Mawile, Carvanha, Sharpedo, Seedot, Nuzleaf, Shiftry, Lotad, Lombre, Ludicolo, Pineco, Forretress, and Spinda.
- Added generation 3, 4, 5, 6, 7, and 8 Starter Pokémon to the starter select screen.
- Added particle effect support for model animations
- Added particle effect and animation for Gastly.
- Added sleep and faint animations to many Pokémon.
- Added item holding for Pokémon. Any Minecraft item can be given to a Pokémon by holding shift and right-clicking them. Traditional Pokémon held items will have their expected battle effects.
- Added heaps of held items with crafting recipes: Assault Vest, Big Root, Black Belt, Black Sludge, Charcoal, Choice Band, Choice Scarf, Choice Specs, Dragon Fang, Exp. Share, Focus Band, Hard Stone, Heavy-Duty Boots, Leftovers, Light Clay, Lucky Egg, Magnet, Miracle Seed, Muscle Band, Mystic Water, Never-Melt Ice, Poison Barb, Quick Claw, Rocky Helmet, Safety Goggles, Sharp Beak, Silk Scarf, Silver Powder, Soft Sand, Spell Tag, Twisted Spoon, and Wise Glasses.
- Added heaps of evolution items with crafting recipes: Milcery's sweets items, Chipped Pot, Cracked Pot, Deep Sea Scale, Deep Sea Tooth, Dragon Scale, Galarica Cuff, Galarica Wreath, Peat Block, Prism Scale, Razor Claw, Razor Fang, Reaper Cloth, Sachet, Sweet Apple, Tart Apple, and Whipped Dream.
- Existing evolution items all now either have a crafting recipe or drop from Pokémon.
- Added the Item [tags](https://minecraft.fandom.com/wiki/Tag) `cobblemon:held/experience_share` and `cobblemon:held/lucky_egg` allowing you to mark any items you desire to have the effects implied in the tag name.
- Added an interface that appears when interacting with your Pokémon while sneaking. The interface allows for interactive options such as shouldering and exchanging held items.
- Added blinking animations to many Pokémon.
- Added animated texture support.
- Added translucent option for aspect layers.
- Added glowing textures to many Pokémon and it looks amazing.
- Added the Saturation shoulder effect.
- Added the Haste shoulder effect, initially for Joltik.
- Added the Water Breathing shoulder effect, initially for Wooper.
- Added the Speed shoulder effect, initially for Pichu and Pikachu.
- [Dispensers](https://minecraft.fandom.com/wiki/Dispenser) can now use shears to automatically harvest fully grown Apricorns.
- Added milking to Miltank.
- Added shearing to Wooloo and Dubwool.
- Added data for generation 9 Pokémon species, moves, and ability data. They're all still Substitute models, but their moves and abilities work.
- Added support for custom Pokémon to implement 'quirks' such as blinks.
- Added sound effect for harvesting Apricorns.
- Added icon to summary and PC interfaces to indicated if a Pokémon is shiny.
- Added the ``/spawnpokemonat <pos> <properties>`` command, the ``pos`` argument uses the same syntax as the Minecraft [summon](https://minecraft.fandom.com/wiki/Commands/summon) command.
- Added the `/giveallpokemon` command which is definitely safe and not insane.
- Added compatibility with Carry On by preventing the mod being able to interact with Cobblemon entities, the mod caused too many gameplay detrimental features to stay enabled.
- Added healing to your party when you sleep in a bed.
- Added the 'ability' Pokémon Property so commands can specify the ability.
- Added block tag support to the 'neededBaseBlocks' and 'neededNearbyBlocks' spawn condition.
- Added a config option for disallowing players from damaging Pokémon by hand.
- Apricorn seeds can now be used with the [Composter](https://minecraft.fandom.com/wiki/Composter), these have the layer increase chance of 65% like Apricorns and various Minecraft crops.
- Added support for Pokémon species data appending making it so datapack developers no longer need to overwrite files.
- Added an implementation of every [catch rate](https://bulbapedia.bulbagarden.net/wiki/Catch_rate) from generation 1 to 9, these can be used by changing the ``captureCalculator`` config value:
- ``generation_1`` Sets the calculator to the generation 1 implementation.
- ``generation_2`` Sets the calculator to the generation 2 implementation.
- ``generation_2_fixed`` Sets the calculator to the generation 2 implementation with the status multiplier bug fixed.
- ``generation_3_4`` Sets the calculator to the generation 3 and 4 implementation.
- ``generation_5`` Sets the calculator to the generation 5 implementation.
- ``generation_6`` Sets the calculator to the generation 6 implementation.
- ``generation_7`` Sets the calculator to the generation 7 implementation.
- ``generation_8`` Sets the calculator to the generation 8 implementation.
- ``generation_9`` Sets the calculator to the generation 9 implementation.
- ``cobblemon`` Sets the calculator to the custom Cobblemon implementation. This is the default value.
- ``debug`` Sets the calculator to the debug/cheat implementation, every attempt will be a successful critical capture.
### Changes
- Pokémon now save to the world by default, meaning the same Pokémon will remain in the world and not disappear after you log out and log back in. They still despawn over time though.
- Significantly sped up the Poké Ball shake animation so it takes less time to try to catch Pokémon.
- Update the PC and Healing Machine models and bounding boxes.
- The Healing Machine and PC now emit light when fully charged or when turned on respectively.
- The PC block screen will now turn on when being used.
- The Healing Machine will now visually display its charge level using 6 stages.
- The Healing Machine will now emit a redstone signal with the strength of 1 for every 10% charge it has when attached to a [Redstone Comparator](https://minecraft.fandom.com/wiki/Redstone_Comparator).
- Made it so that particles are not shown whenever you have a shoulder Pokémon that gives potion effects.
- Changed hitbox and size definitions for Decidueye, Blastoise, and Magmortar
- Apricorns can now be harvested with Axes, the speed will scale with enchantments and tool material, only dropping the Apricorn if fully grown, these will still destroy the Apricorn so the manual harvest still is recommended unless you're just keen on destroying trees.
- Apricorns are now a part of the vanilla tag ``minecraft:blocks/mineable/axe``.
- Apricorns are now compatible with any mod that breaks a whole tree at once.
- Apricorns no longer have a config value for the seed drop chance these are now a part of their loot table which can be found in ``cobblemon/loot_tables/blocks/<color>_apricorn.json``.
- Advancements were redone to be slightly more interesting, with improved names, descriptions, and sorting.
- Updated models and textures for Tentacool line, Gengar, Slowpoke line, Tyrogue line, Doduo line, Dratini, Dragonair, Quagsire, and Piplup line. There were probably others, the team lost track.
- Improved sending out Pokémon at the start of battle so that they are positioned in a less annoying way.
- Name Tags will no longer be used on Pokémon and Poke Ball entities, this prevents the item from being wasted.
- Lowered spawn rate of Tauros.
- Sableye now spawns near gem ores as well as amethyst.
- Added evolution stones and items to item tags
### Fixes
- Fixed catch rates being entirely too difficult.
- Fixed various strange battle issues such as Flying types being vulnerable to Ground type moves and status effects hitting despite vulnerabilities.
- Fixed shiny Gyarados not using the red Gyarados texture.
- Improved the framing of all in-game Pokémon in the party and PC GUIs so they aren't halfway out of the screen or something else crazy.
- Fixed incompatibility with Kotlin for Forge (by depending on Kotlin for Forge ourselves)
- Fixed Gengar, Goodra, and many other Pokémon showing the types of an alternate form despite those not being modelled yet.
- Fixed datapack Pokémon not being able to battle.
- Fixed Pokémon always being created with a moveset as if they're level 1 instead of their current level.
- Fixed an issue of Pokémon not rendering in GUIs on some Mac displays.
- Fixed a soft-duplicate that could occur when a party Pokémon is pushed through a Nether Portal or left in a boat.
- Fixed Pokémon that faint from poison appearing to be on full health and suckering you into false hope.
- Fixed incorrect spawns of Tentacool, Tentacruel, Dragonite, Politoed, Tangrowth, Lickilicky, Electivire, and Magmortar.
- Fixed crashes involving opening the Pokémon summary GUI with an empty party.
- Fixed lower brightness settings causing Pokémon to appear much too dark in menus such as the party and PC.
- Fixed Showdown sometimes failing to start, causing crashes.
- Fixed Showdown initialization happening several times when you login, more depending on how many times you have relogged this session.
- Fixed Showdown failing to update on first attempt. We totally weren't accidentally deleting our target directory or anything, nope.
- Fixed HP recovery related battle actions not animating for the client nor updating the in-game Pokémon HP.
- Fixed moves that force a switch such as Teleport and U-Turn soft locking battles.
- Fixed missing battle text for Bide, Speed Boost, Belly Drum, Anger Point, and Haze.
- Fixed battle messages for many field effects starting, ending, and actions caused by them such as blocking certain moves.
- Improved battle messages for effects that prevent a move from being executed such as a Taunt, requiring a recharge, flinched, etc.
- Fixed move names not being translated in battle messages.
- Fixed stat change messages for boosts over 3 stages.
- Fixed experience calculation not being completely accurate.
- Fixed positioning of Poké Balls when rendered in Healing Machines.
- Fixed a desync issue on servers where all Pokémon seemed like they were special forms when they weren't.
- Fixed an incompatibility with [Exordium](https://www.curseforge.com/minecraft/mc-mods/exordium).
- Fixed datapack Pokémon language key generation. A Pokémon under the namespace ``example`` named ``Pogemon`` will now correctly look for the lang key ``example.species.pogemon.name``.
- Fixed client not receiving messages for the different "stages" for the move Bide.
- Fixed the Medium Slow and Medium Fast experience group IDs, they're now ```medium_slow``` and ``medium_fast``. Any custom datapack Pokémon will require an update.
- Fixed Pokémon friendship being capped to the maximum level config value instead of the friendship one when loading Pokémon data.
- Fixed Poké Balls taking forever to capture Pokémon if you are underwater or up in the air where it takes a long time to hit the ground.
- Fixed Pokémon being unable to spawn on blocks such as snow layers.
- Fixed Pokémon spawning inside of trees.
- Fixed Pokémon experience not loading after a restart and instead going back to the minimal amount for the current level.
- Fixed being able to use ``/healpokemon`` in battle.
- Fixed being able to select fainted party members in the switch menu causing the battle to lock.
- Fixed ``/spawnpokemon`` command not supporting any command source other than players.
- Fixed issues with Charizard's sleep pose.
- Fixed players being able to use multiple healer machines at once.
- Fixed Pokémon layers not rendering when a Pokémon is on your shoulder.
- Fixed Caterpie and Weedle not moving or looking at players. That was meant to be Metapod and Kakuna; how embarrassing.
- Fixed Pokémon not carrying over the correct equivalent original ability when evolving from stages that only had one ability.
- Fixed Deerling and Sawsbuck not spawning with the correct season.
- Fixed issue of not being able to drag the scroll bar in summary and battle interfaces.
- Fixed optional aspects not saving and loading properly.
- Fixed layering logic so multiple texture layers can exist on a Pokémon (probably).
- Fixed not all Poké Balls being associated with the `cobblemon:pokeballs` item tag.
- Fixed the `/pokemoneditother` command not working.
- Fixed ambient sound file path for Porygon2.
- Fixed forms not being able to unset the secondary type of a Pokémon in the stat JSON.
- Fixed moves that haven't carried over from generation 8 onwards having the description they did in the generation 8 games instead of their last valid one.
- Fixed shoulder mounted pokemon not returning to party on healer use and on evolution
### Developer
- Reworked CatchRateModifier, as such, existing implementations need to be updated.
- Fixed minimumDistanceBetweenEntities option being half of what it's set as.
- Fixed the contents of CobblemonEvents, CobblemonBlocks etc having getters instead of just being public static properties.
- Added ApricornHarvestEvent.
- Added a new item for representing Pokémon within native UI menus or item frames which display as the Pokémon's model. It's called a PokemonItem, with static functions to build one.
### Localization
- Added complete translations for French, German, Simplified Mandarin, Brazilian Portuguese, and Pirate English.
- Added partial translations for Traditional Mandarin, Italian, and Spanish. We'd love more help with this!
- Thank you to all of the fantastic volunteer translators for taking the time to help with this!
## [1.2.0 - The Customization Update (January 1st, 2023)](#1-2-0)
### Additions
- Added models for Natu and Xatu, Murkrow and Honchkrow, Wailmer and Wailord.
- Added new PC interface and it is beautiful.
- Reworked the battle system so that battles load faster, cause fewer bugs, and can run on shared server hosts. This is a very big change that also reduced the size of the mod by 50mb!
- Added full resource pack / data pack customization of models, textures, animations, spawning, and spawn file presets to make custom Pokémon species and variations very easy to create. You can find the guide for creating custom Pokémon on [our website](https://cobblemon.com/guides/custompokemon.html)!
- Added water surface spawning for Pokémon like Lapras.
- Added emissive texture support to Pokémon render layers.
- Added compatibility for Mod Menu ([CurseForge](https://www.curseforge.com/minecraft/mc-mods/modmenu), [Modrinth](https://modrinth.com/mod/modmenu)).
- Added blank ambient Pokémon cries so cries can be added via resource packs.
- Added new sounds for GUIs and item uses.
- Added `nature` and `pokeball` options to commands such as `/spawnpokemon` and `/givepokemon`.
### Changes
- Reinforced party and PC saving to make data corruption from crashes less bad.
- Added a config option for whether the starter config will be exported, making it more maintainable as we add starter Pokémon.
- Battles now start with the options menu open for convenience.
- Doubled the default charge rate of healers. You'd need to reset your config under `./config/cobblemon/main.json` to see this change!
- Changed the default Apricorn seed chance config value from 6% to 10%.
- The mod now correctly reports our dependency on Architectury API so people don't get super confused when things don't work.
- Pokémon now look at their opponents during battle.
- Updated Sableye's animations to be super freaky.
- Changed the healer advancements to make the healing machine's mechanics more obvious.
### Fixes
- Fixed an incompatibility with [Porting Lib](https://github.com/Fabricators-of-Create/Porting-Lib) used by Fabric ports of mods such as Create or Twilight Forest.
- Fixed HP and max HP values in the battle GUI not being correct.
- Fixed some animations on snake-type Pokémon being super slow.
- Fixed some animations on snake-type Pokémon being mega slow.
- Fixed a typo in the English name for Calcium. Calcuim.
- Fixed Pokémon gradually becoming rarer around you if you move long distances.
- Fixed a shoulder mount crash on Fabric.
- Fixed a rare issue where chunks would take a really long time to generate.
- Fixed a singleplayer bug where battles wouldn't work after leaving then rejoining a world.
- Fixed stat calculations for everything except HP. HP was fine though :).
- Fixed a randomized Pokémon spawning in mountains that corrupted the data of whatever party or PC it got into. Yikes.
- Fixed a rare crash involving literally random number generation. A random crash involving random numbers.
- Fixed all regular Mewtwo having the stats and types of Mega Mewtwo X - same deal with many other Pokémon.
- Fixed the framing of many Pokémon in GUIs.
- Fixed texture glitches with Rattata and Nidoqueen (again!).
- Fixed dropped item forms of all Pokéballs and the Healing Machine, and slightly adjusted all other display settings
- Fixed issues with forms not showing the correct evolution in the evolution menu.
- Fixed some alternate forms not having the alternate stats and types.
- Fixed moves that only work in double battles not being selectable at all (such as Helping Hand and Aromatic Mist).
- Fixed abilities not remaining legal in some forms.
- Fixed Poké Ball capture effects not triggering after a successful capture, such as the Heal Ball's healing effect.
- Fixed multiple-hit moves sending gibberish into the battle chat.
- Fixed Pyukumuku not being appropriately scaled.
- Fixed shiny and other variations of Pokémon not showing in the battle GUI.
- Fixed Eevee being poorly positioned and un-animated on shoulders.
- Fixed a Pokémon's hitbox not updating when it evolves while sent out.
- Fixed a Pokémon's PP going from zero to above the maximum when entering another battle.
## [1.1.1 (November 27th, 2022)](#1-1-1)
## 1.1.1 (November 27th, 2022)
### Fixes
- Fixed a critical issue with servers where Pokémon data didn't properly synchronize and so you couldn't see any.
## [1.1.0 - The Swim and Sleep Update (November 27th, 2022)](#1-1-0)
## 1.1.0 - The Swim and Sleep Update (November 27th, 2022)
#### "Ideally not at the same time."
### Additions
- Added a new GUI for viewing party information, rearranging moves, and evolving Pokémon. It looks too good.
- Starter Pokémon will sleep on top of you if sent out when you get on a bed.
@@ -606,7 +78,6 @@
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
### Localization
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
## [1.0.0 (November 12th, 2022)](#1-0-0)
- Initial release.
- Added species, ability, and move translations for ko_ko, jp_jp, fr_fr, es_es, it_it, and zh_cn.
## 1.0.0 (2022-11-12)
- Initial release.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (C) 2023 Cobblemon Contributors
Copyright (C) 2022 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
+8 -9
View File
@@ -4,15 +4,14 @@ An open-source Pokémon mod for Minecraft Java Edition, written in Kotlin for Fa
## Getting started
To set up the development workspace, first clone the project and open the build.gradle with Intellij. Make sure that you clone it to a folder that has no spaces in its path (for example, C:/Development/Cobblemon Stuff/cobblemon/ is bad) since Architectury Plugin seems to dislike it.
To set up the development workspace, first clone the project and open the build.gradle with Intellij. There will be
errors until you go to File -> Settings -> Build, Execution, Deployment -> Build Tools -> Gradle and change the Gradle JVM
to 17. After changing this, click the icon for reloading the project. This will automatically
put together all the dependencies and project setup.
After it takes ages to load, you should hopefully have runnable configurations of the project in the top right, such as Minecraft Client (:fabric). If not, try running `./gradlew genEclipseRuns`.
Troubleshooting:
- Try running `./gradlew --refresh-dependencies`
- Try File -> Invalidate Caches.
- Try deleting the `.idea` folder in the project root (make sure IntelliJ is closed when you try it).
- Try completely reclone the thing lmao.
Run `./gradlew genEclipseRuns`, and then in Intellij go to your run configurations, and change whichever you plan on
running to use a Java 17 JRE. runClient is as if you booted up in singleplayer, runServer is a server without a client,
and runData is for summoning the Eldritch gods or something, idk.
## Contributing
@@ -20,4 +19,4 @@ If you're interested in contributing to the project, you can simply fork the rep
[here](https://gitlab.com/cable-mc/cobblemon/-/issues?scope=all&state=opened&label_name[]=accepted&assignee_id=None).
If you want a more involved role in the project, involving branches on the main repository instead of forking and involvement
in design discussions, you can either apply in the `application-box` forum of our Discord or add and message Hiroku (`hiroku_dev`) on our Discord here: https://discord.gg/cobblemon.
in design discussions, add and message Hiroku#4373 on our Discord here: https://discord.gg/AsNpJSST7G.
@@ -3,7 +3,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
val accessWidenerFile = "src/main/resources/cobblemon-common.accesswidener"
plugins {
java
`java-library`
id("org.cadixdev.licenser")
id("dev.architectury.loom")
@@ -39,7 +38,8 @@ loom {
dependencies {
minecraft("net.minecraft:minecraft:${rootProject.property("mc_version")}")
mappings("net.fabricmc:yarn:${rootProject.property("yarn_version")}:v2")
mappings("net.fabricmc:yarn:${rootProject.property("yarn_version")}")
}
tasks {
@@ -19,14 +19,13 @@ tasks {
archiveClassifier.set("dev-shadow")
archiveBaseName.set("Cobblemon-${project.name}")
configurations = listOf(bundle)
mergeServiceFiles()
}
remapJar {
dependsOn(shadowJar)
inputFile.set(shadowJar.flatMap { it.archiveFile })
archiveBaseName.set("Cobblemon-${project.name}")
archiveVersion.set("${rootProject.version}")
archiveClassifier.set("${rootProject.version}-remap")
}
}
@@ -1,37 +0,0 @@
plugins {
java
`java-library`
id("maven-publish")
id("dev.architectury.loom")
}
java {
withSourcesJar()
withJavadocJar()
}
publishing {
repositories {
maven("https://maven.impactdev.net/repository/development/") {
name = "ImpactDev-Public"
credentials {
username = System.getenv("COBBLEMON_MAVEN_USER")
password = System.getenv("COBBLEMON_MAVEN_PASSWORD")
}
}
}
publications {
create<MavenPublication>(project.name) {
artifact(tasks.remapJar)
artifact(tasks.remapSourcesJar)
@Suppress("UnstableApiUsage")
loom.disableDeprecatedPomGeneration(this)
groupId = "com.cobblemon"
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
version = rootProject.version.toString()
}
}
}
+1
View File
@@ -1,3 +1,4 @@
plugins {
base
id("cobblemon.root-conventions")
+36 -13
View File
@@ -1,15 +1,15 @@
plugins {
id("cobblemon.base-conventions")
id("cobblemon.publish-conventions")
id("maven-publish")
}
architectury {
common("forge", "fabric")
common()
}
repositories {
maven(url = "${rootProject.projectDir}/deps")
mavenLocal()
maven(url = "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/")
maven(url = "https://maven.impactdev.net/repository/development/")
}
dependencies {
@@ -17,26 +17,49 @@ dependencies {
implementation(libs.reflect)
modImplementation(libs.fabricLoader)
modApi(libs.architectury)
modApi(libs.molang)
modApi(libs.mclib)
// For Showdown
modCompileOnly(libs.graal)
modCompileOnly(libs.javet) // Linux or Windows
modCompileOnly(libs.javetMac) // Mac OS (x86_64 Only)
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
testRuntimeOnly(libs.junitEngine)
testImplementation(libs.junitApi)
testImplementation(libs.junitParams)
testImplementation(libs.mockito)
testImplementation(libs.mockk)
testImplementation(libs.classgraph)
compileOnly("net.luckperms:api:${rootProject.property("luckperms_version")}")
// For Showdown
// modCompileOnly 'com.caoccao.javet:javet:1.0.6' // Linux or Windows
// modCompileOnly 'com.caoccao.javet:javet-macos:1.0.6' // Mac OS (x86_64 Only)
// modCompileOnly group: 'commons-io', name: 'commons-io', version: '2.6'
implementation("net.impactdev:json:1.0.0")
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
setEvents(listOf("failed"))
setExceptionFormat("full")
publishing {
repositories {
maven("https://maven.impactdev.net/repository/development/") {
name = "ImpactDev-Public"
credentials {
username = System.getenv("NEXUS_USER")
password = System.getenv("NEXUS_PW")
}
}
}
}
publications {
create<MavenPublication>("mod") {
from(components["java"])
groupId = "com.cobblemon"
artifactId = "mod"
version = rootProject.version.toString()
}
}
}
-1
View File
@@ -1 +0,0 @@
maven.artifactId = mod
View File
@@ -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.access;
import net.minecraft.sound.SoundCategory;
public interface SoundManagerDuck {
void toggleCategories(SoundCategory... categories);
}
@@ -1,71 +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.models.blockbench.pose;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
/**
* A bone represents a particular joint of a model. Bones are capable of containing child bones identifiable
* by a String ideally representing the name of a particular bone.
*
* This interface is meant to allow projects and sidemods to implement their own rendering logic in reference
* to the bones.
*
* @author Waterpicker
* @since 1.4.0
*/
public interface Bone {
/**
* A map of identifiable names to child bones
*
* @since 1.4.0
*/
Map<String, Bone> getChildren();
/**
* Renders a particular bone in relation to a particular entity.
*
* @param entity The entity this bone is being drawn for. This parameter need not be available and can be null
* @param stack The current [MatrixStack] for the renderer
* @param buffer The vertex consumer deployed by the renderer
* @param packedLight The light level to be applied to the bone
* @param packedOverlay The overlay value to be applied to the bone
* @param r A value representing the amount of red coloring that should be applied on the RGB scale
* @param g A value representing the amount of green coloring that should be applied on the RGB scale
* @param b A value representing the amount of blue coloring that should be applied on the RGB scale
* @param a The alpha value to apply to the model based on the RGB scale
*
* @since 1.4.0
*/
<T extends Entity> void render(
@Nullable T entity,
MatrixStack stack,
VertexConsumer buffer,
int packedLight,
int packedOverlay,
float r,
float g,
float b,
float a
);
/**
* Allows for direct transformation of a bone via a given matrix stack
*
* @since 1.4.0
*/
void transform(MatrixStack matrixStack);
}
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 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.command.argument.*;
import com.mojang.brigadier.arguments.ArgumentType;
import net.minecraft.command.argument.ArgumentTypes;
import net.minecraft.command.argument.serialize.ArgumentSerializer;
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ArgumentTypes.class)
public class ArgumentTypesMixin {
@Shadow
private static <A extends ArgumentType<?>, T extends ArgumentSerializer.ArgumentTypeProperties<A>> ArgumentSerializer<A, T> register(Registry<ArgumentSerializer<?, ?>> registry, String string, Class<? extends A> clazz, ArgumentSerializer<A, T> argumentSerializer) {
throw new AssertionError("Should not be executed.");
}
@Inject(method = "register(Lnet/minecraft/util/registry/Registry;)Lnet/minecraft/command/argument/serialize/ArgumentSerializer;", at = @At("RETURN"))
private static void register(Registry<ArgumentSerializer<?, ?>> registry, CallbackInfoReturnable<ArgumentSerializer<?, ?>> ci) {
register(registry, "cobblemon:pokemon", PokemonArgumentType.class, ConstantArgumentSerializer.of(PokemonArgumentType.Companion::pokemon));
register(registry, "cobblemon:pokemonproperties", PokemonPropertiesArgumentType.class, ConstantArgumentSerializer.of(PokemonPropertiesArgumentType.Companion::properties));
register(registry, "cobblemon:spawnbucket", SpawnBucketArgumentType.class, ConstantArgumentSerializer.of(SpawnBucketArgumentType.Companion::spawnBucket));
register(registry, "cobblemon:move", MoveArgumentType.class, ConstantArgumentSerializer.of(MoveArgumentType.Companion::move));
register(registry, "cobblemon:partyslot", PartySlotArgumentType.class, ConstantArgumentSerializer.of(PartySlotArgumentType.Companion::partySlot));
}
}
@@ -1,36 +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.client.render.item.CobblemonBuiltinItemRenderer;
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.BuiltinModelItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BuiltinModelItemRenderer.class)
public class BuiltinModelItemRendererMixin {
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
private void cobblemon$useDynamicItemRenderer(ItemStack stack, ModelTransformationMode mode, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, CallbackInfo ci) {
CobblemonBuiltinItemRenderer renderer = CobblemonBuiltinItemRendererRegistry.INSTANCE.rendererOf(stack.getItem());
if (renderer != null) {
renderer.render(stack, mode, matrices, vertexConsumers, light, overlay);
ci.cancel();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,47 +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.CobblemonBlocks;
import com.cobblemon.mod.common.block.PastureBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.FenceBlock;
import net.minecraft.block.HorizontalFacingBlock;
import net.minecraft.util.math.Direction;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = FenceBlock.class)
public abstract class FenceBlockMixin {
// This could be done with a modify variable but it just doesn't seem to want to work, very crude unfinished explanation I had on Fabric discord was
// "boolean is a primitive, it isnt passed by reference but by value and you have your own object references anyway so assigning a new object to non-primitive references (variables) wont modify it after your mixin returns
//(you cant modify a random argument that mixin passes you that way, target the boolean not the FenceBlock)"
// However the issue is the only way to get all the params which we need is by passing in the entire method reference which enforces the return type.
@Redirect(method = "getStateForNeighborUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/FenceBlock;canConnect(Lnet/minecraft/block/BlockState;ZLnet/minecraft/util/math/Direction;)Z"))
private boolean cobblemon$getStateForNeighborUpdate(FenceBlock instance, BlockState state, boolean neighborIsFullSquare, Direction dir) {
return instance.canConnect(state, neighborIsFullSquare, dir) || this.cobblemon$canConnect(state, dir);
}
@Redirect(method = "getPlacementState", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/FenceBlock;canConnect(Lnet/minecraft/block/BlockState;ZLnet/minecraft/util/math/Direction;)Z"))
private boolean cobblemon$getPlacementState(FenceBlock instance, BlockState state, boolean neighborIsFullSquare, Direction dir) {
return instance.canConnect(state, neighborIsFullSquare, dir) || this.cobblemon$canConnect(state, dir);
}
private boolean cobblemon$canConnect(BlockState state, Direction dir) {
if (state.isOf(CobblemonBlocks.PASTURE) && state.get(PastureBlock.Companion.getPART()) == PastureBlock.PasturePart.BOTTOM) {
final Direction pastureFacing = state.get(HorizontalFacingBlock.FACING);
return dir == pastureFacing.rotateYClockwise() || dir == pastureFacing.rotateYCounterclockwise();
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,31 +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.api.pokemon.effect.ShoulderEffectRegistry;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin {
@Inject(method = "onStatusEffectRemoved", at = @At(value = "TAIL"))
private void cobblemon$onStatusEffectRemoved(StatusEffectInstance effect, CallbackInfo ci) {
final LivingEntity entity = (LivingEntity) (Object) this;
if (entity instanceof ServerPlayerEntity) {
ShoulderEffectRegistry.INSTANCE.onEffectEnd((ServerPlayerEntity) entity);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,47 +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.client.render.models.blockbench.pose.Bone;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.Entity;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
@Mixin(ModelPart.class)
public abstract class ModelPartMixin implements Bone {
@Shadow public abstract void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha);
@Shadow public abstract void rotate(MatrixStack matrixStack);
@Shadow @Final
public Map<String, ModelPart> children;
@NotNull
@Override
public Map<String, Bone> getChildren() {
return (Map<String, Bone>) (Object) children;
}
@Override
public <T extends Entity> void render(T entity, MatrixStack stack, VertexConsumer buffer, int packedLight, int packedOverlay, float r, float g, float b, float a) {
this.render(stack, buffer, packedLight, packedOverlay, r, g, b, a);
}
@Override
public void transform(MatrixStack matrixStack) {
this.rotate(matrixStack);
}
}
@@ -1,53 +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.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import net.minecraft.client.Mouse;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(Mouse.class)
public class PartyScrollMixin {
@Shadow
private double eventDeltaWheel;
@Inject(
method = "onMouseScroll",
at = @At(
value = "FIELD",
target="Lnet/minecraft/client/Mouse;eventDeltaWheel:D",
opcode = Opcodes.PUTFIELD,
ordinal = 2,
shift = At.Shift.BEFORE
),
cancellable = true
)
public void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) {
if (PartySendBinding.INSTANCE.getWasDown()) {
int i = (int)eventDeltaWheel;
if (i > 0) {
while (i-- > 0) CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
ci.cancel();
eventDeltaWheel = 0;
PartySendBinding.INSTANCE.actioned();
} else if (i < 0) {
while (i++ < 0) CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
ci.cancel();
eventDeltaWheel = 0;
PartySendBinding.INSTANCE.actioned();
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,25 +9,15 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.DataKeys;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvent;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.world.World;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
@@ -35,13 +25,9 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
import java.util.UUID;
import static com.cobblemon.mod.common.util.LocalizationUtilsKt.lang;
@Mixin(PlayerEntity.class)
public abstract class PlayerMixin extends LivingEntity {
@@ -57,11 +43,6 @@ public abstract class PlayerMixin extends LivingEntity {
@Shadow public abstract boolean isSpectator();
@Shadow public abstract boolean giveItemStack(ItemStack stack);
@Shadow public abstract void sendMessage(Text message, boolean overlay);
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, World p_20967_) {
super(p_20966_, p_20967_);
}
@@ -134,32 +115,4 @@ public abstract class PlayerMixin extends LivingEntity {
return CompoundTagExtensionsKt.isPokemonEntity(nbt);
}
@Inject(
method = "eatFood",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/entity/player/PlayerEntity;getHungerManager()Lnet/minecraft/entity/player/HungerManager;",
shift = At.Shift.AFTER
)
)
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
if (!getWorld().isClient) {
if (stack.getItem() == Items.APPLE && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
assert player != null;
CobblemonEvents.LEFTOVERS_CREATED.postThen(
new LeftoversCreatedEvent(player, leftovers),
leftoversCreatedEvent -> null,
leftoversCreatedEvent -> {
if(!player.giveItemStack(leftoversCreatedEvent.getLeftovers())) {
var itemPos = player.getRotationVector().multiply(0.5).add(getPos());
getWorld().spawnEntity(new ItemEntity(getWorld(), itemPos.getX(), itemPos.getY(), itemPos.getZ(), leftoversCreatedEvent.getLeftovers()));
}
return null;
}
);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,25 +8,20 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags;
import com.cobblemon.mod.common.tags.CobblemonBlockTags;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.PointedDripstoneBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.Slice;
@Mixin(PointedDripstoneBlock.class)
public abstract class PointedDripstoneBlockMixin {
@Redirect(
method = "canGrow(Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;)Z",
at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z", ordinal = 0),
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/block/Block;"))
)
@Redirect(method = "canGrow(Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;isOf(Lnet/minecraft/block/Block;)Z", ordinal = 0))
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
return instance.isIn(CobblemonBlockTags.DRIPSTONE_GROWABLE);
return instance.isIn(CobblemonBlockTags.INSTANCE.getDRIPSTONE_GROWABLE());
}
}
@@ -1,31 +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.brewing.BrewingRecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.BrewingStandScreenHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BrewingStandScreenHandler.PotionSlot.class)
public class PotionSlotMixin {
@Inject(
method = "matches",
at = @At(value = "HEAD"),
cancellable = true
)
private static void matchesBrewable(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (BrewingRecipes.brewableItems.contains(stack.getItem())) {
cir.setReturnValue(true);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -18,6 +18,7 @@ import net.minecraft.world.chunk.ChunkManager;
import net.minecraft.world.chunk.ChunkStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -1,34 +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.ShearableBlock;
import kotlin.Unit;
import net.minecraft.block.BlockState;
import net.minecraft.block.dispenser.ShearsDispenserBehavior;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ShearsDispenserBehavior.class)
public abstract class ShearsDispenserBehaviorMixin {
// This exists, so we can execute our custom interaction only if no one redirected shears interactions to overwrite the vanilla ones.
@Inject(method = "tryShearBlock", at = @At("HEAD"), cancellable = true)
private static void cobblemon$tryApricornHarvest(ServerWorld world, BlockPos pos, CallbackInfoReturnable<Boolean> cir) {
final BlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof ShearableBlock shearableBlock) {
cir.setReturnValue(shearableBlock.attemptShear(world, state, pos, () -> Unit.INSTANCE));
}
}
}
@@ -1,43 +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.access.SoundManagerDuck;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.SoundManager;
import net.minecraft.sound.SoundCategory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SoundManager.class)
public class SoundManagerMixin implements SoundManagerDuck {
private boolean[] blockedCategories = new boolean[SoundCategory.values().length];
@Override
public void toggleCategories(SoundCategory... categories) {
for (SoundCategory category : categories) {
int index = category.ordinal();
boolean blocked = blockedCategories[index];
blockedCategories[index] = !blocked;
}
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
public void play(SoundInstance sound, CallbackInfo cb) {
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
public void play(SoundInstance sound, int delay, CallbackInfo cb) {
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
}
}
@@ -1,39 +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.google.common.collect.Multimap;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.SoundSystem;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(SoundSystem.class)
public abstract class SoundSystemMixin {
@Shadow
private Multimap<SoundCategory, SoundInstance> sounds;
@Shadow
protected abstract void stop(SoundInstance sound);
@Inject(method = "stopSounds(Lnet/minecraft/util/Identifier;Lnet/minecraft/sound/SoundCategory;)V", at = @At("HEAD"), cancellable = true)
public void stopSounds(@Nullable Identifier id, @Nullable SoundCategory category, CallbackInfo cb) {
if (id == null && category != null) {
sounds.get(category).forEach(this::stop);
cb.cancel();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,22 +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.accessor;
import net.minecraft.client.sound.MusicTracker;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(MusicTracker.class)
public interface MusicTrackerAccessor {
@Accessor("timeUntilNextSong")
int timeUntilNextSong();
@Accessor("timeUntilNextSong")
void setTimeUntilNextSong(int timeUntilNextSong);
}
@@ -1,26 +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.accessor;
import net.minecraft.entity.effect.StatusEffectInstance;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(StatusEffectInstance.class)
public interface StatusEffectInstanceAccessor {
@Accessor
void setAmplifier(int amplifier);
@Accessor
void setShowParticles(boolean showParticles);
@Accessor
void setShowIcon(boolean showIcon);
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,41 +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.invoker;
import net.minecraft.block.*;
import net.minecraft.resource.featuretoggle.FeatureFlag;
import net.minecraft.sound.BlockSoundGroup;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@SuppressWarnings("unused")
@Mixin(Blocks.class)
public interface BlocksInvoker {
@Invoker("createLogBlock")
static PillarBlock createLogBlock(MapColor topMapColor, MapColor sideMapColor) {
throw new UnsupportedOperationException();
}
@Invoker("createLeavesBlock")
static LeavesBlock createLeavesBlock(BlockSoundGroup soundGroup) {
throw new UnsupportedOperationException();
}
@Invoker("createWoodenButtonBlock")
static ButtonBlock createWoodenButtonBlock(BlockSetType blockSetType, FeatureFlag... requiredFeatures) {
throw new UnsupportedOperationException();
}
@Invoker("createFlowerPotBlock")
static FlowerPotBlock createFlowerPotBlock(Block flower, FeatureFlag... requiredFeatures) {
throw new UnsupportedOperationException();
}
}
@@ -1,21 +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.invoker;
import net.minecraft.world.GameRules;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(GameRules.BooleanRule.class)
public interface BooleanRuleInvoker {
@Invoker("create")
static GameRules.Type<GameRules.BooleanRule> cobblemon$create(boolean initialValue) {
throw new UnsupportedOperationException();
}
}
@@ -1,20 +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.invoker;
import net.minecraft.client.network.ClientPlayNetworkHandler;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ClientPlayNetworkHandler.class)
public interface ClientPlayNetworkHandlerInvoker {
@Invoker
void callPlaySpawnSound(Entity entity);
}
@@ -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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.DoorBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(DoorBlock.class)
public interface DoorBlockInvoker {
@Invoker("<init>")
static DoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.PressurePlateBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(PressurePlateBlock.class)
public interface PressurePlateBlockInvoker {
@Invoker("<init>")
static PressurePlateBlock cobblemon$create(PressurePlateBlock.ActivationRule type, AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.StairsBlock;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(StairsBlock.class)
public interface StairsBlockInvoker {
@Invoker("<init>")
static StairsBlock cobblemon$create(BlockState baseBlockState, AbstractBlock.Settings settings) {
throw new UnsupportedOperationException();
}
}
@@ -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.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.sound.SoundEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(TrapdoorBlock.class)
public interface TrapdoorBlockInvoker {
@Invoker("<init>")
static TrapdoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
throw new UnsupportedOperationException();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -14,7 +14,6 @@ import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
@@ -34,12 +33,13 @@ public abstract class ItemRendererMixin {
@Shadow @Final private ItemModels models;
@Shadow public abstract void renderItem(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model);
@Shadow public abstract void renderItem(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model);
@Inject(method = "getModel", at = @At("HEAD"), cancellable = true)
private void cobblemon$bakePokeballModel(ItemStack stack, World world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
if (stack.getItem() instanceof PokeBallItem pokeBallItem) {
BakedModel model = this.models.getModelManager().getModel(new ModelIdentifier(pokeBallItem.getPokeBall().getModel3d(), "inventory"));
ModelIdentifier modelIdentifier = new ModelIdentifier(pokeBallItem.getPokeBall().getModel3d());
BakedModel model = this.models.getModelManager().getModel(modelIdentifier);
ClientWorld clientWorld = world instanceof ClientWorld ? (ClientWorld) world : null;
BakedModel overriddenModel = model.getOverrides().apply(model, stack, clientWorld, entity, seed);
cir.setReturnValue(overriddenModel == null ? this.models.getModelManager().getMissingModel() : overriddenModel);
@@ -47,14 +47,15 @@ public abstract class ItemRendererMixin {
}
@Inject(
method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$determinePokeballModel(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d = renderMode == ModelTransformationMode.GUI || renderMode == ModelTransformationMode.FIXED;
private void cobblemon$determinePokeballModel(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
boolean shouldBe2d = renderMode == ModelTransformation.Mode.GUI || renderMode == ModelTransformation.Mode.FIXED;
if (shouldBe2d && stack.getItem() instanceof PokeBallItem pokeBallItem) {
BakedModel replacementModel = this.models.getModelManager().getModel(new ModelIdentifier(pokeBallItem.getPokeBall().getModel2d(), "inventory"));
ModelIdentifier modelIdentifier = new ModelIdentifier(pokeBallItem.getPokeBall().getModel2d());
BakedModel replacementModel = this.models.getModelManager().getModel(modelIdentifier);
if (!model.equals(replacementModel)) {
ci.cancel();
renderItem(stack, renderMode, leftHanded, matrices, vertexConsumers, light, overlay, replacementModel);
@@ -1,35 +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.pokeball;
import com.cobblemon.mod.common.entity.pokeball.WaterDragModifier;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.projectile.thrown.ThrownEntity;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@Mixin(ThrownEntity.class)
public abstract class ThrownEntityMixin extends Entity {
public ThrownEntityMixin(EntityType<?> type, World world) {
super(type, world);
}
@ModifyVariable(method = "tick", at = @At("STORE"), ordinal = 0)
private float cobblemon$waterDragModifier(float value) {
if (this.isTouchingWater() && this instanceof WaterDragModifier) {
return ((WaterDragModifier) this).waterDrag();
}
return value;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -18,13 +18,18 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.LIVING_DEATH
import com.cobblemon.mod.common.api.events.CobblemonEvents.PLAYER_QUIT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
import com.cobblemon.mod.common.api.events.CobblemonEvents.SERVER_STARTED
import com.cobblemon.mod.common.api.events.CobblemonEvents.SERVER_STOPPED
import com.cobblemon.mod.common.api.events.CobblemonEvents.TICK_POST
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
import com.cobblemon.mod.common.api.permission.PermissionValidator
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculators
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CobblemonGen348CaptureCalculator
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
@@ -32,14 +37,18 @@ import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.GlobalSpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.reactive.Observable.Companion.filter
import com.cobblemon.mod.common.api.reactive.Observable.Companion.map
import com.cobblemon.mod.common.api.reactive.Observable.Companion.takeFirst
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
@@ -53,22 +62,14 @@ import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactor
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.command.argument.MoveArgumentType
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
import com.cobblemon.mod.common.battles.runner.ShowdownConnection
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.config.LastChangedVersion
import com.cobblemon.mod.common.config.constraint.IntConstraint
import com.cobblemon.mod.common.config.starter.StarterConfig
import com.cobblemon.mod.common.data.CobblemonDataProvider
@@ -76,68 +77,64 @@ import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.serverhandling.ServerPacketRegistrar
import com.cobblemon.mod.common.permission.LaxPermissionValidator
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
import com.cobblemon.mod.common.pokemon.feature.BattleCriticalHitsFeature
import com.cobblemon.mod.common.pokemon.feature.DamageTakenFeature
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.UntradeableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.getServer
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.removeAmountIf
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.cobblemon.mod.common.world.CobblemonGameRules
import com.cobblemon.mod.common.world.feature.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.placement.CobblemonPlacementTypes
import dev.architectury.event.EventResult
import dev.architectury.event.events.common.CommandRegistrationEvent
import dev.architectury.event.events.common.InteractionEvent
import dev.architectury.hooks.item.tool.AxeItemHooks
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.UUID
import kotlin.properties.Delegates
import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import net.minecraft.client.MinecraftClient
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer
import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.WorldSavePath
import net.minecraft.util.registry.RegistryKey
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
object Cobblemon {
const val MODID = "cobblemon"
const val VERSION = "1.4.0"
const val VERSION = "1.2.0"
const val CONFIG_PATH = "config/$MODID/main.json"
val LOGGER = LogManager.getLogger()
lateinit var implementation: CobblemonImplementation
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
var captureCalculator: CaptureCalculator
get() = this.config.captureCalculator
set(value) {
this.config.captureCalculator = value
}
lateinit var showdown: ShowdownConnection
var captureCalculator: CaptureCalculator = CobblemonGen348CaptureCalculator
var experienceCalculator: ExperienceCalculator = StandardExperienceCalculator
var evYieldCalculator: EvCalculator = Generation8EvCalculator
var starterHandler: StarterHandler = CobblemonStarterHandler()
var isDedicatedServer = false
val showdownThread = ShowdownThread()
var showdownThread = ShowdownThread()
lateinit var config: CobblemonConfig
var prospector: SpawningProspector = CobblemonSpawningProspector
var areaContextResolver: AreaContextResolver = object : AreaContextResolver {}
@@ -151,32 +148,24 @@ object Cobblemon {
var statProvider: StatProvider = CobblemonStatProvider
var seasonResolver: SeasonResolver = TagSeasonResolver
fun preInitialize(implementation: CobblemonImplementation) {
this.implementation = implementation
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerBlocks()
implementation.registerItems()
implementation.registerEntityTypes()
implementation.registerEntityAttributes()
implementation.registerBlockEntityTypes()
implementation.registerWorldGenFeatures()
implementation.registerParticles()
fun preinitialize(implementation: CobblemonImplementation) {
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
ExperienceGroups.registerDefaults()
CaptureCalculators.registerDefaults()
this.loadConfig()
// CobblemonBlockPredicates.touch()
CobblemonOrePlacedFeatures.register()
CobblemonPlacedFeatures.register()
this.registerArgumentTypes()
this.implementation = implementation
CobblemonCriteria // Init the fields and register the criteria
CobblemonGameRules // Init fields and register
CobblemonEntities.register()
CobblemonBlocks.register()
CobblemonBlockEntities.register()
CobblemonItems.register()
ServerPacketRegistrar.registerHandlers()
CobblemonSounds.register()
CobblemonFeatures.register()
CobblemonGameRules.register()
ShoulderEffectRegistry.register()
@@ -184,28 +173,19 @@ object Cobblemon {
storage.onPlayerDataSync(it)
playerData.get(it).sendToPlayer(it)
starterHandler.handleJoin(it)
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel).sendToPlayer(it)
ServerSettingsPacket().sendToPlayer(it)
}
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
PCLinkManager.removeLink(it.player.uuid)
BattleRegistry.getBattleByParticipatingPlayer(it.player)?.stop()
storage.onPlayerDisconnect(it.player)
playerData.onPlayerDisconnect(it.player)
TradeManager.onLogoff(it.player)
PLAYER_QUIT.subscribe {
PCLinkManager.removeLink(it.uuid)
BattleRegistry.getBattleByParticipatingPlayer(it)?.stop()
}
PlatformEvents.PLAYER_DEATH.subscribe {
PCLinkManager.removeLink(it.player.uuid)
battleRegistry.getBattleByParticipatingPlayer(it.player)?.stop()
LIVING_DEATH.pipe(filter { it is ServerPlayerEntity }, map { it as ServerPlayerEntity }).subscribe {
battleRegistry.getBattleByParticipatingPlayer(it)?.stop()
}
PlatformEvents.RIGHT_CLICK_ENTITY.subscribe { event ->
if (event.player.getStackInHand(event.hand).item is NameTagItem && event.entity.type.isIn(CobblemonEntityTypeTags.CANNOT_HAVE_NAME_TAG)) {
event.cancel()
}
}
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { event ->
val player = event.player
val block = player.world.getBlockState(event.pos).block
InteractionEvent.RIGHT_CLICK_BLOCK.register(InteractionEvent.RightClickBlock { pl, _, pos, _ ->
val player = pl as? ServerPlayerEntity ?: return@RightClickBlock EventResult.pass()
val block = player.world.getBlockState(pos).block
player.party().forEach { pokemon ->
pokemon.evolutions
.filterIsInstance<BlockClickEvolution>()
@@ -213,21 +193,22 @@ object Cobblemon {
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.world))
}
}
}
PlatformEvents.CHANGE_DIMENSION.subscribe {
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
}
return@RightClickBlock EventResult.pass()
})
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
fun initialize() {
showdownThread.launch()
showdownThread.start()
CompletableRegistry.allRegistriesCompleted.thenAccept {
LOGGER.info("All registries loaded.")
}
CobblemonPlacementTypes.register()
CobblemonOrePlacedFeatures.register()
// Start up the data provider.
CobblemonDataProvider.registerDefaults()
@@ -238,27 +219,31 @@ object Cobblemon {
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
SpeciesFeatures.register(
DataKeys.CAN_BE_MILKED,
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.CAN_BE_MILKED), default = true))
SpeciesFeatures.register(
DataKeys.HAS_BEEN_SHEARED,
FlagSpeciesFeatureProvider(keys = listOf(DataKeys.HAS_BEEN_SHEARED), default = false))
GlobalSpeciesFeatures.register(DamageTakenFeature.ID) { DamageTakenFeature() }
GlobalSpeciesFeatures.register(BattleCriticalHitsFeature.ID) { BattleCriticalHitsFeature() }
CustomPokemonProperty.register(UntradeableProperty)
CustomPokemonProperty.register(UncatchableProperty)
CustomPokemonProperty.register(PokemonFlagProperty)
CustomPokemonProperty.register(HiddenAbilityPropertyType)
CommandRegistrationEvent.EVENT.register(CobblemonCommands::register)
ifDedicatedServer {
isDedicatedServer = true
PlatformEvents.SERVER_TICK_POST.subscribe { ScheduledTaskTracker.update() }
TICK_POST.subscribe { ScheduledTaskTracker.update() }
CobblemonNetwork.clientHandlersRegistered.complete(Unit)
}
PlatformEvents.SERVER_STARTING.subscribe { event ->
val server = event.server
CobblemonBlocks.completed.thenAccept {
AxeItemHooks.addStrippable(CobblemonBlocks.APRICORN_LOG.get(), CobblemonBlocks.STRIPPED_APRICORN_LOG.get())
AxeItemHooks.addStrippable(CobblemonBlocks.APRICORN_WOOD.get(), CobblemonBlocks.STRIPPED_APRICORN_WOOD.get())
}
SERVER_STARTED.subscribe { server ->
playerData = PlayerDataStoreManager().also { it.setup(server) }
val pokemonStoreRoot = server.getSavePath(WorldSavePath.ROOT).resolve("pokemon").toFile()
storage.registerFactory(
priority = Priority.LOWEST,
factory = FileBackedPokemonStoreFactory(
@@ -273,15 +258,16 @@ object Cobblemon {
)
}
PlatformEvents.SERVER_STOPPED.subscribe {
SERVER_STOPPED.subscribe {
storage.unregisterAll()
playerData.saveAll()
showdown.close()
}
PlatformEvents.SERVER_STARTED.subscribe {
SERVER_STARTED.subscribe {
bestSpawner.onServerStarted()
battleRegistry.onServerStarted()
}
PlatformEvents.SERVER_TICK_POST.subscribe { ServerTickHandler.onTick(it.server) }
TICK_POST.subscribe { ServerTickHandler.onTick(it) }
POKEMON_CAPTURED.subscribe { AdvancementHandler.onCapture(it) }
// EGG_HATCH.subscribe { AdvancementHandler.onHatch(it) }
BATTLE_VICTORY.subscribe { AdvancementHandler.onWinBattle(it) }
@@ -293,39 +279,31 @@ object Cobblemon {
if (this.config.ninjaskCreatesShedinja && pokemon.species.resourceIdentifier == ninjaskIdentifier && PokemonSpecies.getByIdentifier(Pokemon.SHEDINJA) != null) {
val player = pokemon.getOwnerPlayer() ?: return@subscribe
if (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
}
}
}
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
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)
}
}
}
BagItems.observable.subscribe {
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
battleRegistry.startBattle(
BattleFormat.GEN_9_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
).apply { mute = true }
showdownThread.showdownStarted.thenAccept {
PokemonSpecies.observable.pipe(takeFirst()).subscribe {
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
battleRegistry.startBattle(
BattleFormat.GEN_8_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
).apply { mute = true }
}
}
}
fun getLevel(dimension: RegistryKey<World>): World? {
return if (isDedicatedServer) {
server()?.getWorld(dimension)
getServer()?.getWorld(dimension)
} else {
val mc = MinecraftClient.getInstance()
return mc.server?.getWorld(dimension) ?: mc.world
@@ -348,59 +326,44 @@ object Cobblemon {
exception.printStackTrace()
}
val defaultConfig = CobblemonConfig()
this.config::class.memberProperties.forEach {
// Member must have annotations and must be mutable
if (it.annotations.isEmpty() || it !is KMutableProperty<*>) return@forEach
CobblemonConfig::class.memberProperties.forEach {
val field = it.javaField!!
it.isAccessible = true
field.annotations.forEach {
when (it) {
is LastChangedVersion -> {
val defaultChangedVersion = it.version
val lastSavedVersion = config.lastSavedVersion
if (defaultChangedVersion.isLaterVersion(lastSavedVersion)) {
field.set(config, field.get(defaultConfig))
}
}
var value = it.getter.call(config)
for (annotation in it.annotations) {
when (annotation) {
is IntConstraint -> {
var value = field.get(config)
if (value is Int) {
value = value.coerceIn(it.min, it.max)
field.set(config, value)
}
if (value !is Int) break
value = value.coerceIn(annotation.min, annotation.max)
it.setter.call(config, value)
}
}
}
}
} else {
this.config = CobblemonConfig()
this.saveConfig()
}
config.lastSavedVersion = VERSION
this.saveConfig()
bestSpawner.loadConfig()
PokemonSpecies.observable.subscribe { starterConfig = this.loadStarterConfig() }
}
fun loadStarterConfig(): StarterConfig {
if (config.exportStarterConfig) {
val file = File("config/cobblemon/starters.json")
file.parentFile.mkdirs()
if (!file.exists()) {
val config = StarterConfig()
val pw = PrintWriter(file)
StarterConfig.GSON.toJson(config, pw)
pw.close()
return config
}
val reader = FileReader(file)
val config = StarterConfig.GSON.fromJson(reader, StarterConfig::class.java)
reader.close()
val file = File("config/cobblemon/starters.json")
file.parentFile.mkdirs()
if (!file.exists()) {
val config = StarterConfig()
val pw = PrintWriter(file)
StarterConfig.GSON.toJson(config, pw)
pw.close()
return config
} else {
return StarterConfig()
}
val reader = FileReader(file)
val config = StarterConfig.GSON.fromJson(reader, StarterConfig::class.java)
reader.close()
return config
}
fun saveConfig() {
@@ -416,14 +379,4 @@ object Cobblemon {
exception.printStackTrace()
}
}
private fun registerArgumentTypes() {
this.implementation.registerCommandArgument(cobblemonResource("pokemon"), PokemonArgumentType::class, ConstantArgumentSerializer.of(PokemonArgumentType::pokemon))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_properties"), PokemonPropertiesArgumentType::class, ConstantArgumentSerializer.of(PokemonPropertiesArgumentType::properties))
this.implementation.registerCommandArgument(cobblemonResource("spawn_bucket"), SpawnBucketArgumentType::class, ConstantArgumentSerializer.of(SpawnBucketArgumentType::spawnBucket))
this.implementation.registerCommandArgument(cobblemonResource("move"), MoveArgumentType::class, ConstantArgumentSerializer.of(MoveArgumentType::move))
this.implementation.registerCommandArgument(cobblemonResource("party_slot"), PartySlotArgumentType::class, ConstantArgumentSerializer.of(PartySlotArgumentType::partySlot))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,26 +8,29 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.world.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.world.block.entity.PCBlockEntity
import dev.architectury.registry.registries.RegistrySupplier
import java.util.function.Supplier
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.util.registry.Registry
object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, RegistryKey<Registry<BlockEntityType<*>>>, BlockEntityType<*>>() {
override val registry: Registry<BlockEntityType<*>> = Registries.BLOCK_ENTITY_TYPE
override val registryKey: RegistryKey<Registry<BlockEntityType<*>>> = RegistryKeys.BLOCK_ENTITY_TYPE
@JvmField
val HEALING_MACHINE: BlockEntityType<HealingMachineBlockEntity> = this.create("healing_machine", BlockEntityType.Builder.create(::HealingMachineBlockEntity, CobblemonBlocks.HEALING_MACHINE).build(null))
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
object CobblemonBlockEntities : CompletableRegistry<BlockEntityType<*>>(Registry.BLOCK_ENTITY_TYPE_KEY) {
private fun <T : BlockEntityType<*>> register(name: String, blockEntityType: Supplier<T>) : RegistrySupplier<T> {
return queue(name, blockEntityType)
}
val HEALING_MACHINE = com.cobblemon.mod.common.CobblemonBlockEntities.register("healing_machine") {
BlockEntityType.Builder.create(
::HealingMachineBlockEntity,
CobblemonBlocks.HEALING_MACHINE.get()
).build(null)
}
val PC = com.cobblemon.mod.common.CobblemonBlockEntities.register("pc") {
BlockEntityType.Builder.create(
::PCBlockEntity,
CobblemonBlocks.PC.get()
).build(null)
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,243 +9,158 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.block.*
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.world.block.ApricornBlock
import com.cobblemon.mod.common.world.block.ApricornSaplingBlock
import com.cobblemon.mod.common.world.block.HealingMachineBlock
import com.cobblemon.mod.common.world.block.PCBlock
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.block.AbstractBlock
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.Blocks
import net.minecraft.block.DoorBlock
import net.minecraft.block.FenceBlock
import net.minecraft.block.FenceGateBlock
import net.minecraft.block.LeavesBlock
import net.minecraft.block.MapColor
import net.minecraft.block.Material
import net.minecraft.block.OreBlock
import net.minecraft.block.PillarBlock
import net.minecraft.block.PressurePlateBlock
import net.minecraft.block.SlabBlock
import net.minecraft.block.StairsBlock
import net.minecraft.block.TrapdoorBlock
import net.minecraft.block.WoodenButtonBlock
import net.minecraft.entity.EntityType
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.util.math.Direction
import net.minecraft.util.math.intprovider.UniformIntProvider
import net.minecraft.util.registry.Registry
@Suppress("SameParameterValue", "HasPlatformType", "MemberVisibilityCanBePrivate", "unused")
object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<Block>>, Block>() {
object CobblemonBlocks : CompletableRegistry<Block>(Registry.BLOCK_KEY) {
/**
* Evolution Ores
*/
override val registry: Registry<Block> = Registries.BLOCK
override val registryKey: RegistryKey<Registry<Block>> = RegistryKeys.BLOCK
val DAWN_STONE_ORE = this.evolutionStoneOre("dawn_stone_ore")
val DUSK_STONE_ORE = this.evolutionStoneOre("dusk_stone_ore")
val FIRE_STONE_ORE = this.evolutionStoneOre("fire_stone_ore")
val ICE_STONE_ORE = this.evolutionStoneOre("ice_stone_ore")
val LEAF_STONE_ORE = this.evolutionStoneOre("leaf_stone_ore")
val MOON_STONE_ORE = this.evolutionStoneOre("moon_stone_ore")
val DRIPSTONE_MOON_STONE_ORE = this.evolutionStoneOre("dripstone_moon_stone_ore")
val SHINY_STONE_ORE = this.evolutionStoneOre("shiny_stone_ore")
val SUN_STONE_ORE = this.evolutionStoneOre("sun_stone_ore")
val THUNDER_STONE_ORE = this.evolutionStoneOre("thunder_stone_ore")
val WATER_STONE_ORE = this.evolutionStoneOre("water_stone_ore")
val APRICORN_BLOCK_SET_TYPE = BlockSetType("apricorn")
val APRICORN_WOOD_TYPE = WoodType.register(WoodType("apricorn", APRICORN_BLOCK_SET_TYPE))
/**
* Deepslate separator
*/
// Evolution Ores
@JvmField
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore")
@JvmField
val DUSK_STONE_ORE = evolutionStoneOre("dusk_stone_ore")
@JvmField
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
@JvmField
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
@JvmField
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
@JvmField
val MOON_STONE_ORE = evolutionStoneOre("moon_stone_ore")
@JvmField
val DRIPSTONE_MOON_STONE_ORE = evolutionStoneOre("dripstone_moon_stone_ore")
@JvmField
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore")
@JvmField
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
@JvmField
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
@JvmField
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
@JvmField
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore")
@JvmField
val DEEPSLATE_DUSK_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dusk_stone_ore")
@JvmField
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore")
@JvmField
val DEEPSLATE_ICE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_ice_stone_ore")
@JvmField
val DEEPSLATE_LEAF_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_leaf_stone_ore")
@JvmField
val DEEPSLATE_MOON_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_moon_stone_ore")
@JvmField
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore")
@JvmField
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore")
@JvmField
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore")
@JvmField
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
// Apricorns
@JvmField
val APRICORN_LOG = log("apricorn_log", arg2 = MapColor.BROWN)
@JvmField
val STRIPPED_APRICORN_LOG = log("stripped_apricorn_log")
@JvmField
val APRICORN_WOOD = log("apricorn_wood")
@JvmField
val STRIPPED_APRICORN_WOOD = log("stripped_apricorn_wood")
@JvmField
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_LEAVES = leaves("apricorn_leaves")
@JvmField
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
@JvmField // Note At the time of 1.20.0 we don't need our own BlockSetType for Apricorn wood
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
/**
* Apricorns
*/
val APRICORN_LOG = queue("apricorn_log") {
log(
MapColor.DIRT_BROWN,
MapColor.BROWN
)
}
val STRIPPED_APRICORN_LOG = queue("stripped_apricorn_log") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
val APRICORN_WOOD = queue("apricorn_wood") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
val STRIPPED_APRICORN_WOOD = queue("stripped_apricorn_wood") {
log(
MapColor.DIRT_BROWN,
MapColor.DIRT_BROWN
)
}
val APRICORN_PLANKS = queue("apricorn_planks") { Block(AbstractBlock.Settings.of(Material.WOOD, MapColor.DIRT_BROWN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
val APRICORN_LEAVES = queue("apricorn_leaves") { com.cobblemon.mod.common.CobblemonBlocks.leaves(BlockSoundGroup.GRASS) }
val APRICORN_FENCE = queue("apricorn_fence") { FenceBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
val APRICORN_FENCE_GATE = queue("apricorn_fence_gate") { FenceGateBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
val APRICORN_BUTTON = queue("apricorn_button") { WoodenButtonBlock(AbstractBlock.Settings.of(Material.DECORATION).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD)) }
val APRICORN_PRESSURE_PLATE = queue("apricorn_pressure_plate") { PressurePlateBlock(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD)) }
// Tag was removed be sure to add it back when implemented
//val APRICORN_SIGN = queue("apricorn_sign") { StandingSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE) }
//val APRICORN_WALL_SIGN = queue("apricorn_wall_sign") { WallSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD).dropsLike(APRICORN_SIGN), APRICORN_WOOD_TYPE) }
@JvmField
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
@JvmField
val APRICORN_STAIRS = this.create("apricorn_stairs", StairsBlockInvoker.`cobblemon$create`(APRICORN_PLANKS.defaultState, AbstractBlock.Settings.copy(APRICORN_PLANKS)))
@JvmField
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
@JvmField
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
val APRICORN_SLAB = queue("apricorn_slab") { SlabBlock(AbstractBlock.Settings.of(Material.WOOD, MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)) }
val APRICORN_STAIRS = queue("apricorn_stairs") { StairsBlock(
APRICORN_PLANKS.get().defaultState, AbstractBlock.Settings.copy(
APRICORN_PLANKS.get())) }
val APRICORN_DOOR = queue("apricorn_door") { DoorBlock(AbstractBlock.Settings.of(Material.WOOD, APRICORN_PLANKS.get().defaultMapColor).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque()) }
val APRICORN_TRAPDOOR = queue("apricorn_trapdoor") { TrapdoorBlock(AbstractBlock.Settings.of(Material.WOOD, MapColor.OAK_TAN).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }) }
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
@JvmField
val BLACK_APRICORN_SAPLING = this.create("black_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLACK))
@JvmField
val BLUE_APRICORN_SAPLING = this.create("blue_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLUE))
@JvmField
val GREEN_APRICORN_SAPLING = this.create("green_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.GREEN))
@JvmField
val PINK_APRICORN_SAPLING = this.create("pink_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.PINK))
@JvmField
val RED_APRICORN_SAPLING = this.create("red_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.RED))
@JvmField
val WHITE_APRICORN_SAPLING = this.create("white_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.WHITE))
@JvmField
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
private val PLANT_PROPERTIES = AbstractBlock.Settings.of(Material.PLANT).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS)
val BLACK_APRICORN_SAPLING = queue("black_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLACK) }
val BLUE_APRICORN_SAPLING = queue("blue_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.BLUE) }
val GREEN_APRICORN_SAPLING = queue("green_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.GREEN) }
val PINK_APRICORN_SAPLING = queue("pink_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.PINK) }
val RED_APRICORN_SAPLING = queue("red_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.RED) }
val WHITE_APRICORN_SAPLING = queue("white_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.WHITE) }
val YELLOW_APRICORN_SAPLING = queue("yellow_apricorn_sapling") { ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW) }
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
val BLACK_APRICORN = registerApricornBlock("black_apricorn", Apricorn.BLACK)
val BLUE_APRICORN = registerApricornBlock("blue_apricorn", Apricorn.BLUE)
val GREEN_APRICORN = registerApricornBlock("green_apricorn", Apricorn.GREEN)
val PINK_APRICORN = registerApricornBlock("pink_apricorn", Apricorn.PINK)
val RED_APRICORN = registerApricornBlock("red_apricorn", Apricorn.RED)
val WHITE_APRICORN = registerApricornBlock("white_apricorn", Apricorn.WHITE)
val YELLOW_APRICORN = registerApricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
val BLUE_APRICORN = apricornBlock("blue_apricorn", Apricorn.BLUE)
@JvmField
val GREEN_APRICORN = apricornBlock("green_apricorn", Apricorn.GREEN)
@JvmField
val PINK_APRICORN = apricornBlock("pink_apricorn", Apricorn.PINK)
@JvmField
val RED_APRICORN = apricornBlock("red_apricorn", Apricorn.RED)
@JvmField
val WHITE_APRICORN = apricornBlock("white_apricorn", Apricorn.WHITE)
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
val HEALING_MACHINE = queue("healing_machine") { HealingMachineBlock(AbstractBlock.Settings.of(Material.METAL, MapColor.IRON_GRAY).sounds(BlockSoundGroup.METAL).strength(2f).nonOpaque()) }
val PC = queue("pc") { PCBlock(AbstractBlock.Settings.of(Material.METAL, MapColor.IRON_GRAY).sounds(BlockSoundGroup.METAL).strength(2F).nonOpaque()) }
@JvmField
val HEALING_MACHINE = create(
"healing_machine",
HealingMachineBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2f)
.nonOpaque()
.luminance { if (it.get(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 7 else 2 }
)
)
@JvmField
val PC = create(
"pc",
PCBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.strength(2F)
.nonOpaque()
.luminance { if ((it.get(PCBlock.ON) as Boolean) && (it.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }
)
)
@JvmField
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PASTURE = create(
"pasture",
PastureBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.BROWN)
.sounds(BlockSoundGroup.WOOD)
.strength(2F)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.luminance { if ((it.get(PastureBlock.ON) as Boolean) && (it.get(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 10 else 0 }
)
)
@JvmField
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(StatusEffects.LEVITATION, 10, AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().breakInstantly().sounds(BlockSoundGroup.GRASS).offset(AbstractBlock.OffsetType.XZ).pistonBehavior(PistonBehavior.DESTROY)))
@JvmField
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
*
* @return A map of all the blocks that can be stripped with an axe in the format of input - output.
*/
fun strippedBlocks(): Map<Block, Block> = mapOf(
APRICORN_WOOD to STRIPPED_APRICORN_WOOD,
APRICORN_LOG to STRIPPED_APRICORN_LOG
)
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(AbstractBlock.Settings.create().mapColor(apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn))
private fun registerApricornBlock(id: String, apricorn: Apricorn): RegistrySupplier<ApricornBlock> {
return queue(id) { ApricornBlock(AbstractBlock.Settings.of(Material.PLANT).ticksRandomly().strength(0.2f, 3.0f).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn) }
}
/**
* Helper method for creating logs
* copied over from Vanilla
*/
private fun log(name: String, arg: MapColor = MapColor.DIRT_BROWN, arg2: MapColor = MapColor.DIRT_BROWN): PillarBlock {
val block = BlocksInvoker.createLogBlock(arg, arg2)
return this.create(name, block)
private fun log(arg: MapColor, arg2: MapColor): PillarBlock {
return PillarBlock(AbstractBlock.Settings.of(Material.WOOD) { arg3: BlockState ->
if (arg3.get(PillarBlock.AXIS) === Direction.Axis.Y) arg else arg2
}.strength(2.0f).sounds(BlockSoundGroup.WOOD))
}
private fun evolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)))
private fun evolutionStoneOre(name: String) = this.queue(name) { OreBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)) }
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)))
private fun deepslateEvolutionStoneOre(name: String) = this.queue(name) { OreBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)) }
/**
* Helper method for creating leaves
* copied over from Vanilla
*/
private fun leaves(name: String): LeavesBlock {
val block = BlocksInvoker.createLeavesBlock(BlockSoundGroup.GRASS)
return this.create(name, block)
private fun leaves(sound: BlockSoundGroup): LeavesBlock {
return LeavesBlock(
AbstractBlock.Settings.of(Material.LEAVES).strength(0.2f).ticksRandomly().sounds(sound).nonOpaque()
.allowsSpawning { _, _, _, type -> type === EntityType.OCELOT || type === EntityType.PARROT }
.suffocates { _, _, _ -> false }
.blockVision { _, _, _ -> false })
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,34 +9,9 @@
package com.cobblemon.mod.common
import java.util.function.Supplier
import net.minecraft.block.Block
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.client.color.block.BlockColorProvider
import net.minecraft.client.color.item.ItemColorProvider
import net.minecraft.client.model.TexturedModelData
import net.minecraft.client.particle.ParticleFactory
import net.minecraft.client.particle.SpriteProvider
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.entity.model.EntityModelLayer
import net.minecraft.item.Item
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleType
import net.minecraft.resource.SynchronousResourceReloader
interface CobblemonClientImplementation {
fun registerLayer(modelLayer: EntityModelLayer, supplier: Supplier<TexturedModelData>)
fun <T : ParticleEffect> registerParticleFactory(
type: ParticleType<T>,
factory: (SpriteProvider) -> ParticleFactory<T>
)
fun registerBlockRenderType(layer: RenderLayer, vararg blocks: Block)
fun registerItemColors(provider: ItemColorProvider, vararg items: Item)
fun registerBlockColors(provider: BlockColorProvider, vararg blocks: Block)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<T>, factory: BlockEntityRendererFactory<T>)
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,7 +8,22 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.command.*
import com.cobblemon.mod.common.command.ChangeScaleAndSize
import com.cobblemon.mod.common.command.CheckSpawnsCommand
import com.cobblemon.mod.common.command.ClickTextCommand
import com.cobblemon.mod.common.command.FriendshipCommand
import com.cobblemon.mod.common.command.GetNBT
import com.cobblemon.mod.common.command.GivePokemon
import com.cobblemon.mod.common.command.HealPokemonCommand
import com.cobblemon.mod.common.command.LevelUp
import com.cobblemon.mod.common.command.OpenStarterScreenCommand
import com.cobblemon.mod.common.command.PokemonEditCommand
import com.cobblemon.mod.common.command.SpawnAllPokemon
import com.cobblemon.mod.common.command.SpawnPokemon
import com.cobblemon.mod.common.command.StopBattleCommand
import com.cobblemon.mod.common.command.TakePokemon
import com.cobblemon.mod.common.command.TeachCommand
import com.cobblemon.mod.common.command.TestCommand
import com.mojang.brigadier.CommandDispatcher
import net.minecraft.command.CommandRegistryAccess
import net.minecraft.server.command.CommandManager
@@ -20,9 +35,7 @@ object CobblemonCommands {
GivePokemon.register(dispatcher)
TakePokemon.register(dispatcher)
ChangeScaleAndSize.register(dispatcher)
ChangeWalkSpeed.register(dispatcher)
TestCommand.register(dispatcher)
ReloadShowdownCommand.register(dispatcher)
ClickTextCommand.register(dispatcher)
PokemonEditCommand.register(dispatcher)
TeachCommand.register(dispatcher)
@@ -34,16 +47,5 @@ object CobblemonCommands {
OpenStarterScreenCommand.register(dispatcher)
SpawnAllPokemon.register(dispatcher)
FriendshipCommand.register(dispatcher)
GiveAllPokemon.register(dispatcher)
HeldItemCommand.register(dispatcher, registry)
PcCommand.register(dispatcher)
SpawnPokemonFromPool.register(dispatcher)
PokeboxCommand.register(dispatcher)
TestStoreCommand.register(dispatcher)
QueryLearnsetCommand.register(dispatcher)
TestPcSlotCommand.register(dispatcher)
TestPartySlotCommand.register(dispatcher)
ClearPartyCommand.register(dispatcher)
PokemonRestartCommand.register(dispatcher)
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 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
import net.minecraft.util.registry.RegistryEntry
import net.minecraft.world.gen.feature.ConfiguredFeature
import net.minecraft.world.gen.feature.ConfiguredFeatures
import net.minecraft.world.gen.feature.SingleStateFeatureConfig
object CobblemonConfiguredFeatures {
lateinit var BLACK_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var BLUE_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var GREEN_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var PINK_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var RED_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var WHITE_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
lateinit var YELLOW_APRICORN_TREE: RegistryEntry<ConfiguredFeature<SingleStateFeatureConfig, *>>
fun register() {
BLACK_APRICORN_TREE = ConfiguredFeatures.register("black_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.BLACK_APRICORN.get().defaultState))
BLUE_APRICORN_TREE = ConfiguredFeatures.register("blue_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.BLUE_APRICORN.get().defaultState))
GREEN_APRICORN_TREE = ConfiguredFeatures.register("green_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.GREEN_APRICORN.get().defaultState))
PINK_APRICORN_TREE = ConfiguredFeatures.register("pink_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.PINK_APRICORN.get().defaultState))
RED_APRICORN_TREE = ConfiguredFeatures.register("red_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.RED_APRICORN.get().defaultState))
WHITE_APRICORN_TREE = ConfiguredFeatures.register("white_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.WHITE_APRICORN.get().defaultState))
YELLOW_APRICORN_TREE = ConfiguredFeatures.register("yellow_apricorn_tree", CobblemonFeatures.APRICORN_TREE_FEATURE.get(), SingleStateFeatureConfig(
CobblemonBlocks.YELLOW_APRICORN.get().defaultState))
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,45 +8,63 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.entity.EntityAttributeEvent
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import dev.architectury.registry.level.entity.EntityAttributeRegistry
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnGroup
import net.minecraft.entity.attribute.DefaultAttributeContainer
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.entity.attribute.EntityAttributes
import net.minecraft.util.registry.Registry
object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey<Registry<EntityType<*>>>, EntityType<*>>() {
object CobblemonEntities : CompletableRegistry<EntityType<*>>(Registry.ENTITY_TYPE_KEY) {
override fun register() {
super.register()
override val registry: Registry<EntityType<*>> = Registries.ENTITY_TYPE
override val registryKey: RegistryKey<Registry<EntityType<*>>> = RegistryKeys.ENTITY_TYPE
@JvmField
val POKEMON_KEY = cobblemonResource("pokemon")
@JvmField
val POKEMON: EntityType<PokemonEntity> = this.create(
POKEMON_KEY.path,
EntityType.Builder.create({ _, world -> PokemonEntity(world) }, SpawnGroup.CREATURE)
.build(POKEMON_KEY.toString())
)
@JvmField
val EMPTY_POKEBALL_KEY = cobblemonResource("empty_pokeball")
@JvmField
val EMPTY_POKEBALL: EntityType<EmptyPokeBallEntity> = this.create(
EMPTY_POKEBALL_KEY.path,
EntityType.Builder.create({ _, world -> EmptyPokeBallEntity(PokeBalls.POKE_BALL, world) }, SpawnGroup.MISC)
.build(EMPTY_POKEBALL_KEY.toString())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
EntityAttributeRegistry.register(
{ POKEMON.get() },
{
LivingEntity.createLivingAttributes()
.add(EntityAttributes.GENERIC_FOLLOW_RANGE)
.also { CobblemonEvents.ENTITY_ATTRIBUTE.post(EntityAttributeEvent(POKEMON.get(), it)) }
}
)
}
private fun <T : Entity> entity(
name: String,
entityTypeBuilder: EntityType.Builder<T>
): RegistrySupplier<EntityType<T>> {
return queue(name) { entityTypeBuilder.build(cobblemonResource(name).toString()) }
}
private fun <T : LivingEntity> livingEntity(
name: String,
entityTypeBuilder: EntityType.Builder<T>
): RegistrySupplier<EntityType<T>> {
return queue(name) { entityTypeBuilder.build(cobblemonResource("pokemon").toString()) }
}
val POKEMON = livingEntity(
name = "pokemon",
entityTypeBuilder = EntityType.Builder.create<PokemonEntity>(
{ _, world -> PokemonEntity(world) },
SpawnGroup.CREATURE
)
)
val EMPTY_POKEBALL = entity(
name = "empty_pokeball",
entityTypeBuilder = EntityType.Builder.create<EmptyPokeBallEntity>(
{ _, world -> EmptyPokeBallEntity(PokeBalls.POKE_BALL, world) },
SpawnGroup.MISC
)
)
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2022 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
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.world.feature.ApricornTreeFeature
import dev.architectury.registry.registries.RegistrySupplier
import java.util.function.Supplier
import net.minecraft.util.registry.Registry
import net.minecraft.world.gen.feature.Feature
import net.minecraft.world.gen.feature.SingleStateFeatureConfig
object CobblemonFeatures : CompletableRegistry<Feature<*>>(Registry.FEATURE_KEY) {
private fun <T : Feature<*>> register(name: String, feature: Supplier<T>) : RegistrySupplier<T> {
return queue(name, feature)
}
val APRICORN_TREE_FEATURE = register("apricorn_tree_feature") { ApricornTreeFeature(SingleStateFeatureConfig.CODEC) }
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,186 +8,19 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.mojang.brigadier.arguments.ArgumentType
import kotlin.reflect.KClass
import net.minecraft.advancement.criterion.Criterion
import net.minecraft.command.argument.serialize.ArgumentSerializer
import net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.ResourceReloader
import net.minecraft.resource.ResourceType
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.world.GameRules
import net.minecraft.world.biome.Biome
import net.minecraft.world.gen.GenerationStep
import net.minecraft.world.gen.feature.PlacedFeature
interface CobblemonImplementation {
val modAPI: ModAPI
/**
*
*/
val networkManager: NetworkManager
/**
* TODO
*
* @return
*/
fun environment(): Environment
/**
* TODO
*
* @param id
* @return
*/
fun isModInstalled(id: String): Boolean
/**
* TODO
*
*/
fun registerPermissionValidator()
/**
* TODO
*
*/
fun registerSoundEvents()
/**
* TODO
*
*/
fun registerItems()
/**
* TODO
*
*/
fun registerBlocks()
/**
* TODO
*
*/
fun registerEntityTypes()
/**
* TODO
*
*/
fun registerEntityAttributes()
/**
* TODO
*
*/
fun registerBlockEntityTypes()
/**
* TODO
*
*/
fun registerWorldGenFeatures()
fun registerParticles()
/**
* Add a feature to the current platform implementation.
*
* @param feature The [PlacedFeature] being added.
* @param step The [GenerationStep.Feature] of this feature.
* @param validTag The [TagKey] required by the [Biome] for this feature to generate in, if null all biomes are valid.
*/
fun addFeatureToWorldGen(feature: RegistryKey<PlacedFeature>, step: GenerationStep.Feature, validTag: TagKey<Biome>?)
/**
* TODO
*
* @param A
* @param T
* @param identifier
* @param argumentClass
* @param serializer
*/
fun <A : ArgumentType<*>, T : ArgumentSerializer.ArgumentTypeProperties<A>> registerCommandArgument(identifier: Identifier, argumentClass: KClass<A>, serializer: ArgumentSerializer<A, T>)
/**
* TODO
*
* @param T
* @param name
* @param category
* @param type
* @return
*/
fun <T : GameRules.Rule<T>> registerGameRule(name: String, category: GameRules.Category, type: GameRules.Type<T>): GameRules.Key<T>
/**
* TODO
*
* @param T
* @param criteria
* @return
*/
fun <T : Criterion<*>> registerCriteria(criteria: T): T
/**
* TODO
*
* @param identifier
* @param reloader
* @param type
* @param dependencies
*/
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
/**
* TODO
*
* @return
*/
fun server(): MinecraftServer?
}
enum class ModAPI {
FABRIC,
FORGE
}
interface NetworkDelegate {
interface NetworkManager {
fun registerClientBound()
fun registerServerBound()
fun <T: NetworkPacket<T>> createClientBound(identifier: Identifier, kClass: KClass<T>, encoder: (T, PacketByteBuf) -> Unit, decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>)
fun <T: NetworkPacket<T>> createServerBound(identifier: Identifier, kClass: KClass<T>, encoder: (T, PacketByteBuf) -> Unit, decoder: (PacketByteBuf) -> T, handler: ServerNetworkPacketHandler<T>)
fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket<*>)
fun sendPacketToServer(packet: NetworkPacket<*>)
fun <T : NetworkPacket<*>> asVanillaClientBound(packet: T): Packet<ClientPlayPacketListener>
}
enum class Environment {
CLIENT,
SERVER
}
fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket)
fun sendPacketToServer(packet: NetworkPacket)
fun <T : NetworkPacket> buildMessage(
packetClass: Class<T>,
toServer: Boolean
): CobblemonNetwork.PreparedMessage<T>
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,589 +8,179 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.api.pokeball.PokeBalls
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.MintBlock.MintType
import com.cobblemon.mod.common.item.*
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.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.item.ApricornItem
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.item.CobblemonItemGroups
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.item.interactive.CandyItem
import com.cobblemon.mod.common.item.interactive.LinkCableItem
import com.cobblemon.mod.common.item.interactive.VitaminItem
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.registry.CompletableRegistry
import dev.architectury.registry.registries.RegistrySupplier
import net.minecraft.block.Block
import net.minecraft.block.ComposterBlock
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.*
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.item.AliasedBlockItem
import net.minecraft.item.BlockItem
import net.minecraft.item.Item
import net.minecraft.item.ItemGroup
import net.minecraft.util.registry.Registry
@Suppress("unused")
object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<Item>>, Item>() {
override val registry: Registry<Item> = Registries.ITEM
override val registryKey: RegistryKey<Registry<Item>> = RegistryKeys.ITEM
object CobblemonItems : CompletableRegistry<Item>(Registry.ITEM_KEY) {
@JvmField
val pokeBalls = mutableListOf<PokeBallItem>()
@JvmField
val POKE_BALL = pokeBallItem(PokeBalls.POKE_BALL)
@JvmField
val CITRINE_BALL = pokeBallItem(PokeBalls.CITRINE_BALL)
@JvmField
val VERDANT_BALL = pokeBallItem(PokeBalls.VERDANT_BALL)
@JvmField
val AZURE_BALL = pokeBallItem(PokeBalls.AZURE_BALL)
@JvmField
val ROSEATE_BALL = pokeBallItem(PokeBalls.ROSEATE_BALL)
@JvmField
val SLATE_BALL = pokeBallItem(PokeBalls.SLATE_BALL)
@JvmField
val PREMIER_BALL = pokeBallItem(PokeBalls.PREMIER_BALL)
@JvmField
val GREAT_BALL = pokeBallItem(PokeBalls.GREAT_BALL)
@JvmField
val ULTRA_BALL = pokeBallItem(PokeBalls.ULTRA_BALL)
@JvmField
val SAFARI_BALL = pokeBallItem(PokeBalls.SAFARI_BALL)
@JvmField
val FAST_BALL = pokeBallItem(PokeBalls.FAST_BALL)
@JvmField
val LEVEL_BALL = pokeBallItem(PokeBalls.LEVEL_BALL)
@JvmField
val LURE_BALL = pokeBallItem(PokeBalls.LURE_BALL)
@JvmField
val HEAVY_BALL = pokeBallItem(PokeBalls.HEAVY_BALL)
@JvmField
val LOVE_BALL = pokeBallItem(PokeBalls.LOVE_BALL)
@JvmField
val FRIEND_BALL = pokeBallItem(PokeBalls.FRIEND_BALL)
@JvmField
val MOON_BALL = pokeBallItem(PokeBalls.MOON_BALL)
@JvmField
val SPORT_BALL = pokeBallItem(PokeBalls.SPORT_BALL)
@JvmField
val PARK_BALL = pokeBallItem(PokeBalls.PARK_BALL)
@JvmField
val NET_BALL = pokeBallItem(PokeBalls.NET_BALL)
@JvmField
val DIVE_BALL = pokeBallItem(PokeBalls.DIVE_BALL)
@JvmField
val NEST_BALL = pokeBallItem(PokeBalls.NEST_BALL)
@JvmField
val REPEAT_BALL = pokeBallItem(PokeBalls.REPEAT_BALL)
@JvmField
val TIMER_BALL = pokeBallItem(PokeBalls.TIMER_BALL)
@JvmField
val LUXURY_BALL = pokeBallItem(PokeBalls.LUXURY_BALL)
@JvmField
val DUSK_BALL = pokeBallItem(PokeBalls.DUSK_BALL)
@JvmField
val HEAL_BALL = pokeBallItem(PokeBalls.HEAL_BALL)
@JvmField
val QUICK_BALL = pokeBallItem(PokeBalls.QUICK_BALL)
@JvmField
val DREAM_BALL = pokeBallItem(PokeBalls.DREAM_BALL)
@JvmField
val BEAST_BALL = pokeBallItem(PokeBalls.BEAST_BALL)
@JvmField
val MASTER_BALL = pokeBallItem(PokeBalls.MASTER_BALL)
@JvmField
val CHERISH_BALL = pokeBallItem(PokeBalls.CHERISH_BALL)
private val pokeballs = mutableListOf<RegistrySupplier<PokeBallItem>>()
@JvmField
val VIVICHOKE = create("vivichoke", Item(Item.Settings()))
val POKE_BALL = pokeballItem(PokeBalls.POKE_BALL)
val CITRINE_BALL = pokeballItem(PokeBalls.CITRINE_BALL)
val VERDANT_BALL = pokeballItem(PokeBalls.VERDANT_BALL)
val AZURE_BALL = pokeballItem(PokeBalls.AZURE_BALL)
val ROSEATE_BALL = pokeballItem(PokeBalls.ROSEATE_BALL)
val SLATE_BALL = pokeballItem(PokeBalls.SLATE_BALL)
val PREMIER_BALL = pokeballItem(PokeBalls.PREMIER_BALL)
val GREAT_BALL = pokeballItem(PokeBalls.GREAT_BALL)
val ULTRA_BALL = pokeballItem(PokeBalls.ULTRA_BALL)
val SAFARI_BALL = pokeballItem(PokeBalls.SAFARI_BALL)
val FAST_BALL = pokeballItem(PokeBalls.FAST_BALL)
val LEVEL_BALL = pokeballItem(PokeBalls.LEVEL_BALL)
val LURE_BALL = pokeballItem(PokeBalls.LURE_BALL)
val HEAVY_BALL = pokeballItem(PokeBalls.HEAVY_BALL)
val LOVE_BALL = pokeballItem(PokeBalls.LOVE_BALL)
val FRIEND_BALL = pokeballItem(PokeBalls.FRIEND_BALL)
val MOON_BALL = pokeballItem(PokeBalls.MOON_BALL)
val SPORT_BALL = pokeballItem(PokeBalls.SPORT_BALL)
val PARK_BALL = pokeballItem(PokeBalls.PARK_BALL)
val NET_BALL = pokeballItem(PokeBalls.NET_BALL)
val DIVE_BALL = pokeballItem(PokeBalls.DIVE_BALL)
val NEST_BALL = pokeballItem(PokeBalls.NEST_BALL)
val REPEAT_BALL = pokeballItem(PokeBalls.REPEAT_BALL)
val TIMER_BALL = pokeballItem(PokeBalls.TIMER_BALL)
val LUXURY_BALL = pokeballItem(PokeBalls.LUXURY_BALL)
val DUSK_BALL = pokeballItem(PokeBalls.DUSK_BALL)
val HEAL_BALL = pokeballItem(PokeBalls.HEAL_BALL)
val QUICK_BALL = pokeballItem(PokeBalls.QUICK_BALL)
val DREAM_BALL = pokeballItem(PokeBalls.DREAM_BALL)
val BEAST_BALL = pokeballItem(PokeBalls.BEAST_BALL)
val MASTER_BALL = pokeballItem(PokeBalls.MASTER_BALL)
val CHERISH_BALL = pokeballItem(PokeBalls.CHERISH_BALL)
@JvmField
val VIVICHOKE_SEEDS = create("vivichoke_seeds", VivichokeItem(CobblemonBlocks.VIVICHOKE_SEEDS))
val RED_APRICORN = queue("red_apricorn") { ApricornItem(CobblemonBlocks.RED_APRICORN.get()) }
val YELLOW_APRICORN = queue("yellow_apricorn") { ApricornItem(CobblemonBlocks.YELLOW_APRICORN.get()) }
val GREEN_APRICORN = queue("green_apricorn") { ApricornItem(CobblemonBlocks.GREEN_APRICORN.get()) }
val BLUE_APRICORN = queue("blue_apricorn") { ApricornItem(CobblemonBlocks.BLUE_APRICORN.get()) }
val PINK_APRICORN = queue("pink_apricorn") { ApricornItem(CobblemonBlocks.PINK_APRICORN.get()) }
val BLACK_APRICORN = queue("black_apricorn") { ApricornItem(CobblemonBlocks.BLACK_APRICORN.get()) }
val WHITE_APRICORN = queue("white_apricorn") { ApricornItem(CobblemonBlocks.WHITE_APRICORN.get()) }
@JvmField
val RED_APRICORN = create("red_apricorn", ApricornItem(CobblemonBlocks.RED_APRICORN))
@JvmField
val YELLOW_APRICORN = create("yellow_apricorn", ApricornItem(CobblemonBlocks.YELLOW_APRICORN))
@JvmField
val GREEN_APRICORN = create("green_apricorn", ApricornItem(CobblemonBlocks.GREEN_APRICORN))
@JvmField
val BLUE_APRICORN = create("blue_apricorn", ApricornItem(CobblemonBlocks.BLUE_APRICORN))
@JvmField
val PINK_APRICORN = create("pink_apricorn", ApricornItem(CobblemonBlocks.PINK_APRICORN))
@JvmField
val BLACK_APRICORN = create("black_apricorn", ApricornItem(CobblemonBlocks.BLACK_APRICORN))
@JvmField
val WHITE_APRICORN = create("white_apricorn", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
val RED_APRICORN_SEED = queue("red_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.RED_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val YELLOW_APRICORN_SEED = queue("yellow_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val GREEN_APRICORN_SEED = queue("green_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.GREEN_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val BLUE_APRICORN_SEED = queue("blue_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.BLUE_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val PINK_APRICORN_SEED = queue("pink_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.PINK_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val BLACK_APRICORN_SEED = queue("black_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.BLACK_APRICORN_SAPLING.get(), ItemGroup.MISC) }
val WHITE_APRICORN_SEED = queue("white_apricorn_seed") { itemNameBlockItem(CobblemonBlocks.WHITE_APRICORN_SAPLING.get(), ItemGroup.MISC) }
@JvmField
val RED_APRICORN_SEED = create("red_apricorn_seed", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
@JvmField
val YELLOW_APRICORN_SEED = create("yellow_apricorn_seed", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
@JvmField
val GREEN_APRICORN_SEED = create("green_apricorn_seed", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
@JvmField
val BLUE_APRICORN_SEED = create("blue_apricorn_seed", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
@JvmField
val PINK_APRICORN_SEED = create("pink_apricorn_seed", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
@JvmField
val BLACK_APRICORN_SEED = create("black_apricorn_seed", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
@JvmField
val WHITE_APRICORN_SEED = create("white_apricorn_seed", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
val APRICORN_LOG = queue("apricorn_log") { blockItem(CobblemonBlocks.APRICORN_LOG.get(), ItemGroup.BUILDING_BLOCKS) }
val STRIPPED_APRICORN_LOG = queue("stripped_apricorn_log") { blockItem(CobblemonBlocks.STRIPPED_APRICORN_LOG.get(), ItemGroup.BUILDING_BLOCKS) }
val APRICORN_WOOD = queue("apricorn_wood") { blockItem(CobblemonBlocks.APRICORN_WOOD.get(), ItemGroup.BUILDING_BLOCKS) }
val STRIPPED_APRICORN_WOOD = queue("stripped_apricorn_wood") { blockItem(CobblemonBlocks.STRIPPED_APRICORN_WOOD.get(), ItemGroup.BUILDING_BLOCKS) }
val APRICORN_PLANKS = queue("apricorn_planks") { blockItem(CobblemonBlocks.APRICORN_PLANKS.get(), ItemGroup.BUILDING_BLOCKS) }
val APRICORN_LEAVES = queue("apricorn_leaves") { blockItem(CobblemonBlocks.APRICORN_LEAVES.get(), ItemGroup.BUILDING_BLOCKS) }
@JvmField
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
@JvmField
val STRIPPED_APRICORN_LOG = blockItem("stripped_apricorn_log", CobblemonBlocks.STRIPPED_APRICORN_LOG)
@JvmField
val APRICORN_WOOD = blockItem("apricorn_wood", CobblemonBlocks.APRICORN_WOOD)
@JvmField
val STRIPPED_APRICORN_WOOD = blockItem("stripped_apricorn_wood", CobblemonBlocks.STRIPPED_APRICORN_WOOD)
@JvmField
val APRICORN_PLANKS = blockItem("apricorn_planks", CobblemonBlocks.APRICORN_PLANKS)
@JvmField
val APRICORN_LEAVES = blockItem("apricorn_leaves", CobblemonBlocks.APRICORN_LEAVES).also {
val compostChance = ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE.getFloat(Items.OAK_LEAVES)
// Should always pass unless Mojang reworks leaves to no longer work in the Composter, in that case we already updated w.o doing anything
if (compostChance != ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE.defaultReturnValue()) {
ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE[it] = compostChance
}
}
val APRICORN_DOOR = queue("apricorn_door") { blockItem(CobblemonBlocks.APRICORN_DOOR.get(), ItemGroup.REDSTONE) }
val APRICORN_TRAPDOOR = queue("apricorn_trapdoor") { blockItem(CobblemonBlocks.APRICORN_TRAPDOOR.get(), ItemGroup.REDSTONE) }
val APRICORN_FENCE = queue("apricorn_fence") { blockItem(CobblemonBlocks.APRICORN_FENCE.get(), ItemGroup.DECORATIONS) }
val APRICORN_FENCE_GATE = queue("apricorn_fence_gate") { blockItem(CobblemonBlocks.APRICORN_FENCE_GATE.get(), ItemGroup.REDSTONE) }
val APRICORN_BUTTON = queue("apricorn_button") { blockItem(CobblemonBlocks.APRICORN_BUTTON.get(), ItemGroup.REDSTONE) }
val APRICORN_PRESSURE_PLATE = queue("apricorn_pressure_plate") { blockItem(CobblemonBlocks.APRICORN_PRESSURE_PLATE.get(), ItemGroup.REDSTONE) }
//val APRICORN_SIGN = queue("apricorn_sign", SignItem(Item.Properties().stacksTo(16).tab(CreativeModeTab.TAB_DECORATIONS), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
val APRICORN_SLAB = queue("apricorn_slab") { blockItem(CobblemonBlocks.APRICORN_SLAB.get(), ItemGroup.BUILDING_BLOCKS) }
val APRICORN_STAIRS = queue("apricorn_stairs") { blockItem(CobblemonBlocks.APRICORN_STAIRS.get(), ItemGroup.BUILDING_BLOCKS) }
@JvmField
val APRICORN_DOOR = blockItem("apricorn_door", CobblemonBlocks.APRICORN_DOOR)
@JvmField
val APRICORN_TRAPDOOR = blockItem("apricorn_trapdoor", CobblemonBlocks.APRICORN_TRAPDOOR)
@JvmField
val APRICORN_FENCE = blockItem("apricorn_fence", CobblemonBlocks.APRICORN_FENCE)
@JvmField
val APRICORN_FENCE_GATE = blockItem("apricorn_fence_gate", CobblemonBlocks.APRICORN_FENCE_GATE)
@JvmField
val APRICORN_BUTTON = blockItem("apricorn_button", CobblemonBlocks.APRICORN_BUTTON)
@JvmField
val APRICORN_PRESSURE_PLATE = blockItem("apricorn_pressure_plate", CobblemonBlocks.APRICORN_PRESSURE_PLATE)
//@JvmField
// val APRICORN_SIGN = create("apricorn_sign", SignItem(Item.Properties().stacksTo(16).tab(CreativeModeTab.TAB_DECORATIONS), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_SLAB = blockItem("apricorn_slab", CobblemonBlocks.APRICORN_SLAB)
@JvmField
val APRICORN_STAIRS = blockItem("apricorn_stairs", CobblemonBlocks.APRICORN_STAIRS)
@JvmField
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
val HEALING_MACHINE = queue("healing_machine") { blockItem(CobblemonBlocks.HEALING_MACHINE.get(), ItemGroup.REDSTONE) }
val PC = queue("pc") { blockItem(CobblemonBlocks.PC.get(), ItemGroup.REDSTONE) }
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
@JvmField val KINGS_ROCK = noSettingsItem("kings_rock")
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
@JvmField val UPGRADE = noSettingsItem("upgrade")
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
@JvmField val DEEP_SEA_SCALE = noSettingsItem("deep_sea_scale")
@JvmField val DEEP_SEA_TOOTH = noSettingsItem("deep_sea_tooth")
@JvmField val ELECTIRIZER = noSettingsItem("electirizer")
@JvmField val MAGMARIZER = noSettingsItem("magmarizer")
@JvmField val OVAL_STONE = noSettingsItem("oval_stone")
@JvmField val PROTECTOR = noSettingsItem("protector")
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
@JvmField val SACHET = noSettingsItem("sachet")
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
@JvmField val PEAT_BLOCK = noSettingsItem("peat_block")
@JvmField val RAZOR_CLAW = noSettingsItem("razor_claw")
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
// ToDo enable me when malicious armor goes in the game
//@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
val LINK_CABLE = queue("link_cable") { LinkCableItem() }
val KINGS_ROCK = queue("kings_rock") { evolutionItem() }
val METAL_COAT = queue("metal_coat") { evolutionItem() }
val BLACK_AUGURITE = queue("black_augurite") { evolutionItem() }
val PROTECTOR = queue("protector") { evolutionItem() }
val OVAL_STONE = queue("oval_stone") { evolutionItem() }
val DRAGON_SCALE = queue("dragon_scale") { evolutionItem() }
val ELECTIRIZER = queue("electirizer") { evolutionItem() }
val MAGMARIZER = queue("magmarizer") { evolutionItem() }
val UPGRADE = queue("upgrade") { evolutionItem() }
val DUBIOUS_DISC = queue("dubious_disc") { evolutionItem() }
// Medicine
@JvmField
val RARE_CANDY = candyItem("rare_candy") { _, pokemon -> pokemon.getExperienceToNextLevel() }
@JvmField
val EXPERIENCE_CANDY_XS = candyItem("exp_candy_xs") { _, _ -> CandyItem.DEFAULT_XS_CANDY_YIELD }
@JvmField
val EXPERIENCE_CANDY_S = candyItem("exp_candy_s") { _, _ -> CandyItem.DEFAULT_S_CANDY_YIELD }
@JvmField
val EXPERIENCE_CANDY_M = candyItem("exp_candy_m") { _, _ -> CandyItem.DEFAULT_M_CANDY_YIELD }
@JvmField
val EXPERIENCE_CANDY_L = candyItem("exp_candy_l") { _, _ -> CandyItem.DEFAULT_L_CANDY_YIELD }
@JvmField
val EXPERIENCE_CANDY_XL = candyItem("exp_candy_xl") { _, _ -> CandyItem.DEFAULT_XL_CANDY_YIELD }
@JvmField
val CALCIUM = create("calcium", VitaminItem(Stats.SPECIAL_ATTACK))
@JvmField
val CARBOS = create("carbos", VitaminItem(Stats.SPEED))
@JvmField
val HP_UP = create("hp_up", VitaminItem(Stats.HP))
@JvmField
val IRON = create("iron", VitaminItem(Stats.DEFENCE))
@JvmField
val PROTEIN = create("protein", VitaminItem(Stats.ATTACK))
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
@JvmField
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
@JvmField
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
@JvmField
val BRAISED_VIVICHOKE = create("braised_vivichoke", Item(Item.Settings().maxCount(1).food(FoodComponent.Builder().hunger(6).saturationModifier(0.6f).build())))
@JvmField
val VIVICHOKE_DIP = create("vivichoke_dip", StewItem(Item.Settings().maxCount(1)
.food(FoodComponent.Builder()
.hunger(10)
.saturationModifier(1.2F)
.statusEffect(StatusEffectInstance(StatusEffects.ABSORPTION, 600, 0), 1F)
.build()
)
))
@JvmField
val ENERGY_ROOT = create("energy_root", EnergyRootItem(CobblemonBlocks.ENERGY_ROOT, Item.Settings().food(FoodComponent.Builder().hunger(1).snack().saturationModifier(0.2f).build())))
@JvmField
val REVIVAL_HERB = create("revival_herb", RevivalHerbItem(CobblemonBlocks.REVIVAL_HERB))
@JvmField
val PEP_UP_FLOWER = blockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
@JvmField
val MEDICINAL_BREW = create("medicinal_brew", Item(Item.Settings()))
@JvmField
val REMEDY = create("remedy", RemedyItem(RemedyItem.NORMAL))
@JvmField
val FINE_REMEDY = create("fine_remedy", RemedyItem(RemedyItem.FINE))
@JvmField
val SUPERB_REMEDY = create("superb_remedy", RemedyItem(RemedyItem.SUPERB))
@JvmField
val POTION = create("potion", PotionItem(PotionType.POTION))
@JvmField
val SUPER_POTION = create("super_potion", PotionItem(PotionType.SUPER_POTION))
@JvmField
val HYPER_POTION = create("hyper_potion", PotionItem(PotionType.HYPER_POTION))
@JvmField
val MAX_POTION = create("max_potion", PotionItem(PotionType.MAX_POTION))
@JvmField
val FULL_RESTORE = create("full_restore", PotionItem(PotionType.FULL_RESTORE))
@JvmField
val HEAL_POWDER = create("heal_powder", HealPowderItem())
@JvmField
val LEEK_AND_POTATO_STEW = create("leek_and_potato_stew", StewItem(Item.Settings().food(FoodComponent.Builder().hunger(8).saturationModifier(0.6f).build()).maxCount(1)))
@JvmField
val REVIVE = create("revive", ReviveItem(max = false))
@JvmField
val MAX_REVIVE = create("max_revive", ReviveItem(max = true))
@JvmField
val PP_UP = create("pp_up", PPUpItem(1))
@JvmField
val PP_MAX = create("pp_max", PPUpItem(3))
@JvmField
val RED_MINT_SEEDS = blockItem("red_mint_seeds", MintType.RED.getCropBlock())
@JvmField
val RED_MINT_LEAF = create("red_mint_leaf", MintLeafItem(MintType.RED))
@JvmField
val BLUE_MINT_SEEDS = blockItem("blue_mint_seeds", MintType.BLUE.getCropBlock())
@JvmField
val BLUE_MINT_LEAF = create("blue_mint_leaf", MintLeafItem(MintType.BLUE))
@JvmField
val CYAN_MINT_SEEDS = blockItem("cyan_mint_seeds", MintType.CYAN.getCropBlock())
@JvmField
val CYAN_MINT_LEAF = create("cyan_mint_leaf", MintLeafItem(MintType.CYAN))
@JvmField
val PINK_MINT_SEEDS = blockItem("pink_mint_seeds", MintType.PINK.getCropBlock())
@JvmField
val PINK_MINT_LEAF = create("pink_mint_leaf", MintLeafItem(MintType.PINK))
@JvmField
val GREEN_MINT_SEEDS = blockItem("green_mint_seeds", MintType.GREEN.getCropBlock())
@JvmField
val GREEN_MINT_LEAF = create("green_mint_leaf", MintLeafItem(MintType.GREEN))
@JvmField
val WHITE_MINT_SEEDS = blockItem("white_mint_seeds", MintType.WHITE.getCropBlock())
@JvmField
val WHITE_MINT_LEAF = create("white_mint_leaf", MintLeafItem(MintType.WHITE))
@JvmField
val LONELY_MINT = create("lonely_mint", MintItem(Natures.LONELY))
@JvmField
val ADAMANT_MINT = create("adamant_mint", MintItem(Natures.ADAMANT))
@JvmField
val NAUGHTY_MINT = create("naughty_mint", MintItem(Natures.NAUGHTY))
@JvmField
val BRAVE_MINT = create("brave_mint", MintItem(Natures.BRAVE))
@JvmField
val BOLD_MINT = create("bold_mint", MintItem(Natures.BOLD))
@JvmField
val IMPISH_MINT = create("impish_mint", MintItem(Natures.IMPISH))
@JvmField
val LAX_MINT = create("lax_mint", MintItem(Natures.LAX))
@JvmField
val RELAXED_MINT = create("relaxed_mint", MintItem(Natures.RELAXED))
@JvmField
val MODEST_MINT = create("modest_mint", MintItem(Natures.MODEST))
@JvmField
val MILD_MINT = create("mild_mint", MintItem(Natures.MILD))
@JvmField
val RASH_MINT = create("rash_mint", MintItem(Natures.RASH))
@JvmField
val QUIET_MINT = create("quiet_mint", MintItem(Natures.QUIET))
@JvmField
val CALM_MINT = create("calm_mint", MintItem(Natures.CALM))
@JvmField
val GENTLE_MINT = create("gentle_mint", MintItem(Natures.GENTLE))
@JvmField
val CAREFUL_MINT = create("careful_mint", MintItem(Natures.CAREFUL))
@JvmField
val SASSY_MINT = create("sassy_mint", MintItem(Natures.SASSY))
@JvmField
val TIMID_MINT = create("timid_mint", MintItem(Natures.TIMID))
@JvmField
val HASTY_MINT = create("hasty_mint", MintItem(Natures.HASTY))
@JvmField
val JOLLY_MINT = create("jolly_mint", MintItem(Natures.JOLLY))
@JvmField
val NAIVE_MINT = create("naive_mint", MintItem(Natures.NAIVE))
@JvmField
val SERIOUS_MINT = create("serious_mint", MintItem(Natures.SERIOUS))
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY))
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK))
@JvmField val X_DEFENSE = create("x_${Stats.DEFENCE.identifier.path}", XStatItem(Stats.DEFENCE))
@JvmField val X_SP_ATK = create("x_${Stats.SPECIAL_ATTACK.identifier.path}", XStatItem(Stats.SPECIAL_ATTACK))
@JvmField val X_SP_DEF = create("x_${Stats.SPECIAL_DEFENCE.identifier.path}", XStatItem(Stats.SPECIAL_DEFENCE))
@JvmField val X_SPEED = create("x_${Stats.SPEED.identifier.path}", XStatItem(Stats.SPEED))
@JvmField val DIRE_HIT = create("dire_hit", DireHitItem())
@JvmField val GUARD_SPEC = create("guard_spec", GuardSpecItem())
@JvmField val BURN_HEAL = create("burn_heal", StatusCureItem("item.cobblemon.burn_heal", Statuses.BURN))
@JvmField val PARALYZE_HEAL = create("paralyze_heal", StatusCureItem("item.cobblemon.paralyze_heal", Statuses.PARALYSIS))
@JvmField val ICE_HEAL = create("ice_heal", StatusCureItem("item.cobblemon.ice_heal", Statuses.FROZEN))
@JvmField val ANTIDOTE = create("antidote", StatusCureItem("item.cobblemon.antidote", Statuses.POISON, Statuses.POISON_BADLY))
@JvmField val AWAKENING = create("awakening", StatusCureItem("item.cobblemon.awakening", Statuses.SLEEP))
@JvmField val FULL_HEAL = create("full_heal", StatusCureItem("item.cobblemon.full_heal"))
@JvmField val ETHER = create("ether", EtherItem(max = false))
@JvmField val MAX_ETHER = create("max_ether", EtherItem(max = true))
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
val RARE_CANDY = queue("rare_candy") { CandyItem { _, pokemon -> pokemon.getExperienceToNextLevel() } }
val EXPERIENCE_CANDY_XS = queue("exp_candy_xs") { CandyItem { _, _ -> CandyItem.DEFAULT_XS_CANDY_YIELD } }
val EXPERIENCE_CANDY_S = queue("exp_candy_s") { CandyItem { _, _ -> CandyItem.DEFAULT_S_CANDY_YIELD } }
val EXPERIENCE_CANDY_M = queue("exp_candy_m") { CandyItem { _, _ -> CandyItem.DEFAULT_M_CANDY_YIELD } }
val EXPERIENCE_CANDY_L = queue("exp_candy_l") { CandyItem { _, _ -> CandyItem.DEFAULT_L_CANDY_YIELD } }
val EXPERIENCE_CANDY_XL = queue("exp_candy_xl") { CandyItem { _, _ -> CandyItem.DEFAULT_XL_CANDY_YIELD } }
val CALCIUM = queue("calcium") { VitaminItem(Stats.SPECIAL_ATTACK) }
val CARBOS = queue("carbos") { VitaminItem(Stats.SPEED) }
val HP_UP = queue("hp_up") { VitaminItem(Stats.HP) }
val IRON = queue("iron") { VitaminItem(Stats.DEFENCE) }
val PROTEIN = queue("protein") { VitaminItem(Stats.ATTACK) }
val ZINC = queue("zinc") { VitaminItem(Stats.SPECIAL_DEFENCE) }
/**
* Evolution Ores and Stones
*/
@JvmField
val DAWN_STONE_ORE = blockItem("dawn_stone_ore", CobblemonBlocks.DAWN_STONE_ORE)
@JvmField
val DUSK_STONE_ORE = blockItem("dusk_stone_ore", CobblemonBlocks.DUSK_STONE_ORE)
@JvmField
val FIRE_STONE_ORE = blockItem("fire_stone_ore", CobblemonBlocks.FIRE_STONE_ORE)
@JvmField
val ICE_STONE_ORE = blockItem("ice_stone_ore", CobblemonBlocks.ICE_STONE_ORE)
@JvmField
val LEAF_STONE_ORE = blockItem("leaf_stone_ore", CobblemonBlocks.LEAF_STONE_ORE)
@JvmField
val MOON_STONE_ORE = blockItem("moon_stone_ore", CobblemonBlocks.MOON_STONE_ORE)
@JvmField
val SHINY_STONE_ORE = blockItem("shiny_stone_ore", CobblemonBlocks.SHINY_STONE_ORE)
@JvmField
val SUN_STONE_ORE = blockItem("sun_stone_ore", CobblemonBlocks.SUN_STONE_ORE)
@JvmField
val THUNDER_STONE_ORE = blockItem("thunder_stone_ore", CobblemonBlocks.THUNDER_STONE_ORE)
@JvmField
val WATER_STONE_ORE = blockItem("water_stone_ore", CobblemonBlocks.WATER_STONE_ORE)
@JvmField
val DEEPSLATE_DAWN_STONE_ORE = blockItem("deepslate_dawn_stone_ore", CobblemonBlocks.DEEPSLATE_DAWN_STONE_ORE)
@JvmField
val DEEPSLATE_DUSK_STONE_ORE = blockItem("deepslate_dusk_stone_ore", CobblemonBlocks.DEEPSLATE_DUSK_STONE_ORE)
@JvmField
val DEEPSLATE_FIRE_STONE_ORE = blockItem("deepslate_fire_stone_ore", CobblemonBlocks.DEEPSLATE_FIRE_STONE_ORE)
@JvmField
val DEEPSLATE_ICE_STONE_ORE = blockItem("deepslate_ice_stone_ore", CobblemonBlocks.DEEPSLATE_ICE_STONE_ORE)
@JvmField
val DEEPSLATE_LEAF_STONE_ORE = blockItem("deepslate_leaf_stone_ore", CobblemonBlocks.DEEPSLATE_LEAF_STONE_ORE)
@JvmField
val DEEPSLATE_MOON_STONE_ORE = blockItem("deepslate_moon_stone_ore", CobblemonBlocks.DEEPSLATE_MOON_STONE_ORE)
@JvmField
val DEEPSLATE_SHINY_STONE_ORE = blockItem("deepslate_shiny_stone_ore", CobblemonBlocks.DEEPSLATE_SHINY_STONE_ORE)
@JvmField
val DEEPSLATE_SUN_STONE_ORE = blockItem("deepslate_sun_stone_ore", CobblemonBlocks.DEEPSLATE_SUN_STONE_ORE)
@JvmField
val DEEPSLATE_THUNDER_STONE_ORE = blockItem("deepslate_thunder_stone_ore", CobblemonBlocks.DEEPSLATE_THUNDER_STONE_ORE)
@JvmField
val DEEPSLATE_WATER_STONE_ORE = blockItem("deepslate_water_stone_ore", CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE)
@JvmField
val DRIPSTONE_MOON_STONE_ORE = blockItem("dripstone_moon_stone_ore", CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE)
@JvmField
val DAWN_STONE = noSettingsItem("dawn_stone")
@JvmField
val DUSK_STONE = noSettingsItem("dusk_stone")
@JvmField
val FIRE_STONE = noSettingsItem("fire_stone")
@JvmField
val ICE_STONE = noSettingsItem("ice_stone")
@JvmField
val LEAF_STONE = noSettingsItem("leaf_stone")
@JvmField
val MOON_STONE = noSettingsItem("moon_stone")
@JvmField
val SHINY_STONE = noSettingsItem("shiny_stone")
@JvmField
val SUN_STONE = noSettingsItem("sun_stone")
@JvmField
val THUNDER_STONE = noSettingsItem("thunder_stone")
@JvmField
val WATER_STONE = noSettingsItem("water_stone")
val DAWN_STONE_ORE = queue("dawn_stone_ore") { blockItem(CobblemonBlocks.DAWN_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DUSK_STONE_ORE = queue("dusk_stone_ore") { blockItem(CobblemonBlocks.DUSK_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val FIRE_STONE_ORE = queue("fire_stone_ore") { blockItem(CobblemonBlocks.FIRE_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val ICE_STONE_ORE = queue("ice_stone_ore") { blockItem(CobblemonBlocks.ICE_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val LEAF_STONE_ORE = queue("leaf_stone_ore") { blockItem(CobblemonBlocks.LEAF_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val MOON_STONE_ORE = queue("moon_stone_ore") { blockItem(CobblemonBlocks.MOON_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val SHINY_STONE_ORE = queue("shiny_stone_ore") { blockItem(CobblemonBlocks.SHINY_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val SUN_STONE_ORE = queue("sun_stone_ore") { blockItem(CobblemonBlocks.SUN_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val THUNDER_STONE_ORE = queue("thunder_stone_ore") { blockItem(CobblemonBlocks.THUNDER_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val WATER_STONE_ORE = queue("water_stone_ore") { blockItem(CobblemonBlocks.WATER_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_DAWN_STONE_ORE = queue("deepslate_dawn_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_DAWN_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_DUSK_STONE_ORE = queue("deepslate_dusk_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_DUSK_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_FIRE_STONE_ORE = queue("deepslate_fire_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_FIRE_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_ICE_STONE_ORE = queue("deepslate_ice_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_ICE_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_LEAF_STONE_ORE = queue("deepslate_leaf_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_LEAF_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_MOON_STONE_ORE = queue("deepslate_moon_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_MOON_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_SHINY_STONE_ORE = queue("deepslate_shiny_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_SHINY_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_SUN_STONE_ORE = queue("deepslate_sun_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_SUN_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_THUNDER_STONE_ORE = queue("deepslate_thunder_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_THUNDER_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DEEPSLATE_WATER_STONE_ORE = queue("deepslate_water_stone_ore") { blockItem(CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DRIPSTONE_MOON_STONE_ORE = queue("dripstone_moon_stone_ore") { blockItem(CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE.get(), ItemGroup.BUILDING_BLOCKS) }
val DAWN_STONE = queue("dawn_stone") { evolutionItem() }
val DUSK_STONE = queue("dusk_stone") { evolutionItem() }
val FIRE_STONE = queue("fire_stone") { evolutionItem() }
val ICE_STONE = queue("ice_stone") { evolutionItem() }
val LEAF_STONE = queue("leaf_stone") { evolutionItem() }
val MOON_STONE = queue("moon_stone") { evolutionItem() }
val SHINY_STONE = queue("shiny_stone") { evolutionItem() }
val SUN_STONE = queue("sun_stone") { evolutionItem() }
val THUNDER_STONE = queue("thunder_stone") { evolutionItem() }
val WATER_STONE = queue("water_stone") { evolutionItem() }
// Held Items
@JvmField
val ASSAULT_VEST = heldItem("assault_vest")
@JvmField
val BIG_ROOT = blockItem("big_root", CobblemonBlocks.BIG_ROOT)
@JvmField
val BLACK_BELT = heldItem("black_belt")
@JvmField
val BLACK_GLASSES = heldItem("black_glasses")
@JvmField
val BLACK_SLUDGE = heldItem("black_sludge")
@JvmField
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
@JvmField
val CHOICE_BAND = heldItem("choice_band")
@JvmField
val CHOICE_SCARF = heldItem("choice_scarf")
@JvmField
val CHOICE_SPECS = heldItem("choice_specs")
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EXP_SHARE = heldItem("exp_share")
@JvmField
val FOCUS_BAND = heldItem("focus_band")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val LEFTOVERS = heldItem("leftovers")
@JvmField
val LIGHT_CLAY = heldItem("light_clay")
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
@JvmField
val MAGNET = heldItem("magnet")
@JvmField
val MIRACLE_SEED = heldItem("miracle_seed")
@JvmField
val MUSCLE_BAND = heldItem("muscle_band")
@JvmField
val MYSTIC_WATER = heldItem("mystic_water")
@JvmField
val NEVER_MELT_ICE = heldItem("never_melt_ice")
@JvmField
val POISON_BARB = heldItem("poison_barb")
@JvmField
val QUICK_CLAW = heldItem("quick_claw")
@JvmField
val ROCKY_HELMET = heldItem("rocky_helmet")
@JvmField
val SAFETY_GOGGLES = heldItem("safety_goggles")
@JvmField
val SHARP_BEAK = heldItem("sharp_beak")
@JvmField
val SILK_SCARF = heldItem("silk_scarf")
@JvmField
val SILVER_POWDER = heldItem("silver_powder")
@JvmField
val SOFT_SAND = heldItem("soft_sand")
@JvmField
val SPELL_TAG = heldItem("spell_tag")
@JvmField
val TWISTED_SPOON = heldItem("twisted_spoon")
@JvmField
val WISE_GLASSES = heldItem("wise_glasses")
@JvmField
val MENTAL_HERB = heldItem("mental_herb")
@JvmField
val MIRROR_HERB = heldItem("mirror_herb")
@JvmField
val POWER_HERB = heldItem("power_herb")
@JvmField
val WHITE_HERB = heldItem("white_herb")
@JvmField
val BRIGHT_POWDER = heldItem("bright_powder")
@JvmField
val METAL_POWDER = heldItem("metal_powder")
@JvmField
val QUICK_POWDER = heldItem("quick_powder")
@JvmField
val DESTINY_KNOT = heldItem("destiny_knot")
@JvmField
val EVERSTONE = heldItem("everstone")
fun pokeballs(): List<RegistrySupplier<PokeBallItem>> = this.pokeballs
// Mulch
@JvmField
val MULCH_BASE = noSettingsItem("mulch_base")
@JvmField
val COARSE_MULCH = mulchItem("coarse_mulch", MulchVariant.COARSE)
@JvmField
val GROWTH_MULCH = mulchItem("growth_mulch", MulchVariant.GROWTH)
@JvmField
val HUMID_MULCH = mulchItem("humid_mulch", MulchVariant.HUMID)
@JvmField
val LOAMY_MULCH = mulchItem("loamy_mulch", MulchVariant.LOAMY)
@JvmField
val PEAT_MULCH = mulchItem("peat_mulch", MulchVariant.PEAT)
@JvmField
val RICH_MULCH = mulchItem("rich_mulch", MulchVariant.RICH)
@JvmField
val SANDY_MULCH = mulchItem("sandy_mulch", MulchVariant.SANDY)
@JvmField
val SURPRISE_MULCH = mulchItem("surprise_mulch", MulchVariant.SURPRISE)
// Misc
@JvmField
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
private fun noSettingsItem(name: String): CobblemonItem = this.create(name, CobblemonItem(Item.Settings()))
private fun mulchItem(name: String, mulchVariant: MulchVariant): MulchItem = this.create(name, MulchItem(mulchVariant))
private fun pokeBallItem(pokeBall: PokeBall): PokeBallItem {
val item = create(pokeBall.name.path, PokeBallItem(pokeBall))
pokeBall.item = item
pokeBalls.add(item)
return item
private fun blockItem(block: Block, tab: ItemGroup) : BlockItem {
return BlockItem(block, Item.Settings().group(tab))
}
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
private fun itemNameBlockItem(block: Block, tab: ItemGroup) : BlockItem {
return AliasedBlockItem(block, Item.Settings().group(tab))
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Settings()).also {
if (remappedName != null) {
CobblemonHeldItemManager.registerRemap(it, remappedName)
}
}
)
private fun evolutionItem(): CobblemonItem {
return CobblemonItem(Item.Settings().group(CobblemonItemGroups.EVOLUTION_ITEM_GROUP))
}
private fun pokeballItem(pokeBall: PokeBall): RegistrySupplier<PokeBallItem> {
val supplier = this.queue(pokeBall.name.path) { PokeBallItem(pokeBall) }
pokeBall.itemSupplier = supplier
this.pokeballs.add(supplier)
return supplier
}
}
@@ -1,40 +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
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.mechanics.RemediesMechanic
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object CobblemonMechanics : DataRegistry {
override val id: Identifier = cobblemonResource("mechanics")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<CobblemonMechanics>()
val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.create()
var remedies = RemediesMechanic()
override fun sync(player: ServerPlayerEntity) {}
override fun reload(manager: ResourceManager) {
manager.getResourceOrThrow(cobblemonResource("mechanics/remedies.json")).inputStream.use {
remedies = gson.fromJson(it.reader(), RemediesMechanic::class.java)
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,72 +8,50 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.net.MessageBuiltEvent
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
import com.cobblemon.mod.common.client.net.sound.PokemonCryHandler
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
import com.cobblemon.mod.common.client.net.storage.RemoveClientPokemonHandler
import com.cobblemon.mod.common.client.net.storage.SwapClientPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.InitializePartyHandler
import com.cobblemon.mod.common.client.net.storage.party.MoveClientPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
import com.cobblemon.mod.common.client.net.storage.pc.ClosePCHandler
import com.cobblemon.mod.common.client.net.storage.pc.InitializePCHandler
import com.cobblemon.mod.common.client.net.storage.pc.MoveClientPCPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.OpenPCHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCBoxPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCPokemonHandler
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.net.PacketHandler
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyCaptureResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureShakePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleCaptureStartPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleFaintPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleInitializePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleSetTeamPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwitchPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleUpdateTeamPokemonPacket
import com.cobblemon.mod.common.net.messages.client.battle.ChallengeNotificationPacket
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
import com.cobblemon.mod.common.net.messages.client.pokemon.update.AbilityUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.AspectsUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.BenchedMovesUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.CaughtBallUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.EVsUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ExperienceUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.FriendshipUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.GenderUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.HealthUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.IVsUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.MoveSetUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.NatureUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.PokemonStateUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ShinyUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.SpeciesUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.StatusUpdatePacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.net.messages.client.sound.PokemonCryPacket
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.storage.RemoveClientPokemonPacket
@@ -88,15 +66,6 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokem
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
@@ -104,17 +73,6 @@ import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
@@ -126,284 +84,174 @@ import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePCPokemonToPa
import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonToPCPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
import com.cobblemon.mod.common.net.serverhandling.storage.RequestMoveSwapHandler
import com.cobblemon.mod.common.net.serverhandling.storage.SendOutPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.SwapPCPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePCPokemonToPartyHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonToPCHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.util.server
import kotlin.reflect.KClass
import net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import com.cobblemon.mod.common.util.getServer
import java.util.concurrent.CompletableFuture
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
/**
* Registers Cobblemon network packets.
* Registers Cobblemon packets. Packet handlers are set up on handling the [MessageBuiltEvent] dispatched from here.
*
* This class also contains short functions for dispatching our packets to a player, all players, or to the entire server.
*
* @author Hiroku, Licious
* @author Hiroku
* @since November 27th, 2021
*/
object CobblemonNetwork : NetworkManager {
object CobblemonNetwork {
const val PROTOCOL_VERSION = "1"
fun ServerPlayerEntity.sendPacket(packet: NetworkPacket<*>) = sendPacketToPlayer(this, packet)
fun sendToServer(packet: NetworkPacket<*>) = this.sendPacketToServer(packet)
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerManager.playerList, packet)
fun sendPacketToPlayers(players: Iterable<ServerPlayerEntity>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
var clientHandlersRegistered = CompletableFuture<Unit>()
var serverHandlersRegistered = CompletableFuture<Unit>()
init {
clientHandlersRegistered.runAfterBoth(serverHandlersRegistered) { register() }
}
lateinit var networkDelegate: NetworkDelegate
fun ServerPlayerEntity.sendPacket(packet: NetworkPacket) = sendToPlayer(this, packet)
fun sendToPlayer(player: ServerPlayerEntity, packet: NetworkPacket) = networkDelegate.sendPacketToPlayer(player, packet)
fun sendToServer(packet: NetworkPacket) = networkDelegate.sendPacketToServer(packet)
fun sendToAllPlayers(packet: NetworkPacket) = sendToPlayers(getServer()!!.playerManager.playerList, packet)
fun sendToPlayers(players: Iterable<ServerPlayerEntity>, packet: NetworkPacket) = players.forEach { sendToPlayer(it, packet) }
interface PreparedMessage<T : NetworkPacket> {
fun registerMessage()
fun registerHandler(handler: PacketHandler<T>)
}
interface NetworkContext {
val player: ServerPlayerEntity?
}
fun register() {
// Don't forget to register handlers in either ClientPacketRegistrar or ServerPacketRegistrar!
/**
* Client Packets
*/
override fun registerClientBound() {
// Pokemon Update Packets
this.createClientBound(FriendshipUpdatePacket.ID, FriendshipUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(MoveSetUpdatePacket.ID, MoveSetUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(NatureUpdatePacket.ID, NatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ShinyUpdatePacket.ID, ShinyUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesUpdatePacket.ID, SpeciesUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(NicknameUpdatePacket.ID, NicknameUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(HealthUpdatePacket.ID, HealthUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ExperienceUpdatePacket.ID, ExperienceUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(StatusUpdatePacket.ID, StatusUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(CaughtBallUpdatePacket.ID, CaughtBallUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(BenchedMovesUpdatePacket.ID, BenchedMovesUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(GenderUpdatePacket.ID, GenderUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(AspectsUpdatePacket.ID, AspectsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(AbilityUpdatePacket.ID, AbilityUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(EVsUpdatePacket.ID, EVsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(IVsUpdatePacket.ID, IVsUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(HeldItemUpdatePacket.ID, HeldItemUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
buildClientMessage<FriendshipUpdatePacket>()
buildClientMessage<MoveSetUpdatePacket>()
buildClientMessage<NatureUpdatePacket>()
buildClientMessage<ShinyUpdatePacket>()
buildClientMessage<SpeciesUpdatePacket>()
buildClientMessage<HealthUpdatePacket>()
buildClientMessage<ExperienceUpdatePacket>()
buildClientMessage<StatusUpdatePacket>()
buildClientMessage<CaughtBallUpdatePacket>()
buildClientMessage<BenchedMovesUpdatePacket>()
buildClientMessage<GenderUpdatePacket>()
buildClientMessage<AspectsUpdatePacket>()
buildClientMessage<AbilityUpdatePacket>()
buildClientMessage<EVsUpdatePacket>()
buildClientMessage<IVsUpdatePacket>()
// Evolution start
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(ClearEvolutionsPacket.ID, ClearEvolutionsPacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(RemoveEvolutionPacket.ID, RemoveEvolutionPacket::decode, PokemonUpdatePacketHandler())
buildClientMessage<AddEvolutionPacket>()
buildClientMessage<ClearEvolutionsPacket>()
buildClientMessage<RemoveEvolutionPacket>()
// Evolution End
buildClientMessage<PokemonStateUpdatePacket>()
// Storage Packets
buildClientMessage<InitializePartyPacket>()
buildClientMessage<SetPartyPokemonPacket>()
buildClientMessage<MoveClientPartyPokemonPacket>()
buildClientMessage<SetPartyReferencePacket>()
buildClientMessage<InitializePCPacket>()
buildClientMessage<MoveClientPCPokemonPacket>()
buildClientMessage<SetPCBoxPokemonPacket>()
buildClientMessage<SetPCPokemonPacket>()
buildClientMessage<OpenPCPacket>()
buildClientMessage<ClosePCPacket>()
buildClientMessage<SwapClientPokemonPacket>()
buildClientMessage<RemoveClientPokemonPacket>()
// UI Packets
buildClientMessage<SummaryUIPacket>()
// Starter packets
buildClientMessage<OpenStarterUIPacket>()
buildClientMessage<SetClientPlayerDataPacket>()
// Battle packets
buildClientMessage<BattleEndPacket>()
buildClientMessage<BattleInitializePacket>()
buildClientMessage<BattleQueueRequestPacket>()
buildClientMessage<BattleFaintPacket>()
buildClientMessage<BattleMakeChoicePacket>()
buildClientMessage<BattleHealthChangePacket>()
buildClientMessage<BattleSetTeamPokemonPacket>()
buildClientMessage<BattleSwitchPokemonPacket>()
buildClientMessage<BattleMessagePacket>()
buildClientMessage<BattleCaptureStartPacket>()
buildClientMessage<BattleCaptureEndPacket>()
buildClientMessage<BattleCaptureShakePacket>()
buildClientMessage<BattleApplyCaptureResponsePacket>()
buildClientMessage<ChallengeNotificationPacket>()
buildClientMessage<BattleUpdateTeamPokemonPacket>()
buildClientMessage<BattlePersistentStatusPacket>()
// Settings packets
buildClientMessage<ServerSettingsPacket>()
// Data registries
buildClientMessage<AbilityRegistrySyncPacket>()
buildClientMessage<MovesRegistrySyncPacket>()
buildClientMessage<SpeciesRegistrySyncPacket>()
buildClientMessage<PropertiesCompletionRegistrySyncPacket>()
/**
* Server Packets
*/
// Pokemon Update Packets
// Evolution start
buildServerMessage<AcceptEvolutionPacket>()
// Evolution End
// Storage Packets
this.createClientBound(InitializePartyPacket.ID, InitializePartyPacket::decode, InitializePartyHandler)
this.createClientBound(SetPartyPokemonPacket.ID, SetPartyPokemonPacket::decode, SetPartyPokemonHandler)
this.createClientBound(MoveClientPartyPokemonPacket.ID, MoveClientPartyPokemonPacket::decode, MoveClientPartyPokemonHandler)
this.createClientBound(SetPartyReferencePacket.ID, SetPartyReferencePacket::decode, SetPartyReferenceHandler)
buildServerMessage<SendOutPokemonPacket>()
buildServerMessage<RequestMoveSwapPacket>()
buildServerMessage<BenchMovePacket>()
buildServerMessage<BattleChallengePacket>()
this.createClientBound(InitializePCPacket.ID, InitializePCPacket::decode, InitializePCHandler)
this.createClientBound(MoveClientPCPokemonPacket.ID, MoveClientPCPokemonPacket::decode, MoveClientPCPokemonHandler)
this.createClientBound(SetPCBoxPokemonPacket.ID, SetPCBoxPokemonPacket::decode, SetPCBoxPokemonHandler)
this.createClientBound(SetPCPokemonPacket.ID, SetPCPokemonPacket::decode, SetPCPokemonHandler)
this.createClientBound(OpenPCPacket.ID, OpenPCPacket::decode, OpenPCHandler)
this.createClientBound(ClosePCPacket.ID, ClosePCPacket::decode, ClosePCHandler)
this.createClientBound(SwapClientPokemonPacket.ID, SwapClientPokemonPacket::decode, SwapClientPokemonHandler)
this.createClientBound(RemoveClientPokemonPacket.ID, RemoveClientPokemonPacket::decode, RemoveClientPokemonHandler)
// UI Packets
this.createClientBound(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler)
this.createClientBound(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler)
buildServerMessage<MovePCPokemonToPartyPacket>()
buildServerMessage<MovePartyPokemonToPCPacket>()
buildServerMessage<ReleasePartyPokemonPacket>()
buildServerMessage<ReleasePCPokemonPacket>()
// Starter packets
this.createClientBound(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler)
this.createClientBound(SetClientPlayerDataPacket.ID, SetClientPlayerDataPacket::decode, SetClientPlayerDataHandler)
buildServerMessage<SelectStarterPacket>()
buildServerMessage<RequestStarterScreenPacket>()
buildServerMessage<SwapPCPokemonPacket>()
buildServerMessage<SwapPartyPokemonPacket>()
buildServerMessage<MovePCPokemonPacket>()
buildServerMessage<MovePartyPokemonPacket>()
buildServerMessage<SwapPCPartyPokemonPacket>()
// Battle packets
this.createClientBound(BattleEndPacket.ID, BattleEndPacket::decode, BattleEndHandler)
this.createClientBound(BattleInitializePacket.ID, BattleInitializePacket::decode, BattleInitializeHandler)
this.createClientBound(BattleQueueRequestPacket.ID, BattleQueueRequestPacket::decode, BattleQueueRequestHandler)
this.createClientBound(BattleFaintPacket.ID, BattleFaintPacket::decode, BattleFaintHandler)
this.createClientBound(BattleMakeChoicePacket.ID, BattleMakeChoicePacket::decode, BattleMakeChoiceHandler)
this.createClientBound(BattleHealthChangePacket.ID, BattleHealthChangePacket::decode, BattleHealthChangeHandler)
this.createClientBound(BattleSetTeamPokemonPacket.ID, BattleSetTeamPokemonPacket::decode, BattleSetTeamPokemonHandler)
this.createClientBound(BattleSwitchPokemonPacket.ID, BattleSwitchPokemonPacket::decode, BattleSwitchPokemonHandler)
this.createClientBound(BattleMessagePacket.ID, BattleMessagePacket::decode, BattleMessageHandler)
this.createClientBound(BattleCaptureStartPacket.ID, BattleCaptureStartPacket::decode, BattleCaptureStartHandler)
this.createClientBound(BattleCaptureEndPacket.ID, BattleCaptureEndPacket::decode, BattleCaptureEndHandler)
this.createClientBound(BattleCaptureShakePacket.ID, BattleCaptureShakePacket::decode, BattleCaptureShakeHandler)
this.createClientBound(BattleApplyPassResponsePacket.ID, BattleApplyPassResponsePacket::decode, BattleApplyPassResponseHandler)
this.createClientBound(BattleChallengeNotificationPacket.ID, BattleChallengeNotificationPacket::decode, BattleChallengeNotificationHandler)
this.createClientBound(BattleUpdateTeamPokemonPacket.ID, BattleUpdateTeamPokemonPacket::decode, BattleUpdateTeamPokemonHandler)
this.createClientBound(BattlePersistentStatusPacket.ID, BattlePersistentStatusPacket::decode, BattlePersistentStatusHandler)
this.createClientBound(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler)
this.createClientBound(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler)
this.createClientBound(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler)
// Settings packets
this.createClientBound(ServerSettingsPacket.ID, ServerSettingsPacket::decode, ServerSettingsPacketHandler)
// Data registries
this.createClientBound(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
// Effects
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
// Hax
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
// Trade packets
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
this.createClientBound(TradeCancelledPacket.ID, TradeCancelledPacket::decode, TradeCancelledHandler)
this.createClientBound(TradeCompletedPacket.ID, TradeCompletedPacket::decode, TradeCompletedHandler)
this.createClientBound(TradeUpdatedPacket.ID, TradeUpdatedPacket::decode, TradeUpdatedHandler)
this.createClientBound(TradeOfferNotificationPacket.ID, TradeOfferNotificationPacket::decode, TradeOfferNotificationHandler)
this.createClientBound(TradeOfferExpiredPacket.ID, TradeOfferExpiredPacket::decode, TradeOfferExpiredHandler)
this.createClientBound(TradeStartedPacket.ID, TradeStartedPacket::decode, TradeStartedHandler)
// Pasture
this.createClientBound(OpenPasturePacket.ID, OpenPasturePacket::decode, OpenPastureHandler)
this.createClientBound(ClosePasturePacket.ID, ClosePasturePacket::decode, ClosePastureHandler)
this.createClientBound(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler)
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
// Behaviours
this.createClientBound(PokemonCryPacket.ID, PokemonCryPacket::decode, PokemonCryHandler)
// Move select packets
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
// Party select packets
this.createClientBound(OpenPartyCallbackPacket.ID, OpenPartyCallbackPacket::decode, OpenPartyCallbackHandler)
// Party move select packets
this.createClientBound(OpenPartyMoveCallbackPacket.ID, OpenPartyMoveCallbackPacket::decode, OpenPartyMoveCallbackHandler)
buildServerMessage<BattleSelectActionsPacket>()
}
override fun registerServerBound() {
// Pokemon Update Packets
this.createServerBound(SetNicknamePacket.ID, SetNicknamePacket::decode, SetNicknameHandler)
private inline fun <reified P : NetworkPacket> buildClientMessage() =
buildMessage<P>(toServer = false)
private inline fun <reified P : NetworkPacket> buildServerMessage() =
buildMessage<P>(toServer = true)
// Evolution Packets
this.createServerBound(AcceptEvolutionPacket.ID, AcceptEvolutionPacket::decode, AcceptEvolutionHandler)
// Interaction Packets
this.createServerBound(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler)
// Storage Packets
this.createServerBound(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler)
this.createServerBound(RequestMoveSwapPacket.ID, RequestMoveSwapPacket::decode, RequestMoveSwapHandler)
this.createServerBound(BenchMovePacket.ID, BenchMovePacket::decode, BenchMoveHandler)
this.createServerBound(BattleChallengePacket.ID, BattleChallengePacket::decode, ChallengeHandler)
this.createServerBound(MovePCPokemonToPartyPacket.ID, MovePCPokemonToPartyPacket::decode, MovePCPokemonToPartyHandler)
this.createServerBound(MovePartyPokemonToPCPacket.ID, MovePartyPokemonToPCPacket::decode, MovePartyPokemonToPCHandler)
this.createServerBound(ReleasePartyPokemonPacket.ID, ReleasePartyPokemonPacket::decode, ReleasePartyPokemonHandler)
this.createServerBound(ReleasePCPokemonPacket.ID, ReleasePCPokemonPacket::decode, ReleasePCPokemonHandler)
this.createServerBound(UnlinkPlayerFromPCPacket.ID, UnlinkPlayerFromPCPacket::decode, UnlinkPlayerFromPCHandler)
// Starter packets
this.createServerBound(SelectStarterPacket.ID, SelectStarterPacket::decode, SelectStarterPacketHandler)
this.createServerBound(RequestStarterScreenPacket.ID, RequestStarterScreenPacket::decode, RequestStarterScreenHandler)
this.createServerBound(SwapPCPokemonPacket.ID, SwapPCPokemonPacket::decode, SwapPCPokemonHandler)
this.createServerBound(SwapPartyPokemonPacket.ID, SwapPartyPokemonPacket::decode, SwapPartyPokemonHandler)
this.createServerBound(MovePCPokemonPacket.ID, MovePCPokemonPacket::decode, MovePCPokemonHandler)
this.createServerBound(MovePartyPokemonPacket.ID, MovePartyPokemonPacket::decode, MovePartyPokemonHandler)
this.createServerBound(SwapPCPartyPokemonPacket.ID, SwapPCPartyPokemonPacket::decode, SwapPCPartyPokemonHandler)
// Battle packets
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
this.createServerBound(CancelTradePacket.ID, CancelTradePacket::decode, CancelTradeHandler)
this.createServerBound(ChangeTradeAcceptancePacket.ID, ChangeTradeAcceptancePacket::decode, ChangeTradeAcceptanceHandler)
this.createServerBound(OfferTradePacket.ID, OfferTradePacket::decode, OfferTradeHandler)
this.createServerBound(UpdateTradeOfferPacket.ID, UpdateTradeOfferPacket::decode, UpdateTradeOfferHandler)
// Pasture
this.createServerBound(PasturePokemonPacket.ID, PasturePokemonPacket::decode, PasturePokemonHandler)
this.createServerBound(UnpasturePokemonPacket.ID, UnpasturePokemonPacket::decode, UnpasturePokemonHandler)
this.createServerBound(UnpastureAllPokemonPacket.ID, UnpastureAllPokemonPacket::decode, UnpastureAllPokemonHandler)
// Move select packets
this.createServerBound(MoveSelectedPacket.ID, MoveSelectedPacket::decode, MoveSelectedHandler)
this.createServerBound(MoveSelectCancelledPacket.ID, MoveSelectCancelledPacket::decode, MoveSelectCancelledHandler)
// Party select packets
this.createServerBound(PartyPokemonSelectedPacket.ID, PartyPokemonSelectedPacket::decode, PartyPokemonSelectedHandler)
this.createServerBound(PartySelectCancelledPacket.ID, PartySelectCancelledPacket::decode, PartySelectCancelledHandler)
// Party move select packets
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
private inline fun <reified P : NetworkPacket> buildMessage(toServer: Boolean) {
val message = networkDelegate.buildMessage(P::class.java, toServer)
// Gives client or server the chance to attach its packet handler
CobblemonEvents.MESSAGE_BUILT.post(MessageBuiltEvent(P::class.java, toServer, message))
message.registerMessage()
}
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
Cobblemon.implementation.networkManager.createClientBound(identifier, T::class, { message, buffer -> message.encode(buffer) }, decoder, handler)
}
private inline fun <reified T : NetworkPacket<T>> createServerBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ServerNetworkPacketHandler<T>) {
Cobblemon.implementation.networkManager.createServerBound(identifier, T::class, { message, buffer -> message.encode(buffer) }, decoder, handler)
}
override fun <T : NetworkPacket<T>> createClientBound(
identifier: Identifier,
kClass: KClass<T>,
encoder: (T, PacketByteBuf) -> Unit,
decoder: (PacketByteBuf) -> T,
handler: ClientNetworkPacketHandler<T>
) {
Cobblemon.implementation.networkManager.createClientBound(identifier, kClass, encoder, decoder, handler)
}
override fun <T : NetworkPacket<T>> createServerBound(
identifier: Identifier,
kClass: KClass<T>,
encoder: (T, PacketByteBuf) -> Unit,
decoder: (PacketByteBuf) -> T,
handler: ServerNetworkPacketHandler<T>
) {
Cobblemon.implementation.networkManager.createServerBound(identifier, kClass, encoder, decoder, handler)
}
override fun sendPacketToPlayer(player: ServerPlayerEntity, packet: NetworkPacket<*>) = Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
override fun sendPacketToServer(packet: NetworkPacket<*>) = Cobblemon.implementation.networkManager.sendPacketToServer(packet)
override fun <T : NetworkPacket<*>> asVanillaClientBound(packet: T): Packet<ClientPlayPacketListener> = Cobblemon.implementation.networkManager.asVanillaClientBound(packet)
}
@@ -0,0 +1,73 @@
/*
* Copyright (C) 2022 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
import com.cobblemon.mod.common.util.cobblemonResource
import dev.architectury.registry.level.biome.BiomeModifications
import net.minecraft.util.registry.RegistryEntry
import net.minecraft.util.registry.RegistryEntryList
import net.minecraft.world.gen.GenerationStep
import net.minecraft.world.gen.feature.ConfiguredFeatures
import net.minecraft.world.gen.feature.Feature
import net.minecraft.world.gen.feature.PlacedFeature
import net.minecraft.world.gen.feature.PlacedFeatures
import net.minecraft.world.gen.feature.SimpleRandomFeatureConfig
import net.minecraft.world.gen.feature.VegetationPlacedFeatures
import net.minecraft.world.gen.placementmodifier.RarityFilterPlacementModifier
object CobblemonPlacements {
lateinit var BLACK_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var BLUE_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var GREEN_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var PINK_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var RED_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var WHITE_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var YELLOW_APRICORN_TREE: RegistryEntry<PlacedFeature>
lateinit var APRICORN_TREES: RegistryEntry<PlacedFeature>
fun register() {
BLACK_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("black_apricorn_tree").toString(), CobblemonConfiguredFeatures.BLACK_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.BLACK_APRICORN_SAPLING.get()))
BLUE_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("blue_apricorn_tree").toString(), CobblemonConfiguredFeatures.BLUE_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.BLUE_APRICORN_SAPLING.get()))
GREEN_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("green_apricorn_tree").toString(), CobblemonConfiguredFeatures.GREEN_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.GREEN_APRICORN_SAPLING.get()))
PINK_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("pink_apricorn_tree").toString(), CobblemonConfiguredFeatures.PINK_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.PINK_APRICORN_SAPLING.get()))
RED_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("red_apricorn_tree").toString(), CobblemonConfiguredFeatures.RED_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.RED_APRICORN_SAPLING.get()))
WHITE_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("white_apricorn_tree").toString(), CobblemonConfiguredFeatures.WHITE_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.WHITE_APRICORN_SAPLING.get()))
YELLOW_APRICORN_TREE = PlacedFeatures.register(cobblemonResource("yellow_apricorn_tree").toString(), CobblemonConfiguredFeatures.YELLOW_APRICORN_TREE, PlacedFeatures.wouldSurvive(
CobblemonBlocks.YELLOW_APRICORN_SAPLING.get()))
val apricornTreeVariety = ConfiguredFeatures.register(
cobblemonResource("apricorn_trees").toString(), Feature.SIMPLE_RANDOM_SELECTOR, SimpleRandomFeatureConfig(
RegistryEntryList.of(
BLACK_APRICORN_TREE,
BLUE_APRICORN_TREE,
GREEN_APRICORN_TREE,
PINK_APRICORN_TREE,
RED_APRICORN_TREE,
WHITE_APRICORN_TREE,
YELLOW_APRICORN_TREE
)
)
)
APRICORN_TREES = PlacedFeatures.register(cobblemonResource("apricorn_trees").toString(), apricornTreeVariety, VegetationPlacedFeatures.modifiers(RarityFilterPlacementModifier.of(8)))
BiomeModifications.addProperties({ context -> true}, { context, properties ->
properties.generationProperties.addFeature(GenerationStep.Feature.VEGETAL_DECORATION, APRICORN_TREES)
})
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,76 +8,20 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.registry.CompletableRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.SoundEvent
import net.minecraft.util.registry.Registry
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
object CobblemonSounds : CompletableRegistry<SoundEvent>(Registry.SOUND_EVENT_KEY) {
private fun queue(name: String) = queue(name) { SoundEvent(cobblemonResource(name)) }
override val registry: Registry<SoundEvent> = Registries.SOUND_EVENT
override val registryKey: RegistryKey<Registry<SoundEvent>> = RegistryKeys.SOUND_EVENT
@JvmField
val GUI_CLICK = this.create("gui.click")
@JvmField
val PC_ON = this.create("pc.on")
@JvmField
val PC_OFF = this.create("pc.off")
@JvmField
val PC_GRAB = this.create("pc.grab")
@JvmField
val PC_DROP = this.create("pc.drop")
@JvmField
val PC_RELEASE = this.create("pc.release")
@JvmField
val PC_CLICK = this.create("pc.click")
@JvmField
val HEALING_MACHINE_ACTIVE = this.create("healing_machine.active")
@JvmField
val POKE_BALL_CAPTURE_STARTED = this.create("poke_ball.capture_started")
@JvmField
val POKE_BALL_CAPTURE_SUCCEEDED = this.create("poke_ball.capture_succeeded")
@JvmField
val POKE_BALL_SHAKE = this.create("poke_ball.shake")
@JvmField
val POKE_BALL_OPEN = this.create("poke_ball.open")
@JvmField
val POKE_BALL_HIT = this.create("poke_ball.hit")
@JvmField
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
@JvmField
val POKE_BALL_RECALL = this.create("poke_ball.recall")
@JvmField
val ITEM_USE = this.create("item.use")
@JvmField
val CAN_EVOLVE = this.create("pokemon.can_evolve")
@JvmField
val EVOLVING = this.create("pokemon.evolving")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@JvmField
val PVP_BATTLE = this.create("battle.pvp.default")
@JvmField
val PVW_BATTLE = this.create("battle.pvw.default")
@JvmField
val MEDICINE_HERB_USE = this.create("medicine_herb.use")
@JvmField
val MEDICINE_LIQUID_USE = this.create("medicine_liquid.use")
@JvmField
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
@JvmField
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
val POKE_BALL_CAPTURE_STARTED = queue("poke_ball.capture_started")
val POKE_BALL_CAPTURE_SUCCEEDED = queue("poke_ball.capture_succeeded")
val POKE_BALL_SHAKE = queue("poke_ball.shake")
val POKE_BALL_OPEN = queue("poke_ball.open")
val POKE_BALL_HIT = queue("poke_ball.hit")
val POKE_BALL_SEND_OUT = queue("poke_ball.send_out")
val POKE_BALL_RECALL = queue("poke_ball.recall")
val ITEM_USE = queue("item.use")
}
@@ -1,92 +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
import net.minecraft.registry.Registries
import net.minecraft.village.TradeOffers
import net.minecraft.village.VillagerData
import net.minecraft.village.VillagerProfession
/**
* A generator for various trade offers in the mod.
*/
object CobblemonTradeOffers {
/**
* Creates a list of all Cobblemon trade offers for every villager profession.
*
* @return The resulting list.
*/
fun tradeOffersForAll(): List<VillagerTradeOffer> = Registries.VILLAGER_PROFESSION.map(this::tradeOffersFor).flatten()
/**
* Creates a list of all Cobblemon trade offers for the given [VillagerProfession].
*
* @param profession The [VillagerProfession] being queried.
* @return The resulting list.
*/
fun tradeOffersFor(profession: VillagerProfession): List<VillagerTradeOffer> = when (profession) {
VillagerProfession.FARMER -> listOf(VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 32, 1, 1, 6))))
else -> emptyList()
}
/**
* Creates a list of all Cobblemon trade offers for the Wandering trader.
*
* @return The resulting list.
*/
fun resolveWanderingTradeOffers(): List<WandererTradeOffer> = listOf(
WandererTradeOffer(false, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 32, 1, 1, 6)))
)
/**
* Represents a trade offer that can be attached to a villager or a wandering trader.
*/
interface TradeOfferHolder {
/**
* The list of the possible [TradeOffers.Factory].
*/
val tradeOffers: List<TradeOffers.Factory>
}
/**
* Represents a trade offer from a villager.
*
* @property profession The target profession for this trade.
* @property requiredLevel The level required must be a possible level.
* @property tradeOffers The list of the possible [TradeOffers.Factory].
*
* @throws IllegalArgumentException If the [requiredLevel] is not within the bounds of [VillagerData.MIN_LEVEL] & [VillagerData.MAX_LEVEL].
*/
data class VillagerTradeOffer(
val profession: VillagerProfession,
val requiredLevel: Int,
override val tradeOffers: List<TradeOffers.Factory>
) : TradeOfferHolder {
init {
if (this.requiredLevel < VillagerData.MIN_LEVEL || this.requiredLevel > VillagerData.MAX_LEVEL) {
throw IllegalArgumentException("${this.requiredLevel} is not a valid level for a villager trade accepted range is ${VillagerData.MIN_LEVEL}-${VillagerData.MAX_LEVEL}")
}
}
}
/**
* Represents a trade offer from a wandering trader.
*
* @property isRareTrade If this is rare or common trade.
* @property tradeOffers The list of the possible [TradeOffers.Factory].
*/
data class WandererTradeOffer(
val isRareTrade: Boolean,
override val tradeOffers: List<TradeOffers.Factory>
) : TradeOfferHolder
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,10 +8,12 @@
package com.cobblemon.mod.common.advancement
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.advancement.criterion.*
import com.cobblemon.mod.common.advancement.criterion.CaughtPokemonCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.PickStarterCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.SimpleCountableCriterionCondition
import com.cobblemon.mod.common.advancement.criterion.SimpleCriterionTrigger
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.advancement.criterion.Criterion
import net.minecraft.advancement.criterion.Criteria
/**
* Contains all the advancement criteria in Cobblemon.
@@ -20,57 +22,40 @@ import net.minecraft.advancement.criterion.Criterion
* @since October 26th, 2022
*/
object CobblemonCriteria {
val PICK_STARTER = this.create(
val PICK_STARTER = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("pick_starter"),
PickStarterCriterionCondition::class.java
)
)
val CATCH_POKEMON = this.create(
val CATCH_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("catch_pokemon"),
CaughtPokemonCriterionCondition::class.java
)
)
val CATCH_SHINY_POKEMON = this.create(
val CATCH_SHINY_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("catch_shiny_pokemon"),
SimpleCountableCriterionCondition::class.java
)
)
val EGG_HATCH = this.create(
val EGG_HATCH = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("eggs_hatched"),
SimpleCountableCriterionCondition::class.java
)
)
val EVOLVE_POKEMON = this.create(
val EVOLVE_POKEMON = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("pokemon_evolved"),
SimpleCountableCriterionCondition::class.java
)
)
val WIN_BATTLE = this.create(
val WIN_BATTLE = Criteria.register(
SimpleCriterionTrigger(
cobblemonResource("battles_won"),
SimpleCountableCriterionCondition::class.java
)
)
val DEFEAT_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("pokemon_defeated"),
SimpleCountableCriterionCondition::class.java
)
)
val COLLECT_ASPECT = this.create(
AspectCriterionTrigger(
cobblemonResource("aspects_collected"),
AspectCriterionCondition::class.java
)
)
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
}
@@ -1,45 +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.advancement.criterion
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
}
class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
var pokemon = Identifier("cobblemon:pikachu")
var aspects = mutableListOf<String>()
override fun toJson(json: JsonObject) {
json.add("aspects", JsonArray(aspects.size).also {
aspects.forEach { aspect -> it.add(aspect) }
})
json.addProperty("pokemon", pokemon.toString())
}
override fun fromJson(json: JsonObject) {
aspects.clear()
json.getAsJsonArray("aspects").forEach { element ->
aspects.add(element.asString)
}
pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
}
override fun matches(player: ServerPlayerEntity, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
return this.aspects.all { it in caughtAspects }
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.advancement.criterion
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -21,7 +21,7 @@ import net.minecraft.util.Identifier
*/
open class CountablePokemonTypeContext(times: Int, var type: String) : CountableContext(times)
class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
class CaughtPokemonCriterionCondition(id: Identifier, entity: Extended) : CountableCriterionCondition<CountablePokemonTypeContext>(id, entity) {
var type = "any"
override fun toJson(json: JsonObject) {
super.toJson(json)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.advancement.criterion
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -20,7 +20,7 @@ import net.minecraft.util.Identifier
* @author Hiroku
* @since November 4th, 2022
*/
abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<T>(id, predicate) {
abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, entity: Extended) : SimpleCriterionCondition<T>(id, entity) {
var count = 0
override fun fromJson(json: JsonObject) {
count = json.get("count")?.asInt ?: 0
@@ -43,7 +43,7 @@ abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier,
* @author Hiroku
* @since November 4th, 2022
*/
class SimpleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountableContext>(id, predicate)
class SimpleCountableCriterionCondition(id: Identifier, entity: Extended) : CountableCriterionCondition<CountableContext>(id, entity)
fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayerEntity, times: Int) = trigger(player, CountableContext(times))
/**
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -11,7 +11,7 @@ package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.Pokemon
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -21,7 +21,7 @@ import net.minecraft.util.Identifier
* @author Licious, Hiroku
* @since October 26th, 2022
*/
class PickStarterCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<Pokemon>(id, predicate) {
class PickStarterCriterionCondition(id: Identifier, entity: Extended) : SimpleCriterionCondition<Pokemon>(id, entity) {
var properties = PokemonProperties()
override fun toJson(json: JsonObject) {
json.addProperty("properties", properties.originalString)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -13,7 +13,7 @@ import net.minecraft.advancement.criterion.AbstractCriterion
import net.minecraft.advancement.criterion.AbstractCriterionConditions
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer
import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.predicate.entity.EntityPredicate.Extended
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
@@ -31,17 +31,16 @@ open class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
val criterionClass: Class<C>
) : AbstractCriterion<C>() {
override fun getId() = _id
fun trigger(player: ServerPlayerEntity, context: T) = this.trigger(player) { it.matches(player, context) }
override fun conditionsFromJson(
obj: JsonObject,
playerPredicate: LootContextPredicate,
playerPredicate: Extended,
predicateDeserializer: AdvancementEntityPredicateDeserializer
): C {
val instance = criterionClass.getConstructor(Identifier::class.java, LootContextPredicate::class.java).newInstance(id, playerPredicate)
val instance = criterionClass.getConstructor(Identifier::class.java, Extended::class.java).newInstance(id, playerPredicate)
instance.fromJson(obj)
return instance
}
fun trigger(player: ServerPlayerEntity, context: T) = this.trigger(player) { it.matches(player, context) }
}
/**
@@ -53,8 +52,8 @@ open class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
*/
abstract class SimpleCriterionCondition<T>(
id: Identifier,
playerPredicate: LootContextPredicate
): AbstractCriterionConditions(id, playerPredicate) {
entity: Extended
): AbstractCriterionConditions(id, entity) {
override fun toJson(predicateSerializer: AdvancementEntityPredicateSerializer): JsonObject {
val json = super.toJson(predicateSerializer)
toJson(json)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -18,8 +18,7 @@ package com.cobblemon.mod.common.api
*/
open class PrioritizedList<T> : Iterable<T> {
protected val priorityMap = mutableMapOf<Priority, MutableList<T>>()
// Please don't change arraylist, we need insertion order
protected val ordered = arrayListOf<T>()
protected val ordered = mutableListOf<T>()
val mapping: Map<Priority, List<T>>
get() = priorityMap.toMap()
@@ -32,8 +31,7 @@ open class PrioritizedList<T> : Iterable<T> {
}
fun add(priority: Priority, value: T) {
// Please don't change arraylist, we need insertion order
priorityMap.putIfAbsent(priority, arrayListOf())
priorityMap.putIfAbsent(priority, mutableListOf())
priorityMap[priority]?.add(value)
reorder()
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,41 +9,64 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resource.ResourceManager
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
import kotlin.io.path.Path
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
/**
* Registry for all known Abilities
*/
object Abilities : DataRegistry {
object Abilities : JsonDataRegistry<AbilityTemplate> {
override val id = cobblemonResource("abilities")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<Abilities>()
override val typeToken: TypeToken<AbilityTemplate> = TypeToken.get(AbilityTemplate::class.java)
override val resourcePath = "abilities"
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setLenient()
.setPrettyPrinting()
.registerTypeAdapter(MutableText::class.java, MutableTextAdapter)
.create()
val DUMMY = AbilityTemplate(name = "dummy")
private val allAbilities = mutableListOf<AbilityTemplate>()
private val abilityMap = mutableMapOf<String, AbilityTemplate>()
override fun reload(manager: ResourceManager) {
object MutableTextAdapter : JsonDeserializer<MutableText> {
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext) = json.asString.asTranslated()
}
override fun reload(data: Map<Identifier, AbilityTemplate>) {
PotentialAbility.types.clear()
PotentialAbility.types.add(CommonAbilityType)
PotentialAbility.types.add(HiddenAbilityType)
this.abilityMap.clear()
val abilitiesJson = ShowdownService.service.getAbilityIds()
for (i in 0 until abilitiesJson.size()) {
val id = abilitiesJson[i].asString
val ability = AbilityTemplate(id)
this.register(ability)
allAbilities.clear()
abilityMap.clear()
data.forEach { (identifier, abilityTemplate) ->
allAbilities.add(abilityTemplate)
abilityMap[identifier.path] = abilityTemplate
}
Cobblemon.LOGGER.info("Loaded {} abilities", this.abilityMap.size)
Cobblemon.LOGGER.info("Loaded {} abilities", this.allAbilities.size)
this.observable.emit(this)
}
@@ -52,19 +75,14 @@ object Abilities : DataRegistry {
}
fun register(ability: AbilityTemplate): AbilityTemplate {
this.abilityMap[ability.name.lowercase()] = ability
abilityMap[ability.name.lowercase()] = ability
allAbilities.add(ability)
return ability
}
fun all() = this.abilityMap.values.toList()
fun first() = this.abilityMap.values.first()
fun all() = allAbilities.toList()
fun first() = allAbilities.first()
fun get(name: String) = abilityMap[name.lowercase()]
fun getOrException(name: String) = get(name) ?: throw IllegalArgumentException("Unable to find ability of name: $name")
fun count() = this.abilityMap.size
internal fun receiveSyncPacket(abilities: Collection<AbilityTemplate>) {
this.abilityMap.clear()
abilities.forEach { ability -> this.register(ability) }
}
fun getOrException(name: String) = get(name)!!
fun count() = allAbilities.size
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,10 +8,10 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.util.DataKeys
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.text.MutableText
/**
* Representing an Ability with all its attributes
@@ -21,60 +21,27 @@ import net.minecraft.nbt.NbtCompound
* @author Qu
* @since January 9th, 2022
*/
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
open class Ability internal constructor(var template: AbilityTemplate) {
val name: String
get() = template.name
val displayName: String
val displayName: MutableText
get() = template.displayName
val description: String
val description: MutableText
get() = template.description
/**
* This represents the last known index of this backing ability in the species data.
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
* The value can be mutated however this is not recommended by API users.
*/
var index: Int = -1
/**
* The last known priority of this ability in the species data.
* The value can be mutated however this is not recommended by API users.
*/
var priority = Priority.LOWEST
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
nbt.putBoolean(DataKeys.POKEMON_ABILITY_FORCED, forced)
nbt.putInt(DataKeys.POKEMON_ABILITY_INDEX, index)
nbt.putString(DataKeys.POKEMON_ABILITY_PRIORITY, priority.name)
return nbt
}
open fun saveToJSON(json: JsonObject): JsonObject {
json.addProperty(DataKeys.POKEMON_ABILITY_NAME, name)
json.addProperty(DataKeys.POKEMON_ABILITY_FORCED, forced)
json.addProperty(DataKeys.POKEMON_ABILITY_INDEX, index)
json.addProperty(DataKeys.POKEMON_ABILITY_PRIORITY, priority.name)
return json
}
open fun loadFromNBT(nbt: NbtCompound): Ability {
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
}
return this
}
open fun loadFromJSON(json: JsonObject): Ability {
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
}
return this
}
open fun loadFromNBT(nbt: NbtCompound) = this
open fun loadFromJSON(json: JsonObject) = this
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -22,17 +22,15 @@ import com.cobblemon.mod.common.pokemon.Species
* @since July 28th, 2022
*/
open class AbilityPool : PrioritizedList<PotentialAbility>() {
fun select(species: Species, aspects: Set<String>): Pair<Ability, Priority> {
fun select(species: Species, aspects: Set<String>): Ability {
for (priority in Priority.values()) {
val potentialAbilities = priorityMap[priority]?.filter { it.isSatisfiedBy(aspects) } ?: continue
if (potentialAbilities.isNotEmpty()) {
return potentialAbilities.random().template.create() to priority
return potentialAbilities.random().template.create()
}
}
LOGGER.error("Unable to select an ability from the pool for $species and aspects: ${aspects.joinToString()}")
LOGGER.error("Usually this happens when a client is doing logic it shouldn't. Please show this to the Cobblemon developers!")
Exception().printStackTrace()
return Abilities.first().create() to Priority.LOWEST
return Abilities.first().create()
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,8 +8,10 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.util.lang
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
import net.minecraft.text.MutableText
/**
* This represents the base of an Ability.
@@ -19,14 +21,14 @@ import net.minecraft.nbt.NbtCompound
*/
class AbilityTemplate(
val name: String = "",
var builder: (AbilityTemplate, forced: Boolean) -> Ability = { template, forced -> Ability(template, forced) },
val displayName: String = "cobblemon.ability.$name",
val description: String = "cobblemon.ability.$name.desc"
var builder: (AbilityTemplate) -> Ability = { Ability(it) },
val displayName: MutableText = lang("ability.$name"),
val description: MutableText = lang("ability.$name.desc")
) {
/**
* Returns the Ability or if applicable the extension connected to this template
*/
fun create(forced: Boolean = false) = builder(this, forced)
fun create() = builder(this)
/**
@@ -34,12 +36,12 @@ class AbilityTemplate(
*
* Ability extensions need to write and read their needed data from here.
*/
fun create(nbt: NbtCompound) = create().loadFromNBT(nbt)
fun create(nbt: NbtCompound) = builder(this).loadFromNBT(nbt)
/**
* Returns the Ability and loads the given JSON object into it.
*
* Ability extensions need to write and read their needed data from here.
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
fun create(json: JsonObject) = builder(this).loadFromJSON(json)
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -10,10 +10,9 @@ package com.cobblemon.mod.common.api.apricorn
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.block.ApricornBlock
import com.cobblemon.mod.common.block.ApricornSaplingBlock
import com.cobblemon.mod.common.item.ApricornItem
import net.minecraft.block.MapColor
import com.cobblemon.mod.common.world.block.ApricornBlock
import com.cobblemon.mod.common.world.block.ApricornSaplingBlock
import net.minecraft.item.BlockItem
/**
@@ -33,53 +32,43 @@ enum class Apricorn {
YELLOW;
fun item(): ApricornItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN
BLUE -> CobblemonItems.BLUE_APRICORN
GREEN -> CobblemonItems.GREEN_APRICORN
PINK -> CobblemonItems.PINK_APRICORN
RED -> CobblemonItems.RED_APRICORN
WHITE -> CobblemonItems.WHITE_APRICORN
YELLOW -> CobblemonItems.YELLOW_APRICORN
BLACK -> CobblemonItems.BLACK_APRICORN.get()
BLUE -> CobblemonItems.BLUE_APRICORN.get()
GREEN -> CobblemonItems.GREEN_APRICORN.get()
PINK -> CobblemonItems.PINK_APRICORN.get()
RED -> CobblemonItems.RED_APRICORN.get()
WHITE -> CobblemonItems.WHITE_APRICORN.get()
YELLOW -> CobblemonItems.YELLOW_APRICORN.get()
}
fun seed(): BlockItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN_SEED
BLUE -> CobblemonItems.BLUE_APRICORN_SEED
GREEN -> CobblemonItems.GREEN_APRICORN_SEED
PINK -> CobblemonItems.PINK_APRICORN_SEED
RED -> CobblemonItems.RED_APRICORN_SEED
WHITE -> CobblemonItems.WHITE_APRICORN_SEED
YELLOW -> CobblemonItems.YELLOW_APRICORN_SEED
BLACK -> CobblemonItems.BLACK_APRICORN_SEED.get()
BLUE -> CobblemonItems.BLUE_APRICORN_SEED.get()
GREEN -> CobblemonItems.GREEN_APRICORN_SEED.get()
PINK -> CobblemonItems.PINK_APRICORN_SEED.get()
RED -> CobblemonItems.RED_APRICORN_SEED.get()
WHITE -> CobblemonItems.WHITE_APRICORN_SEED.get()
YELLOW -> CobblemonItems.YELLOW_APRICORN_SEED.get()
}
fun block(): ApricornBlock = when(this) {
BLACK -> CobblemonBlocks.BLACK_APRICORN
BLUE -> CobblemonBlocks.BLUE_APRICORN
GREEN -> CobblemonBlocks.GREEN_APRICORN
PINK -> CobblemonBlocks.PINK_APRICORN
RED -> CobblemonBlocks.RED_APRICORN
WHITE -> CobblemonBlocks.WHITE_APRICORN
YELLOW -> CobblemonBlocks.YELLOW_APRICORN
BLACK -> CobblemonBlocks.BLACK_APRICORN.get()
BLUE -> CobblemonBlocks.BLUE_APRICORN.get()
GREEN -> CobblemonBlocks.GREEN_APRICORN.get()
PINK -> CobblemonBlocks.PINK_APRICORN.get()
RED -> CobblemonBlocks.RED_APRICORN.get()
WHITE -> CobblemonBlocks.WHITE_APRICORN.get()
YELLOW -> CobblemonBlocks.YELLOW_APRICORN.get()
}
fun sapling(): ApricornSaplingBlock = when(this) {
BLACK -> CobblemonBlocks.BLACK_APRICORN_SAPLING
BLUE -> CobblemonBlocks.BLUE_APRICORN_SAPLING
GREEN -> CobblemonBlocks.GREEN_APRICORN_SAPLING
PINK -> CobblemonBlocks.PINK_APRICORN_SAPLING
RED -> CobblemonBlocks.RED_APRICORN_SAPLING
WHITE -> CobblemonBlocks.WHITE_APRICORN_SAPLING
YELLOW -> CobblemonBlocks.YELLOW_APRICORN_SAPLING
}
fun mapColor(): MapColor = when(this) {
BLACK -> MapColor.BLACK
BLUE -> MapColor.BLUE
GREEN -> MapColor.GREEN
PINK -> MapColor.PINK
RED -> MapColor.RED
WHITE -> MapColor.WHITE
YELLOW -> MapColor.YELLOW
BLACK -> CobblemonBlocks.BLACK_APRICORN_SAPLING.get()
BLUE -> CobblemonBlocks.BLUE_APRICORN_SAPLING.get()
GREEN -> CobblemonBlocks.GREEN_APRICORN_SAPLING.get()
PINK -> CobblemonBlocks.PINK_APRICORN_SAPLING.get()
RED -> CobblemonBlocks.RED_APRICORN_SAPLING.get()
WHITE -> CobblemonBlocks.WHITE_APRICORN_SAPLING.get()
YELLOW -> CobblemonBlocks.YELLOW_APRICORN_SAPLING.get()
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,73 +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.battles.interpreter
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
/**
* The context of how a condition was created or changed during a battle.
*
* @author Segfault Guy
* @since April 10th, 2023
*/
interface BattleContext {
/** The effect or condition this [BattleContext] represents. */
val id: String
/** The turn this [BattleContext] was created. */
val turn: Int
/** The [BattleContext.Type] tied to this [BattleContext]. */
val type: Type
/** The [BattlePokemon] that directly or indirectly caused this [BattleContext]. */
val origin: BattlePokemon?
/**
* The type of [BattleContext].
*
* @property damaging Whether a context of this type is a source of damage.
* @property exclusive Whether only one context of this type can exist.
*
* @author Segfault Guy
* @since April 10th, 2023
*/
enum class Type(val damaging: Boolean, val exclusive: Boolean) {
ITEM(true, true),
STATUS(true, false),
VOLATILE(true, false),
HAZARD(true, false),
WEATHER(true, true),
ROOM(false, true),
SPORT(false, false),
TERRAIN(false, true),
GRAVITY(false, true),
TAILWIND(false, true),
SCREEN(false, false),
FAINT(false, false),
BOOST(false, false),
UNBOOST(false, false),
MISC(false, false);
}
}
data class BasicContext(
override val id: String,
override val turn: Int,
override val type: BattleContext.Type,
override val origin: BattlePokemon?
) : BattleContext
data class MissingContext(
override val id: String = "error",
override val turn: Int = 0,
override val type: BattleContext.Type = BattleContext.Type.MISC,
override val origin: BattlePokemon? = null
) : BattleContext
@@ -1,252 +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.battles.interpreter
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import java.util.UUID
/**
* A class responsible for parsing a raw simulator protocol message received from Showdown.
* For more information see the [Showdown protocol](https://github.com/smogon/pokemon-showdown/blob/master/sim/SIM-PROTOCOL.md).
*
* @constructor Creates a battle message with the given raw message.
*
* @param rawMessage The raw message received from Showdown.
*
* @author Licious
* @since December 31st, 2022
*/
class BattleMessage(rawMessage: String) {
/**
* The ID of the action received in the message.
*/
var id = ""
private set
/**
* The raw message received.
*/
var rawMessage: String = rawMessage
private set
/**
* A collection of the individual arguments the message had.
*/
private val args = arrayListOf<String>()
/**
* A collection of the optional arguments the message had.
*/
private val optionalArguments = hashMapOf<String, String>()
/**
* Pattern to match the start of an optional argument.
*/
private val optionalArgumentMatcher = Regex("^\\$OPTIONAL_ARG_START([^]]+)$OPTIONAL_ARG_END")
init {
this.parse(rawMessage)
}
/**
* Get an argument at the given [index].
*
* @param index The index of the expected argument.
* @return The argument if existing or null.
*/
fun argumentAt(index: Int): String? = this.args.getOrNull(index)
/**
* Get an optional argument with the given [name].
* This returns the data of the argument only.
*
* @param name The name of the optional argument.
* @return The argument data if existing or null.
*/
fun optionalArgument(name: String): String? = this.optionalArguments[name.lowercase()]
/**
* Checks if an optional argument is present.
* [optionalArgument] is null safe, this method is meant as a way to check 'flags' as some optional arguments contain no data.
*
* @param name The name of the optional argument.
* @return True if the argument is present.
*/
fun hasOptionalArgument(name: String): Boolean = this.optionalArgument(name) != null
/**
* Clears the parsed arguments and parses the message again with the new given [rawMessage].
*
* @param rawMessage The raw message received from Showdown.
* @return This instance of the battle message updated.
*/
fun parse(rawMessage: String): BattleMessage {
var message = rawMessage.trim()
this.id = ""
this.args.clear()
this.optionalArguments.clear()
this.rawMessage = message
if (!message.startsWith(SEPARATOR) || message == SEPARATOR) {
return this
}
message = this.push(message)
this.id = message.substringBefore(SEPARATOR)
message = this.push(message)
while (message.isNotBlank()) {
val currentData = message.substringBefore(SEPARATOR)
val optionalArgumentID = this.optionalArgumentMatcher.find(currentData)
if (optionalArgumentID != null) {
val id = optionalArgumentID.value.removePrefix(OPTIONAL_ARG_START).removeSuffix(OPTIONAL_ARG_END).lowercase()
val value = currentData.substringAfter(optionalArgumentID.value).trim()
this.optionalArguments[id] = value
}
else {
this.args.add(currentData)
}
message = this.push(message)
}
return this
}
fun pokemonByUuid(index: Int, battle: PokemonBattle): BattlePokemon? {
return this.argumentAt(index)?.let { UUID.fromString(it) }?.let { uuid -> battle.actors.flatMap { it.pokemonList }.find { it.uuid == uuid } }
}
/**
* Queries an argument at the given [index] for a 'pnx' that will be parsed into a [BattleActor] and [ActiveBattlePokemon].
*
* @param index The index of the argument containing the [BattleActor] and [ActiveBattlePokemon].
* @param battle The [PokemonBattle] being queried.
* @return A pair of [BattleActor] and [ActiveBattlePokemon] if the argument exists and successfully parses them otherwise null.
*/
fun actorAndActivePokemon(index: Int, battle: PokemonBattle): Pair<BattleActor, ActiveBattlePokemon>? {
val (pnx, _) = this.pnxAndUuid(index) ?: return null
return this.actorAndActivePokemon(pnx, battle)
}
/*
Example:
|-curestatus|p1: a8e5710e-6835-4387-99d3-331b45f848e6|slp|[msg]
|-curestatus|p1: 0686b20d-3019-4167-92e2-786834245743|slp|[msg]
// Function used to grab BattlePokemon (As we need to be able to grab non active pokemon to cure their status)
// by using playerNumber(actorID) and pokemon uuid(pokemonID)
*/
fun getBattlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
val actorAndPokemonID = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(": ") ?: return null
if (actorAndPokemonID.count() < 2) return null
val actorID = actorAndPokemonID[0]
val pokemonID = actorAndPokemonID[1]
return this.getBattlePokemon(actorID, pokemonID, battle)
}
fun getSourceBattlePokemon(battle: PokemonBattle): BattlePokemon? {
val sourcePokemonArgument = this.optionalArguments.get("of") ?: return null
val actorAndPokemonID = sourcePokemonArgument.takeIf { it.length >= 2 }?.split(": ") ?: return null
if (actorAndPokemonID.count() < 2) return null
val actorID = actorAndPokemonID[0]
val pokemonID = actorAndPokemonID[1]
return this.getBattlePokemon(actorID, pokemonID, battle)
}
/**
* Deconstructs the Showdown ID of a Pokemon at the given [index] into its 'pnx' and 'uuid' parts.
*
* @param index The index of the argument containing the Showdown ID of a Pokemon.
* @return A 'pnx' String representing position and a 'uuid' String representing the unique Pokemon if parsed correctly, otherwise null.
*/
fun pnxAndUuid(index: Int): Pair<String, String>? {
val argument = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) } ?: return null
val uuid = argument[1].trim()
return pnx to uuid
}
/**
* Attempts to parse an [Effect] from an argument at the given [index].
*
* @param index The index of the expected argument.
* @return The parsed [Effect] or null.
*/
fun effectAt(index: Int): Effect? {
val data = this.argumentAt(index) ?: return null
return Effect.parse(data)
}
/**
* Attempts to parse an [Effect] from an optional argument.
*
* @param argumentName The name of the optional argument.
* @return The parsed [Effect] or null.
*/
fun effect(argumentName: String = "from"): Effect? {
val data = this.optionalArgument(argumentName) ?: return null
return Effect.parse(data)
}
/**
* Queries an optional argument with given [argumentName] for a 'pnx' that will be parsed into a [BattleActor] and [ActiveBattlePokemon].
*
* @param battle The [PokemonBattle] being queried.
* @param argumentName The name of the optional argument.
* @return A pair of [BattleActor] and [ActiveBattlePokemon] if the argument exists and successfully parses them otherwise null.
*/
fun actorAndActivePokemonFromOptional(battle: PokemonBattle, argumentName: String = "of"): Pair<BattleActor, ActiveBattlePokemon>? {
val pnx = this.optionalArgument(argumentName)?.takeIf { it.length >= 3 }?.substring(0, 3) ?: return null
return this.actorAndActivePokemon(pnx, battle)
}
/**
* Pushes the given string down into the next argument.
*
* @param message The current state of the message.
* @return A substring of [message] after the first [SEPARATOR] or empty if no [SEPARATOR] remains.
*/
private fun push(message: String): String = message.substringAfter(SEPARATOR, "")
/**
* A utility to wrap [PokemonBattle.getActorAndActiveSlotFromPNX] to make it nullable instead of throwing an exception.
*
* @param pnx The raw pnx.
* @param battle The [PokemonBattle] being queried.
* @returnA pair of [BattleActor] and [ActiveBattlePokemon] if [PokemonBattle.getActorAndActiveSlotFromPNX] executes without any exception being thrown or else null.
*/
private fun actorAndActivePokemon(pnx: String, battle: PokemonBattle): Pair<BattleActor, ActiveBattlePokemon>? = try {
battle.getActorAndActiveSlotFromPNX(pnx)
} catch (_: Exception) {
null
}
private fun getBattlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
battle.getBattlePokemon(pnx, pokemonID)
} catch (_: Exception) {
null
}
companion object {
private const val SEPARATOR = "|"
private const val OPTIONAL_ARG_START = "["
private const val OPTIONAL_ARG_END = "]"
/**
* Pattern to match a Showdown position e.g. p2a, p1b
*/
val PNX_MATCHER = Regex("p\\d[a-c]")
/**
* Pattern to match a Showdown side position e.g. p2, p1
*/
val PN_MATCHER = Regex("p\\d")
}
}
@@ -1,149 +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.battles.interpreter
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.battles.interpreter.CobblemonEffect
/**
* A representation of an effect received from Showdown inside a [BattleMessage].
*
* @author Licious
* @since December 31st, 2022
*/
interface Effect {
/**
* The literal ID of this [Effect].
*/
val id: String
/**
* The [Effect.Type] of this [Effect].
*/
val type: Type
/**
* The raw literal data received when parsing this [Effect].
*/
val rawData: String
val typelessData: String
get() = rawData.substringAfter(type.prefix).trim()
/**
* Represents the type of the [Effect].
*
* @property prefix The literal prefix used to identify the type by the Showdown simulator protocol.
*
* @author Licious
* @since December 31st, 2022
*/
enum class Type(val prefix: String) {
ABILITY("ability:"),
ITEM("item:"),
MOVE("move:"),
BAGITEM("bagitem:"),
PURE(""),
}
companion object {
/**
* Creates an [Effect].
*
* @param id The ID of the effect, this may be validated
* @param type The [Effect.Type].
* @param rawData The received string in the battle message.
* @return An [Effect] containing the given data of the given [type].
*/
private fun of(id: String, type: Type, rawData: String): Effect = CobblemonEffect(id, type, rawData)
/**
* Creates an [Effect] with type [Effect.Type.ABILITY].
*
* @param id The ID of the effect, meant to be present in [Abilities].
* @param rawData The received string in the battle message.
* @return An [Effect] containing the given data of [Effect.Type.ABILITY].
*
* @throws IllegalArgumentException If the [id] cannot be found in the [Abilities] registry.
*/
fun ability(id: String, rawData: String): Effect {
if (Abilities.get(id) == null) {
throw IllegalArgumentException("Cannot instance ability effect with ID $id")
}
return of(id, Type.ABILITY, rawData)
}
/**
* Creates an [Effect] with type [Effect.Type.ITEM].
*
* @param id The ID of the effect. This should be trusted as Showdown keeps the held items on their end.
* @param rawData The received string in the battle message.
* @return An [Effect] containing the given data of [Effect.Type.ITEM].
*/
fun item(id: String, rawData: String): Effect = of(id, Type.ITEM, rawData)
/**
* Creates an [Effect] with type [Effect.Type.MOVE].
*
* @param id The ID of the effect, meant to be present in [Moves].
* @param rawData The received string in the battle message.
* @return An [Effect] containing the given data of [Effect.Type.MOVE].
*
* @throws IllegalArgumentException If the [id] cannot be found in the [Moves] registry.
*/
fun move(id: String, rawData: String): Effect {
if (Moves.getByName(id) == null) {
throw IllegalArgumentException("Cannot instance move effect with ID $id")
}
return of(id, Type.MOVE, rawData)
}
/**
* Creates a "pure" [Effect].
* This is the representation of a purely literal effect by Showdown.
*
* @param id The ID of the effect.
* @param rawData The received string in the battle message.
* @return An [Effect] containing the given data of [Effect.Type.PURE].
*/
fun pure(id: String, rawData: String): Effect = of(id, Type.PURE, rawData)
/**
* Parses an [Effect] from the given [rawData].
*
* @param rawData The raw data expecting to create an [Effect].
* @return The parsed [Effect] or null if the raw data is blank or the parsed effect throws an [IllegalArgumentException].
*
* @throws IllegalArgumentException if the parsed type doesn't allow the resulting ID.
*/
fun parse(rawData: String): Effect? {
if (rawData.isBlank()) {
return null
}
return try {
when {
rawData.startsWith(Type.ABILITY.prefix) -> ability(rawData.lowercase().substringAfter(Type.ABILITY.prefix).replace(ShowdownIdentifiable.REGEX, ""), rawData)
rawData.startsWith(Type.ITEM.prefix) -> item(rawData.lowercase().substringAfter(Type.ITEM.prefix).replace(ShowdownIdentifiable.REGEX, ""), rawData)
rawData.startsWith(Type.MOVE.prefix) -> move(rawData.lowercase().substringAfter(Type.MOVE.prefix).replace(ShowdownIdentifiable.REGEX, ""), rawData)
else -> pure(rawData.lowercase().replace(ShowdownIdentifiable.REGEX, ""), rawData)
}
} catch (_: Exception) {
null
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -10,46 +10,32 @@ package com.cobblemon.mod.common.api.battles.model
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.Cobblemon.showdown
import com.cobblemon.mod.common.CobblemonNetwork
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.BattleCaptureAction
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.battles.dispatch.BattleDispatch
import com.cobblemon.mod.common.battles.dispatch.DispatchResult
import com.cobblemon.mod.common.battles.dispatch.GO
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
import com.cobblemon.mod.common.battles.interpreter.ContextManager
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.battles.runner.ShowdownService
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
import com.cobblemon.mod.common.pokemon.feature.BattleCriticalHitsFeature
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import net.minecraft.entity.Entity
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.text.Text
import java.io.File
import kotlin.io.path.Path
import kotlin.io.path.writeLines
import net.minecraft.server.network.ServerPlayerEntity
/**
* Individual battle instance
@@ -64,13 +50,12 @@ open class PokemonBattle(
) {
/** Whether or not logging will be silenced for this battle. */
var mute = true
init {
side1.battle = this
side2.battle = this
this.actors.forEach { actor ->
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.criticalHits = 0
battlePokemon.effectedPokemon.getFeature<BattleCriticalHitsFeature>(BattleCriticalHitsFeature.ID)?.reset()
}
}
}
@@ -89,7 +74,6 @@ open class PokemonBattle(
val battleId = UUID.randomUUID()
val showdownMessages = mutableListOf<String>()
val battleLog = mutableListOf<String>()
var started = false
var ended = false
// TEMP battle showcase stuff
@@ -100,14 +84,9 @@ open class PokemonBattle(
var dispatchResult = GO
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
val afterDispatches = mutableListOf<() -> Unit>()
val captureActions = mutableListOf<BattleCaptureAction>()
val majorBattleActions = hashMapOf<UUID, BattleMessage>()
val minorBattleActions = hashMapOf<UUID, BattleMessage>()
val contextManager = ContextManager()
/** Whether or not there is one side with at least one player, and the other only has wild Pokémon. */
val isPvW: Boolean
get() {
@@ -150,11 +129,6 @@ open class PokemonBattle(
return actors.find { actor -> actor.uuid == actorId }
}
/**
* Gets the first battle actor whom the given player controls, or null if there is no such actor.
*/
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
/**
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
*
@@ -169,25 +143,22 @@ open class PokemonBattle(
return actor to pokemon
}
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
return actor.pokemonList.find { it.uuid.toString() == pokemonID }
?: throw IllegalStateException("Invalid pnx: $pnx - unknown pokemon")
}
fun broadcastChatMessage(component: Text) {
spectators.forEach { spectatorId ->
spectatorId.getPlayer()?.let {
CobblemonNetwork.sendPacketToPlayer(it, BattleMessagePacket(component))
}
}
return actors.forEach { it.sendMessage(component) }
}
fun writeShowdownAction(vararg messages: String) {
log(messages.joinToString("\n"))
ShowdownService.service.send(battleId, messages.toList().toTypedArray())
val jsonArray = JsonArray()
for (message in messages) {
jsonArray.add(message)
}
val request = JsonObject()
request.addProperty(DataKeys.REQUEST_TYPE, DataKeys.REQUEST_BATTLE_SEND_MESSAGE)
request.addProperty(DataKeys.REQUEST_BATTLE_ID, battleId.toString())
request.add(DataKeys.REQUEST_MESSAGES, jsonArray)
val json = BattleRegistry.gson.toJson(request)
log(json)
showdown.write(json)
}
fun turn(newTurnNumber: Int) {
@@ -204,50 +175,20 @@ open class PokemonBattle(
fun end() {
ended = true
this.actors.forEach { actor ->
val faintedPokemons = actor.pokemonList.filter { it.health <= 0 }
actor.getSide().getOppositeSide().actors.forEach { opponent ->
val opponentNonFaintedPokemons = opponent.pokemonList.filter { it.health > 0 }
faintedPokemons.forEach { faintedPokemon ->
for (opponentPokemon in opponentNonFaintedPokemons) {
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
val defeatProgress = DefeatEvolutionProgress()
val pokemon = opponentPokemon.effectedPokemon
if (facedFainted && defeatProgress.shouldKeep(pokemon)) {
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target.matches(faintedPokemon.effectedPokemon) }) { defeatProgress }
progress.updateProgress(DefeatEvolutionProgress.Progress(progress.currentProgress().target, progress.currentProgress().amount + 1))
}
val multiplier = when {
// ToDo when Exp. All is implement if enabled && !facedFainted return 2.0, probably should be a configurable value too, this will have priority over the Exp. Share
!facedFainted && pokemon.heldItemNoCopy().isIn(CobblemonItemTags.EXPERIENCE_SHARE) -> Cobblemon.config.experienceShareMultiplier
// ToDo when Exp. All is implemented the facedFainted and else can be collapsed into the 1.0 return value
facedFainted -> 1.0
else -> continue
}
val experience = Cobblemon.experienceCalculator.calculate(opponentPokemon, faintedPokemon, multiplier)
if (experience > 0) {
opponent.awardExperience(opponentPokemon, experience)
}
Cobblemon.evYieldCalculator.calculate(opponentPokemon, faintedPokemon).forEach { (stat, amount) ->
pokemon.evs.add(stat, amount)
}
for (actor in actors) {
for (pokemon in actor.pokemonList.filter { it.health > 0 }) {
if (pokemon.facedOpponents.isNotEmpty() /* TODO exp share held item check */) {
val experience = Cobblemon.experienceCalculator.calculate(pokemon)
if (experience > 0) {
actor.awardExperience(pokemon, (experience * Cobblemon.config.experienceMultiplier).toInt())
}
Cobblemon.evYieldCalculator.calculate(pokemon).forEach { (stat, amount) ->
pokemon.originalPokemon.evs.add(stat, amount)
}
}
}
}
// Heal Mon if wild
actors.filter { it.type == ActorType.WILD }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filterIsInstance<PokemonEntity>()
.forEach{it.pokemon.heal()}
actors.forEach { actor ->
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.entity?.let { entity -> battlePokemon.postBattleEntityOperation(entity) }
}
}
sendUpdate(BattleEndPacket())
sendUpdate(BattleMusicPacket(null))
BattleRegistry.closeBattle(this)
}
@@ -260,56 +201,24 @@ open class PokemonBattle(
if (!mute) {
LOGGER.info(message)
}
battleLog.add(message)
}
fun saveBattleLog() {
val battleLogsDir = File("./battle_logs/")
if (!battleLogsDir.exists()) {
battleLogsDir.mkdirs()
}
val logFile = File(battleLogsDir, "$battleId.txt")
logFile.bufferedWriter().use { out ->
battleLog.forEach {
out.write(it)
out.newLine()
}
}
LOGGER.info("Saved battle log as $battleId.txt")
}
fun sendUpdate(packet: NetworkPacket<*>) {
fun sendUpdate(packet: NetworkPacket) {
actors.forEach { it.sendUpdate(packet) }
sendSpectatorUpdate(packet)
}
/**
* Sends a packet depending on the side of an actor.
*
* @param source The actor that triggered the necessity for this update.
* @param allyPacket The packet sent to the [source] and their allies.
* @param opponentPacket The packet sent to the opposing actors.
* @param spectatorsAsAlly If the spectators receive the [allyPacket] or the [opponentPacket], default is false.
*/
fun sendSidedUpdate(source: BattleActor, allyPacket: NetworkPacket<*>, opponentPacket: NetworkPacket<*>, spectatorsAsAlly: Boolean = false) {
source.getSide().actors.forEach { it.sendUpdate(allyPacket) }
source.getSide().getOppositeSide().actors.forEach { it.sendUpdate(opponentPacket) }
sendSpectatorUpdate(if (spectatorsAsAlly) allyPacket else opponentPacket)
fun sendToActors(packet: NetworkPacket) {
CobblemonNetwork.sendToPlayers(actors.flatMap { it.getPlayerUUIDs().mapNotNull { it.getPlayer() } }, packet)
}
fun sendToActors(packet: NetworkPacket<*>) {
CobblemonNetwork.sendPacketToPlayers(actors.flatMap { it.getPlayerUUIDs().mapNotNull { it.getPlayer() } }, packet)
}
fun sendSplitUpdate(privateActor: BattleActor, publicPacket: NetworkPacket<*>, privatePacket: NetworkPacket<*>) {
fun sendSplitUpdate(privateActor: BattleActor, publicPacket: NetworkPacket, privatePacket: NetworkPacket) {
actors.forEach { it.sendUpdate(if (it == privateActor) privatePacket else publicPacket) }
sendSpectatorUpdate(publicPacket)
}
fun sendSpectatorUpdate(packet: NetworkPacket<*>) {
CobblemonNetwork.sendPacketToPlayers(spectators.mapNotNull { it.getPlayer() }, packet)
fun sendSpectatorUpdate(packet: NetworkPacket) {
CobblemonNetwork.sendToPlayers(spectators.mapNotNull { it.getPlayer() }, packet)
}
fun dispatch(dispatcher: () -> DispatchResult) {
@@ -323,13 +232,6 @@ open class PokemonBattle(
}
}
fun dispatchWaiting(delaySeconds: Float = 1F, dispatcher: () -> Unit) {
dispatch {
dispatcher()
WaitDispatch(delaySeconds)
}
}
fun dispatchInsert(dispatcher: () -> Iterable<BattleDispatch>) {
dispatch {
val newDispatches = dispatcher()
@@ -345,31 +247,13 @@ open class PokemonBattle(
dispatches.add(dispatcher)
}
fun doWhenClear(action: () -> Unit) {
afterDispatches.add(action)
}
fun tick() {
try {
while (dispatchResult.canProceed()) {
val dispatch = dispatches.poll() ?: break
dispatchResult = dispatch(this)
}
if (dispatches.isEmpty()) {
afterDispatches.toList().forEach { it() }
afterDispatches.clear()
}
} catch (e: Exception) {
LOGGER.error("Exception while ticking a battle. Saving battle log.", e)
val message = battleLang("crash").red()
this.actors.filterIsInstance<PlayerBattleActor>().forEach { it.entity?.sendMessage(message) }
this.saveBattleLog()
this.stop()
return
while (dispatchResult.canProceed()) {
val dispatch = dispatches.poll() ?: break
dispatchResult = dispatch(this)
}
if (started && isPvW && !ended && dispatches.isEmpty()) {
if (started && isPvW && !ended) {
checkFlee()
}
}
@@ -380,27 +264,18 @@ open class PokemonBattle(
.filterIsInstance<FleeableBattleActor>()
.filter { it.getWorldAndPosition() != null }
.none { pokemonActor ->
if (pokemonActor.fleeDistance == -1F) true
else {
val (world, pos) = pokemonActor.getWorldAndPosition()!!
val nearestPlayerActorDistance = actors.asSequence()
.filter { it.type == ActorType.PLAYER }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filter { it.world == world }
.minOfOrNull { pos.distanceTo(it.pos) }
val (world, pos) = pokemonActor.getWorldAndPosition()!!
val nearestPlayerActorDistance = actors
.filter { it.type == ActorType.PLAYER }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filter { it.world == world }
.minOfOrNull { pos.distanceTo(it.pos) }
nearestPlayerActorDistance != null && nearestPlayerActorDistance < pokemonActor.fleeDistance
}
nearestPlayerActorDistance != null && nearestPlayerActorDistance < pokemonActor.fleeDistance
}
if (wildPokemonOutOfRange) {
// Heal Wild Pokemon
actors.filter { it.type == ActorType.WILD }
.filterIsInstance<EntityBackedBattleActor<*>>()
.mapNotNull { it.entity }
.filterIsInstance<PokemonEntity>()
.forEach{it.pokemon.heal()}
CobblemonEvents.BATTLE_FLED.post(BattleFledEvent(this, actors.asSequence().filterIsInstance<PlayerBattleActor>().iterator().next()))
actors.filterIsInstance<EntityBackedBattleActor<*>>().mapNotNull { it.entity }.forEach { it.sendMessage(battleLang("flee").yellow()) }
stop()
}
@@ -418,35 +293,4 @@ open class PokemonBattle(
actors.forEach { it.responses.clear() ; it.request = null }
}
}
/**
* Creates a [Text] representation of an error to interpret a battle message.
* This also logs the error, the goal of this function is to make sure users see missing interpretations and report them to us.
* Logging is independent of [mute].
*
* @param message The [BattleMessage] that wasn't able to find a lang interpretation.
* @return The generated [Text] meant to notify the client.
*/
internal fun createUnimplemented(message: BattleMessage): Text {
LOGGER.error("Missing interpretation on '{}' action {}", message.id, message.rawMessage)
return Text.literal("Missing interpretation on '${message.id}' action ${message.rawMessage}").red()
}
/**
* A variant of [createUnimplemented].
* This will log both the public and private message however the clients will no longer receive the full raw message in order to prevent extra information they shouldn't see.
*
* @param publicMessage The public variant of [BattleMessage] that wasn't able to find a lang interpretation.
* @param privateMessage The private variant of [BattleMessage] that wasn't able to find a lang interpretation.
* @return The generated [Text] meant to notify the client.
*
* @throws IllegalArgumentException if the [publicMessage] and [privateMessage] don't have a matching [BattleMessage.id].
*/
internal fun createUnimplementedSplit(publicMessage: BattleMessage, privateMessage: BattleMessage): Text {
if (publicMessage.id != privateMessage.id) {
throw IllegalArgumentException("Messages do not match")
}
LOGGER.error("Missing interpretation on '{}' action: \nPublic » {}\nPrivate » {}", publicMessage.id, publicMessage.rawMessage, privateMessage.rawMessage)
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,12 +8,9 @@
package com.cobblemon.mod.common.api.battles.model.actor
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.battles.model.ai.BattleAI
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.battles.PassActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import java.util.UUID
@@ -22,17 +19,11 @@ abstract class AIBattleActor(
pokemonList: List<BattlePokemon>,
val battleAI: BattleAI
) : BattleActor(gameId, pokemonList.toMutableList()) {
override fun sendUpdate(packet: NetworkPacket<*>) {
override fun sendUpdate(packet: NetworkPacket) {
super.sendUpdate(packet)
if (packet is BattleMakeChoicePacket) {
try {
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose))
} catch (exception: IllegalActionChoiceException) {
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
exception.printStackTrace()
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
}
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose) )
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -11,13 +11,12 @@ package com.cobblemon.mod.common.api.battles.model.actor
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.battles.ActiveBattlePokemon
import com.cobblemon.mod.common.battles.ForcePassActionResponse
import com.cobblemon.mod.common.battles.BallActionResponse
import com.cobblemon.mod.common.battles.ShowdownActionRequest
import com.cobblemon.mod.common.battles.ShowdownActionResponse
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
import com.cobblemon.mod.common.net.messages.client.battle.BattleApplyPassResponsePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
import java.util.UUID
@@ -41,24 +40,11 @@ abstract class BattleActor(
var request: ShowdownActionRequest? = null
var responses = mutableListOf<ShowdownActionResponse>()
val expectingPassActions = mutableListOf<ShowdownActionResponse>()
var expectingCaptureActions = 0
var mustChoose = false
/** For when battles start, it's the number of Pokémon that are still in the process of being sent out (animation wise) */
var stillSendingOutCount = 0
abstract val type: ActorType
fun canFitForcedAction() = mustChoose && request?.let { request ->
val countMovable = (request.active?.count() ?: 0) - request.forceSwitch.count { it }
return@let countMovable > expectingPassActions.size && !battle.ended
} ?: false
fun forceChoose(response: ShowdownActionResponse) {
expectingPassActions.add(response)
sendUpdate(BattleApplyPassResponsePacket())
}
fun getSide() = if (this in battle.side1.actors) battle.side1 else battle.side2
open fun getPlayerUUIDs(): Iterable<UUID> = emptyList()
@@ -74,7 +60,7 @@ abstract class BattleActor(
val requestActive = request.active
if (requestActive == null || requestActive.isEmpty() || request.wait) {
this.request = null
expectingPassActions.clear()
expectingCaptureActions = 0
return
}
}
@@ -92,24 +78,23 @@ abstract class BattleActor(
fun setActionResponses(responses: List<ShowdownActionResponse>) {
val request = request ?: return
val originalPassActions = expectingPassActions.toList()
val originalCaptureActions = expectingCaptureActions
responses.forEachIndexed { index, response ->
val activeBattlePokemon = activePokemon.let { if (it.size > index) it[index] else return }
val showdownMoveSet = request.active?.let { if (it.size > index) it[index] else null }
val forceSwitch = request.forceSwitch.let { if (it.size > index) it[index] else false }
if (!response.isValid(activeBattlePokemon, showdownMoveSet, forceSwitch)) {
expectingPassActions.clear()
expectingPassActions.addAll(originalPassActions)
expectingCaptureActions = originalCaptureActions
throw IllegalActionChoiceException(this, "Invalid action choice for ${activeBattlePokemon.battlePokemon!!.getName().string}: $response")
} else if (response is ForcePassActionResponse) {
this.responses.add(expectingPassActions.removeAt(0))
} else {
this.responses.add(response)
} else if (response is BallActionResponse) {
expectingCaptureActions--
}
this.responses.add(response)
}
if (expectingPassActions.size > 0) {
if (expectingCaptureActions > 0) {
throw IllegalActionChoiceException(this, "Invalid action choice: a capture was expected. Are you hacking me?")
}
expectingCaptureActions = originalCaptureActions
mustChoose = false
battle.checkForInputDispatch()
}
@@ -125,24 +110,14 @@ abstract class BattleActor(
}
responses.clear()
request = null
expectingPassActions.clear()
expectingCaptureActions = 0
battle.writeShowdownAction(">$showdownId ${showdownMessages.joinToString()}")
}
abstract fun getName(): MutableText
/**
* Appends the given name to this owner as the prefix.
* NPC and player actors expect to append their [getName] while wild Pokémon append nothing.
*
* @param name The name of an object being appended, typically a Pokémon nickname received from showdown.
* @return A [MutableText] of the [name] append with owner prefix.
*/
abstract fun nameOwned(name: String): MutableText
open fun sendMessage(component: Text) {
sendUpdate(BattleMessagePacket(component))
}
open fun awardExperience(battlePokemon: BattlePokemon, experience: Int) {}
open fun sendUpdate(packet: NetworkPacket<*>) {}
open fun sendUpdate(packet: NetworkPacket) {}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,133 +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.callback
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.moves.Move
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.InBattleMove
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.writeSizedInt
import java.util.UUID
import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
/**
* Used for opening move selection screens for players and handling their choice. Currently
* only supports up to 4 moves to select from.
*
* @author Hiroku
* @since July 1st, 2023
*/
object MoveSelectCallbacks {
val callbacks = mutableMapOf<UUID, MoveSelectCallback>()
@JvmOverloads
fun create(
player: ServerPlayerEntity,
title: Text = "".text(),
possibleMoves: List<MoveSelectDTO>,
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (ServerPlayerEntity, index: Int, MoveSelectDTO) -> Unit
) {
val callback = MoveSelectCallback(
shownMoves = possibleMoves,
cancel = cancel,
handler = handler
)
callbacks[player.uuid] = callback
player.sendPacket(OpenMoveCallbackPacket(callback.uuid, title.copy(), possibleMoves))
}
@JvmOverloads
fun create(
player: ServerPlayerEntity,
moves: List<Move>,
canSelect: (Move) -> Boolean = { true },
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (Move) -> Unit
) = create(
player = player,
possibleMoves = moves.map { battleMove -> MoveSelectDTO(battleMove).also { it.enabled = canSelect(battleMove) } },
cancel = cancel,
handler = { _, index, _ -> handler(moves[index]) }
)
@JvmOverloads
fun createBattleSelect(
player: ServerPlayerEntity,
moves: List<InBattleMove>,
canSelect: (InBattleMove) -> Boolean = { true },
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (InBattleMove) -> Unit
) = create(
player = player,
possibleMoves = moves.map { battleMove -> MoveSelectDTO(battleMove).also { it.enabled = canSelect(battleMove) } },
cancel = cancel,
handler = { _, index, _ -> handler(moves[index]) }
)
fun handleCancelled(player: ServerPlayerEntity, uuid: UUID) {
val callback = callbacks[player.uuid] ?: return
if (callback.uuid != uuid) {
return
}
callbacks.remove(player.uuid)
callback.cancel(player)
}
fun handleCallback(player: ServerPlayerEntity, uuid: UUID, index: Int) {
val callback = callbacks[player.uuid] ?: return
callbacks.remove(player.uuid)
if (callback.uuid != uuid) {
Cobblemon.LOGGER.warn("A move select callback ran but with a mismatching UUID from ${player.gameProfile.name}. Hacking attempts?")
} else if (index >= callback.shownMoves.size) {
Cobblemon.LOGGER.warn("${player.gameProfile.name} used move select callback with an index that was out of bounds. Hacking attempts? Tried $index, possible size was ${callback.shownMoves.size}")
} else if (!callback.shownMoves[index].enabled) {
Cobblemon.LOGGER.warn("${player.gameProfile.name} used move select callback with a move that is not enabled. Hacking attempts?")
} else {
callback.handler(player, index, callback.shownMoves[index])
}
}
}
class MoveSelectCallback(
val uuid: UUID = UUID.randomUUID(),
val shownMoves: List<MoveSelectDTO>,
val cancel: (ServerPlayerEntity) -> Unit = {},
val handler: (ServerPlayerEntity, Int, MoveSelectDTO) -> Unit
)
class MoveSelectDTO(val moveTemplate: MoveTemplate, var enabled: Boolean, val pp: Int = -1, val ppMax: Int = -1) {
@JvmOverloads
constructor(move: Move, enabled: Boolean = true): this(moveTemplate = move.template, enabled = enabled, pp = move.currentPp, ppMax = move.maxPp)
@JvmOverloads
constructor(move: InBattleMove, enabled: Boolean = true): this(moveTemplate = Moves.getByNameOrDummy(move.move), enabled = enabled, pp = move.pp, ppMax = move.maxpp)
constructor(buffer: PacketByteBuf): this(
moveTemplate = Moves.getByNameOrDummy(buffer.readString()),
enabled = buffer.readBoolean(),
pp = buffer.readSizedInt(IntSize.BYTE),
ppMax = buffer.readSizedInt(IntSize.BYTE)
)
fun writeToBuffer(buffer: PacketByteBuf) {
buffer.writeString(moveTemplate.name)
buffer.writeBoolean(enabled)
buffer.writeSizedInt(IntSize.BYTE, pp)
buffer.writeSizedInt(IntSize.BYTE, ppMax)
}
}
@@ -1,114 +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.callback
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.moves.Move
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
/**
* Used for opening a party select screen for players which routes to move selection when they choose a Pokémon.
* You can do the same sort of thing with combined [MoveSelectCallbacks] and [PartySelectCallbacks] but it isn't
* as smooth an experience.
*
* @author Hiroku
* @since July 29th, 2023
*/
object PartyMoveSelectCallbacks {
val callbacks = mutableMapOf<UUID, PartyMoveSelectCallback>()
@JvmOverloads
fun create(
player: ServerPlayerEntity,
pokemon: List<Pair<PartySelectPokemonDTO, List<MoveSelectDTO>>>,
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (ServerPlayerEntity, pokemonIndex: Int, PartySelectPokemonDTO, moveIndex: Int, MoveSelectDTO) -> Unit
) {
val callback = PartyMoveSelectCallback(
pokemon = pokemon,
cancel = cancel,
handler = handler
)
callbacks[player.uuid] = callback
player.sendPacket(OpenPartyMoveCallbackPacket(callback.uuid, callback.pokemon))
}
@JvmOverloads
fun createFromPokemon(
player: ServerPlayerEntity,
pokemon: List<Pokemon>,
moves: (Pokemon) -> List<Move> = { it.moveSet.getMoves() },
canSelectPokemon: (Pokemon) -> Boolean = { true },
canSelectMove: (Pokemon, Move) -> Boolean = { _, _ -> true },
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (Pokemon, Move) -> Unit
) {
val pokemonList = mutableListOf<Pair<PartySelectPokemonDTO, List<MoveSelectDTO>>>()
for (pk in pokemon) {
val enabled = canSelectPokemon(pk)
val moveList = moves(pk).map { MoveSelectDTO(it, enabled = canSelectMove(pk, it)) }
pokemonList.add(PartySelectPokemonDTO(pk, enabled) to moveList)
}
create(
player = player,
pokemon = pokemonList,
cancel = cancel,
handler = { _, pkIndex, _, moveIndex, _ ->
handler(pokemon[pkIndex], pokemon[pkIndex].moveSet[moveIndex] ?: return@create)
}
)
}
fun handleCancelled(player: ServerPlayerEntity, uuid: UUID) {
val callback = callbacks[player.uuid] ?: return
if (callback.uuid != uuid) {
return
}
callbacks.remove(player.uuid)
callback.cancel(player)
}
fun handleCallback(player: ServerPlayerEntity, uuid: UUID, pokemonIndex: Int, moveIndex: Int) {
val callback = callbacks[player.uuid] ?: return
callbacks.remove(player.uuid)
if (callback.uuid != uuid) {
return Cobblemon.LOGGER.warn("A party move select callback ran but with a mismatching UUID from ${player.gameProfile.name}. Hacking attempts?")
} else if (pokemonIndex >= callback.pokemon.size) {
return Cobblemon.LOGGER.warn("${player.gameProfile.name} used party move select callback with a Pokémon index that was out of bounds. Hacking attempts? Tried $pokemonIndex, possible size was ${callback.pokemon.size}")
}
val (pokemon, moves) = callback.pokemon[pokemonIndex]
if (!pokemon.enabled) {
return Cobblemon.LOGGER.warn("${player.gameProfile.name} used party move select callback with a Pokémon that is not enabled. Hacking attempts?")
} else if (moveIndex >= moves.size) {
return Cobblemon.LOGGER.warn("${player.gameProfile.name} used party move select callback with a move index that was out of bounds. Hacking attempts? Tried $pokemonIndex-$moveIndex, possible size was ${moves.size}")
}
val move = moves[moveIndex]
if (!move.enabled) {
Cobblemon.LOGGER.warn("${player.gameProfile.name} used party move select callback with a move that is not enabled. Hacking attempts?")
} else {
callback.handler(player, pokemonIndex, pokemon, moveIndex, move)
}
}
}
class PartyMoveSelectCallback(
val uuid: UUID = UUID.randomUUID(),
val pokemon: List<Pair<PartySelectPokemonDTO, List<MoveSelectDTO>>>,
val cancel: (ServerPlayerEntity) -> Unit = {},
val handler: (ServerPlayerEntity, pokemonIndex: Int, PartySelectPokemonDTO, moveIndex: Int, MoveSelectDTO) -> Unit
)
@@ -1,152 +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.callback
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonPropertyExtractor
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import java.util.UUID
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.PacketByteBuf
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
/**
* Used for opening party Pokémon selection screens for players and handling their choice. Currently
* only supports up to 6 Pokémon to select from.
*
* @author Hiroku
* @since July 1st, 2023
*/
object PartySelectCallbacks {
val callbacks = mutableMapOf<UUID, PartySelectCallback>()
@JvmOverloads
fun create(
player: ServerPlayerEntity,
title: Text = "".text(),
pokemon: List<PartySelectPokemonDTO>,
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (ServerPlayerEntity, index: Int) -> Unit
) {
val callback = PartySelectCallback(
shownPokemon = pokemon,
cancel = cancel,
handler = handler
)
callbacks[player.uuid] = callback
player.sendPacket(
OpenPartyCallbackPacket(
uuid = callback.uuid,
title = title.copy(),
pokemon = pokemon
)
)
}
@JvmOverloads
fun createBattleSelect(
player: ServerPlayerEntity,
pokemon: List<BattlePokemon>,
canSelect: (BattlePokemon) -> Boolean,
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (BattlePokemon) -> Unit
) = create(
player = player,
cancel = cancel,
pokemon = pokemon.map { pk -> PartySelectPokemonDTO(pk.effectedPokemon).also { it.enabled = canSelect(pk) } }
) { _, index -> handler(pokemon[index]) }
@JvmOverloads
fun createFromPokemon(
player: ServerPlayerEntity,
pokemon: List<Pokemon>,
canSelect: (Pokemon) -> Boolean,
cancel: (ServerPlayerEntity) -> Unit = {},
handler: (Pokemon) -> Unit
) = create(
player = player,
cancel = cancel,
pokemon = pokemon.map { pk -> PartySelectPokemonDTO(pk).also { it.enabled = canSelect(pk) } }
) { _, index -> handler(pokemon[index]) }
fun handleCancelled(player: ServerPlayerEntity, uuid: UUID) {
val callback = callbacks[player.uuid] ?: return
if (callback.uuid != uuid) {
return
}
callbacks.remove(player.uuid)
callback.cancel(player)
}
fun handleCallback(player: ServerPlayerEntity, uuid: UUID, index: Int) {
val callback = callbacks[player.uuid] ?: return
callbacks.remove(player.uuid)
if (callback.uuid != uuid) {
Cobblemon.LOGGER.warn("A party select callback ran but with a mismatching UUID from ${player.gameProfile.name}. Hacking attempts?")
} else if (index >= callback.shownPokemon.size) {
Cobblemon.LOGGER.warn("${player.gameProfile.name} used party select callback with an out of bounds index. Hacking attempts? Tried $index, Pokémon list size was ${callback.shownPokemon.size}")
} else if (!callback.shownPokemon[index].enabled) {
Cobblemon.LOGGER.warn("${player.gameProfile.name} used party select callback with a Pokémon that is not enabled. Hacking attempts?")
} else {
callback.handler(player, index)
}
}
}
class PartySelectCallback(
val uuid: UUID = UUID.randomUUID(),
val shownPokemon: List<PartySelectPokemonDTO>,
val cancel: (ServerPlayerEntity) -> Unit = {},
val handler: (ServerPlayerEntity, index: Int) -> Unit
)
open class PartySelectPokemonDTO(
val pokemonProperties: PokemonProperties,
val heldItem: ItemStack = ItemStack.EMPTY,
var hpRatio: Float = 1F,
var enabled: Boolean
) {
@JvmOverloads
constructor(pokemon: Pokemon, enabled: Boolean = true): this(
pokemonProperties = pokemon.createPokemonProperties(
PokemonPropertyExtractor.ASPECTS,
PokemonPropertyExtractor.SPECIES,
PokemonPropertyExtractor.LEVEL,
PokemonPropertyExtractor.NICKNAME,
PokemonPropertyExtractor.POKEBALL,
PokemonPropertyExtractor.STATUS
),
heldItem = pokemon.heldItemNoCopy(),
hpRatio = pokemon.currentHealth / pokemon.hp.toFloat(),
enabled = enabled
)
constructor(buffer: PacketByteBuf): this(
pokemonProperties = PokemonProperties().loadFromNBT(buffer.readNbt() as NbtCompound),
heldItem = buffer.readItemStack(),
hpRatio = buffer.readFloat(),
enabled = buffer.readBoolean()
)
fun writeToBuffer(buffer: PacketByteBuf) {
buffer.writeNbt(pokemonProperties.saveToNBT())
buffer.writeItemStack(heldItem)
buffer.writeFloat(hpRatio)
buffer.writeBoolean(enabled)
}
}
@@ -1,47 +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.codec
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.network.PacketByteBuf
class MappedCodec<A : CodecMapped, K>(
val codecRetriever: (K) -> Codec<out A>,
val keyName: String = "type",
val keyFromString: (String) -> K
) : Codec<A> {
override fun <T> encode(input: A, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return input.encode(ops)
}
override fun <T> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<A, T>> {
val thingCodec: Codec<ThingWithType> = RecordCodecBuilder.create { instance ->
instance
.group(PrimitiveCodec.STRING.fieldOf(keyName).forGetter { it.string })
.apply(instance, ::ThingWithType)
}
val thingWithType = thingCodec.decode(ops, input).map { it.first }
val key = thingWithType.get().left().get().string
val codec = codecRetriever(keyFromString(key))
return codec.decode(ops, input).map { Pair(it.first, it.second) }
}
}
private class ThingWithType(val string: String)
interface CodecMapped {
fun <T> encode(ops: DynamicOps<T>): DataResult<T>
fun readFromBuffer(buffer: PacketByteBuf)
fun writeToBuffer(buffer: PacketByteBuf)
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.conditional
import net.minecraft.registry.Registry
import net.minecraft.util.registry.Registry
/**
* A condition which applies to an entry in some [Registry].
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,8 +9,8 @@
package com.cobblemon.mod.common.api.conditional
import com.google.gson.JsonElement
import net.minecraft.registry.Registry
import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry
/**
* A condition for some registry type which asserts that the entry must have the given [Identifier].
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -9,10 +9,10 @@
package com.cobblemon.mod.common.api.conditional
import com.google.gson.JsonElement
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.tag.TagKey
import net.minecraft.tag.TagKey
import net.minecraft.util.Identifier
import net.minecraft.util.registry.Registry
import net.minecraft.util.registry.RegistryKey
/**
* A condition for some registry type that asserts that the entry must be inside the given [TagKey]. This is presented
@@ -40,11 +40,11 @@ open class RegistryLikeTagCondition<T>(val tag: TagKey<T>) : RegistryLikeConditi
}
override fun fits(t: T, registry: Registry<T>): Boolean {
// val registryHasTag = registry.containsTag(tag)
// if (!registryHasTag) {
//// LOGGER.warn("No tag in registry: ${tag.id}")
// return false
// }
val registryHasTag = registry.containsTag(tag)
if (!registryHasTag) {
// LOGGER.warn("No tag in registry: ${tag.id}")
return false
}
return registry.getKey(t)
.flatMap(registry::getEntry)
@@ -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.api.data
import com.cobblemon.mod.common.api.codec.CodecMapped
import com.cobblemon.mod.common.api.codec.MappedCodec
import com.mojang.serialization.Codec
import net.minecraft.network.PacketByteBuf
/**
* A utility class to help give Codec support for map adapted class hierarchies.
*
* @author Hiroku
* @since January 21st, 2023
*/
abstract class ArbitrarilyMappedSerializableCompanion<T : CodecMapped, K>(
val keyFromString: (String) -> K,
val stringFromKey: (K) -> String,
val keyFromValue: (T) -> K
) {
val codec: MappedCodec<T, K> = MappedCodec(codecRetriever = { subtypes[it]!!.codec }, keyFromString = keyFromString)
private val subtypes = mutableMapOf<K, RegisteredSubtype<out T>>()
fun <E : T> registerSubtype(key: K, clazz: Class<E>, codec: Codec<E>) {
subtypes[key] = RegisteredSubtype(clazz, codec)
}
fun writeToBuffer(buffer: PacketByteBuf, value: T) {
val typeString = stringFromKey(keyFromValue(value))
buffer.writeString(typeString)
value.writeToBuffer(buffer)
}
fun readFromBuffer(buffer: PacketByteBuf): T {
val typeString = buffer.readString()
val clazz = subtypes[keyFromString(typeString)]?.clazz ?: throw IllegalArgumentException("Unrecognized subtype: $typeString")
val value = clazz.getDeclaredConstructor().newInstance()
value.readFromBuffer(buffer)
return value
}
}
class RegisteredSubtype<T>(val clazz: Class<out T>, val codec: Codec<out T>)
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
* Copyright (C) 2022 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

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