Compare commits

..
14 Commits
Author SHA1 Message Date
JPAKx4 099bee8d5d Added jsons to resolve textures and en_us names. 2023-11-14 12:53:04 -06:00
JPAKx4 5a926ffa23 Added new hold items to registries and groups 2023-11-13 21:55:34 -06:00
JPAKx4 d7d32a186b Merge remote-tracking branch 'origin/HOLDY' into HOLDY
# Conflicts:
#	common/src/main/resources/data/cobblemon/species/generation6/aromatisse.json
2023-11-13 20:54:56 -06:00
JPAKx4 f437b7a7ff Added new hold items to registries and groups 2023-11-13 20:53:08 -06:00
miasmus ff4ef2d90b changelog 2023-11-13 20:53:06 -06:00
miasmus 5fb39bba2b data changes for new items, add to lang file 2023-11-13 20:52:59 -06:00
miasmus e4798e6793 Added items to registry and groups 2023-11-13 20:52:20 -06:00
dhi_holo ce6ef64cec Hold this for me please
47 new recipes and their advancements.
Ability Shield, Air Balloon, Amulet Coin, Binding Band, Blunder Policy, Cell Battery, Clear Amulet, Covert Cloak, Destiny Knot, Eject Button, Eject Pack, Expert Belt, Flame Orb, Focus Sash, Lagging Tail, Life Orb, Loaded Dice, Luminous Moss, Metronome, Pink Bow, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Punching Glove, Red Card, Ring Target, Room Service, Scope Lens, Shell Bell, Soothe Bell, Terrain Extender, Throat Spray, Toxic Orb, Utility Umbrella, Weakness Policy, Heat Rock, Damp Rock, Icy Rock, Smooth Rock, Wide Lens, Zoom Lens, Iron Ball, and Bright Powder
2023-11-13 20:51:30 -06:00
miasmus 6d52b8f690 changelog 2023-10-20 12:45:32 -04:00
miasmus b1c804d567 data changes for new items, add to lang file 2023-10-19 17:29:02 -04:00
miasmus b386d1a806 added cleanse tag and fairy feather, edit relevant species drops 2023-10-19 17:28:36 -04:00
miasmus 01ea8daedf Merge remote-tracking branch 'origin/main' into HOLDY
# Conflicts:
#      CHANGELOG.md
#      destiny_knot.json
2023-10-19 17:23:43 -04:00
Paul a449396dc3 Merge remote-tracking branch 'origin/main' into HOLDY
# Conflicts:
#	CHANGELOG.md
2023-09-03 13:26:30 +10:00
dhi_holo ed3b0e9630 Hold this for me please
47 new recipes and their advancements.
Ability Shield, Air Balloon, Amulet Coin, Binding Band, Blunder Policy, Cell Battery, Clear Amulet, Covert Cloak, Destiny Knot, Eject Button, Eject Pack, Expert Belt, Flame Orb, Focus Sash, Lagging Tail, Life Orb, Loaded Dice, Luminous Moss, Metronome, Pink Bow, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Punching Glove, Red Card, Ring Target, Room Service, Scope Lens, Shell Bell, Soothe Bell, Terrain Extender, Throat Spray, Toxic Orb, Utility Umbrella, Weakness Policy, Heat Rock, Damp Rock, Icy Rock, Smooth Rock, Wide Lens, Zoom Lens, Iron Ball, and Bright Powder
2023-06-26 13:36:05 +10:00
7803 changed files with 43601 additions and 477327 deletions

No files matched your search

-7
View File
@@ -21,8 +21,6 @@ build
# other
eclipse
run
runClient
runServer
# Files from Forge MDK
forge*changelog.txt
@@ -35,8 +33,3 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
common/.fabric
# MacOS
.DS_Store
-30
View File
@@ -1,30 +0,0 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your issue has already been reported. If it has, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the issue was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can to make sure the issue can get fixed asap. -->
## Summary
(Please summarize the bug encountered concisely)
## Steps to reproduce
(How one can reproduce the issue - this is very important)
## What is the current bug behavior?
(What actually happens)
## What is the expected correct behavior?
(What you should see instead)
## Cobblemon Version and Mod Loader
(Are you using Forge or Fabric? And what version of Cobblemon are you using?)
## Mods used besides Cobblemon
(Did you have any other mods installed besides Cobblemon? If so, please list them here)
## Relevant logs, screenshots and/or videos
(Paste any relevant logs - use code blocks (```) at the start and end to format console output, logs, and code, as
it's very hard to read otherwise. Or just put a link here)
## Additional Information
(If you can, link to the line of code that might be responsible for the problem, or any other info that might be useful)
/label ~bug
@@ -1,31 +0,0 @@
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your feature was already requested. If it is, please add a comment to the existing issue instead of creating a new one.)-->
<!-- 2. If the feature request was not already reported, please fill out the following template. -->
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can. -->
<!-- 4. The more info you provide here, the greater the chance of it being considered by the Design team. -->
## Summary
(Please summarize your feature request concisely)
## What are the projected benefits of this feature?
- (List)
- (benefits)
- (here)
## What could speak against this feature?
- (List)
- (possible)
- (cons)
## Why do you think the benefits outweigh the cons?
(Explain why you think the benefits outweigh the cons)
## Mods involved besides Cobblemon
(Does your suggestion require any other mods besides Cobblemon? If so, please list them here)
## Sketches, screenshots and/or videos
(Feel free to add any sketches, screenshots or videos that might help the Design team understand your suggestion)
## Additional Information
(Is there anything else you would like to add?)
/label ~feature ~suggestion ~needs-design
+43 -489
View File
@@ -1,478 +1,69 @@
# Changelog
## [1.6.0 - The Bass Pro Fishing Update (Month Xth, 2024)](#1-6-0)
#### "Now that there's a fishing mechanic, the mod is actually good!"
### Additions
- Added Pokémon (and item) fishing using modified fishing rods - Poké Rods! You'll need a Poké Rod smithing template, a fishing rod, and some type of Poké Ball. Each Poké Ball makes a differently themed rod. Why not?
- Added Lure Ball functionality, increasing the catch rate of Pokémon that were caught on a fishing rod.
- Added property chaining support for duplicate CustomPokemonPropertyType elements.
- Added aspect and unaspect PokemonProperty arguments (which also includes commands such as /pokemonedit, /spawnpokemon, and /givepokemon) to allow forcing or un-forcing an aspect on a Pokémon.
### Developer
- SpawnCause is now an implementation of SpawningInfluence.
- Added "forcedAspects" to Pokemon to make it easier to easily add basic aspects to a Pokémon in a way that persists. We already know that everyone is going to overuse this.
- Made the Pokemon.aspects setter private. This could technically break sidemods but if you are affected by this then you were using it wrong! Use Pokemon.forcedAspects to fix it.
## [1.5.1](#1-5-1)
### Additions
- Added unique send out particles for Cherish, Dream, Beast, and Ancient Origin balls.
## [1.4.1](#1-4-1)
### Changes
- Sounds for Relic Coin Sacks have been correctly renamed. Relic Coin Pouches received new sounds for breaking and placing.
### Fixes
- Fixed a bug in which adding organic material to the fossil tank via right click was adding the full count of the stack currently in hand
- Fixed a niche issue where some properties of entities were not initialized correctly, causing Pokémon that appeared to be level 1 until you battle them.
- Fixed Fossilized Drake being missing from the Fossils item tag.
- Fixed PCStore#resize not allowing PC boxes size reduction.
### Developer
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. More information this way.
### Data Pack & Resource Pack Creators
- Added support for MoLang conditions for quirks and poses.
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual.
## [1.5.0 - The Ruins and Revival Update (May 12th, 2024)](#1-5-0)
#### "You're telling me that Mojang has added archaeology to the game? Hmm... that gives me an idea."
### Additions
- Added 17 ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
- Added 23 fossil structures, where you can brush Suspicious Sand/Gravel for [Fossils](https://wiki.cobblemon.com/index.php/Fossil). You can add [custom fossils using datapacks](https://wiki.cobblemon.com/index.php/Fossils_File).
- Added the Data Monitor, Fossil Compartment, and Restoration Tank blocks. Placed in the correct formation, you can use these to create a [Restoration Machine](https://wiki.cobblemon.com/index.php/Resurrection_Machine) where you can bring fossils back to life. Use organic material to fill the tank first!
- Added 3 variants of [Tumblestone](https://wiki.cobblemon.com/index.php/Tumblestone), which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will receive more functionality in a future update.
- Added visual effects for many Poké Balls when sending out or capturing Pokémon.
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
- Added simple move animations for Pokémon in battle with a proof of concept (Flamethrower) for more complicated animations. More and more specific animations will come in future updates.
- Added Original Trainer to the summary menu. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
- Added the hidden "True Vivillionaire" advancement.
- Added the [Display Case](https://wiki.cobblemon.com/index.php/Display_Case) block. Use it to display your archaeological findings, Poké Balls, or other items.
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures. Sherds... sh-erds. Weird word.
- Added a Pokémon-themed armor trim, obtained from ruin structures.
- Added Nether Fire Stone Ore to, surprisingly, the Nether.
- Added Terracotta Sun Stone Ore to Badlands biomes.
- Added the EV Boosting Feathers.
- Added [Gilded Chests](https://wiki.cobblemon.com/index.php/Gilded_Chest), available in all Apricorn colors.
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks. Gimmighoul might be interested in these.
- Added Type Gems. These will have additional uses later, so you should start collecting them.
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
- Added Hisui starters to the starter selection menu. They come inside of ancient Poké Balls.
- Added a bubble quirk to Krabby that only plays during clear sunsets. It looks familiar...
- Added forfeit option to PVP battles.
- Added visual changes for entities affected by Illusion, Imposter, or Transform in battle.
- Added shoulder mounting for Squirtle, Ralts, Roggenrola, Charcadet, Sizzlipede, Litwick, Cutiefly, Flabebe, Flittle, and Scatterbug
- Added species data for Hydrapple, Iron Boulder, Iron Crown, Pecharunt, Raging Bolt, and Terapagos
- Added various new tags for search-ability and better mod compatibility.
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch). These have no way of getting them (for now) and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
### Pokémon Added
#### Gen 2
- Sentret
- Furret
- Qwilfish
- Heracross
- Skarmory
- Larvitar
- Pupitar
- Tyranitar
#### Gen 3
- Lileep
- Cradily
- Anorith
- Armaldo
- Tropius
- Roselia
- Aron
- Lairon
- Aggron
- Solrock
- Lunatone
- Makuhita
- Hariyama
- Trapinch
- Vibrava
- Flygon
#### Gen 4
- Shieldon
- Bastiodon
- Cranidos
- Rampardos
- Budew
- Roserade
- Hippopotas
- Hippowdon
#### Gen 5
- Tirtouga
- Carracosta
- Archen
- Archeops
- Zorua
- Zoroark
- Petilil
- Lilligant
- Darumaka
- Darmanitan
- Woobat
- Swoobat
- Sandile
- Krokorok
- Krookodile
- Frillish
- Jellicent
- Cubchoo
- Beartic
- Deino
- Zweilous
- Hydreigon
- Larvesta
- Volcarona
- Alomomola
- Ferroseed
- Ferrothorn
#### Gen 6
- Tyrunt
- Tyrantrum
- Amaura
- Aurorus
- Goomy
- Sliggoo
- Goodra
- Carbink
- Flabébé
- Floette
- Florges
- Klefki
#### Gen 7
- Turtonator
- Fomantis
- Lurantis
- Salandit
- Salazzle
- Jangmo-o
- Hakamo-o
- Kommo-o
- Alolan Diglett
- Alolan Dugtrio
#### Gen 8
- Gossifleur
- Eldegoss
- Arctozolt
- Arctovish
- Dracozolt
- Dracovish
- Basculegion
- Hisuian Decidueye
- Hisuian Typhlosion
- Hisuian Samurott
- Hisuian Lilligant
- Hisuian Sliggoo
- Hisuian Goodra
- Hisuian Zorua
- Hisuian Zoroark
- Hisuian Voltorb
- Hisuian Electrode
- Hisuian Qwilfish
- Overqwil
- Hisuian Sneasel
- Sneasler
- Stonjourner
- Cufant
- Copperajah
- Dreepy
- Drakloak
- Dragapult
- Impidimp
- Morgrem
- Grimmsnarl
#### Gen 9
- Gimmighoul
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. But what will that do to when you evolve it?
- Gholdengo
#### Cobblemon Exclusives
- Hisui Bias Rowlet
- Hisui Bias Dartrix
- Hisui Bias Cyndaquil
- Hisui Bias Quilava
- Hisui Bias Oshawott
- Hisui Bias Dewott
- Hisui Bias Goomy
- Hisui Bias Petilil
These are our compromise for having both regular and Hisuian forms of these Pokémon in the game. Hisui Biased variations will evolve into the Hisuian evolutions under most conditions. They are otherwise purely cosmetic differences.
### Added cries to the following Pokémon
- Alolan Raticate
- Vulpix, Ninetales
- Zubat, Golbat, Crobat
- Meowth, Persian
- Psyduck, Golduck
- Growlithe, Arcanine
- Geodude, Graveler, Golem
- Doduo, Dodrio
- Seel, Dewgong
- Muk, Grimer
- Krabby, Kingler
- Voltorb, Electrode, Hisuian Voltorb, Hisuian Electrode
- Tangela, Tangrowth
- Snorlax
- Cubone, Marowak
- Koffing, Weezing
- Aerodactyl
- Elekid, Electabuzz, Electivire
- Omanyte, Omastar
- Kabuto, Kabutops
- Lapras
- Scyther
- Hisui Bias Cyndaquil, Hisui Bias Quilava
- Igglybuff
- Yanma, Yanmega
- Gligar, Gliscor
- Qwilfish, Hisuian Qwilfish, Overqwil
- Sneasel, Hisuian Sneasel, Weavile, Sneasler
- Larvitar, Pupitar, Tyranitar
- Swinub, Piloswine, Mamoswine
- Aron, Lairon, Aggron
- Trapinch, Vibrava, Flygon
- Cacnea, Cacturne
- Barboach, Whiscash
- Lileep, Cradily
- Anorith, Armaldo
- Tropius
- Chimecho
- Bidoof, Bibarel
- Buizel, Floatzel
- Gible, Gabite, Garchomp
- Hisui Bias Oshawott, Hisui Bias Dewott
- Petilil, Lilligant, Hisui Bias Petilil, Hisuian Lilligant
- Basculin, Basculegion
- Sandile, Krokolok, Krookodile
- Darumaka, Darmanitan
- Archen, Archeops
- Zorua, Zoroark, Hisuian Zorua, Hisuian Zoroark
- Tyrunt, Tyrantrum
- Amaura Aurorus
- Carbink
- Goomy, Sliggoo, Goodra, Hisui Bias Goomy, Hisuian Sliggoo, Hisuian Goodra
- Klefki
- Hisui Bias Rowlet, Hisui Bias Dartrix
- Komala
- Impidimp, Morgrem, Grimmsnarl
- Cufant, Copperajah
- Dreepy, Drakloak, Dragapult
- Dracozolt, Arctozolt, Dracovish, Arctovish
- Lechonk, Oinkologne
- Maushold family of three and four
### Changes
- Alolan Pikachu and Exeggcute changed to Alola Bias.
- Pokémon now transition more smoothly between different poses.
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Pidgeot, Omanyte, Omastar, Growlithe, Arcanine, Nidoran Male, Nidoran Female, Lapras, Swinub, Piloswine, Basculin, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Mawile, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, Psyduck, Dusknoir, Diglett, Dugtrio, Natu, Xatu, Oshawott, Samurott, Torchic, Grovyle, Sceptile, Sizzlipede, Mismagius, and Raboot.
- Updated animations for Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Diglett, Dugtrio, Magikarp, Dragonite, Omanyte, Omastar, Kabuto, Pinsir, Chinchou, Lanturn, Ralts, Kirlia, Gardevoir, Gallade, Buizel, Garchomp, Pumpkaboo, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Sizzlipede, Centiskorch, Obstagoon, Timburr, Gurdurr, Conkeldurr, Drifloon, and Drifblim.
- Resized Drifloon.
- Added more held items to the held item tag, and Metal Coat to the held item tab.
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
- Changed the Destiny Knot to be crafted with a Ghast Tear rather than a diamond. We have big plans for the Destiny Knot...
- You can now punch grown apricorns to harvest them. We saw so many content creators breaking apricorns with their fists that it was making us die inside.
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
- Updated the biome tags for Spewpa's evolutions into the various Vivillon patterns. You should mostly be getting one evolution option at a time now.
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
- Added tooltips to interaction GUIs to make it clearer what they do.
- Poké Ball recipes now use tags for their center ingredient, rather than specifically Copper Ingots, Iron Ingots, Gold Ingots, and Diamonds, allowing for further datapack customisation and mod compatibility.
- Starter Toast now closes once the corresponding button is pressed once.
- Moved some items into the vanilla Food & Drinks category.
- Stacked Cobblemon Potion Bases can now be quick moved into Brewing Stands.
- Changed the Healing Machine recipe to swap the Max Revive for a Revive so that it is a bit easier to craft.
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%, further helping the crafting of a Healing Machine.
- Pokémon with a low Blaze Powder drop chance now drop it more frequently in the Nether.
- Reorganised a few advancements.
- Pokémon entity shadows now scale when the Pokémon is being sent out or recalled.
- Remade Torkoal particles, now they only appear when in battle.
- Improved the shiny icon within summary and PC interfaces.
- Changed the Poison Barb sprite so that it doesn't look like a sword when held. It's a Poison Barb, not a Poison Sword. Wait, that gives me an idea.
- Moon Stone ore generates more frequently in Taigas and has been added to Magical and Spooky biomes. Ooo... Sorry.
- Density, Season, and Nether biome tags have been moved and renamed within the biome tags directory.
- Added particles to Lucario when in battle. Lucario is special.
- Movesets updated for Blueberry DLC.
### Fixes
- Re-added the recipe for the Iron vitamin. Well, technically it's a mineral.
- Fixed Exeggcute and Pikachu not being able to evolve.
- Fixed evolution priority for Exeggcute and Pikachu regional evolutions. Using a thunder stone on Kantonian Pikachu on the beach will give Alolan Raichu. A second thunder stone would then give Kantonian Raichu.
- Fixed battle text for the Poison Touch Ability.
- Finally found Sudowoodo and Bonsly. They were missing spawn data. Same with Drifloon and Litwick. Uh... sorry about that.
- Fixed Squawkabilly forms not being recognized.
- Fixed the bounce animation for Poké Balls being delayed by like, a full second. It's enough to drive you mad.
- Note blocks now play the correct sound on the Apricorn Plank-based blocks.
- Fixed an issue with transformed parts in posers causing whacky positional issues.
- Fixed Poké Balls freezing in an open state if you're looking away at the moment that it's meant to close. This actually fixes some other things but it's hard to explain.
- Fixed thrown Poké Balls technically having no name.
- Fixed very many issues with Bedrock particle effects. There are probably many more. Life goes on.
- Fixed Arbok patterns not being as specific in spawning as they were intended to be.
- Fixed Pokémon not avoiding danger at all when pathfinding.
- Fixed Pokémon pathing over snow layers and carpets.
- Fixed the Sobble line not being able to swim or breathe underwater.
- Fixed mod incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
- Fixed mod incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
- Fixed an issue that allowed Pokémon to spawn on rails.
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
- Fixed Pokémon sometimes losing hidden abilities when evolving. This fix will only take effect for newly created Pokémon because of technical reasons that were explained to me but which I then forgot.
- Fixed capture messages not displaying in battle.
- Fixed the Illusion ability causing the wrong Pokémon to be targeted in battle.
- Fixed battles started with fainted party members causing a soft-lock on defeat.
- Fixed some issues with eyes in the faint animations of Hitmonlee and Phantump
- Fixed missing evolution moves, for example Stone Axe for Kleavor.
- Cleaned up empty evolutions declaration in species data (And no, I'm not listing all 169. No I don't care what you pay me, I'm not doing it).
- Fixed non-consumable held items being consumed or swapped in battle permanently.
### Developer
- Significantly changed the way the properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed for some things).
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks. The developers say that how it works is cool but I stopped listening.
- Added dialogue API and data registry. This is powerful, and there is a full example in the Cobblemon mod you can trigger using /opendialogue \<username\> cobblemon:example. The example JSON is inside the data folder of the mod.
- Opened up the ItemDropEntry class to allow for it to be extended.
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
- Made the spawning API capable of non-entity spawning. You can make it 'spawn' commands if you want. Go nuts.
- Made PokemonProperties.parse more interoperable with Java. Save yourself and stop using Java.
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
- ``Pokemon.ability`` no longer has a public setter. Please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 or 2 regular abilities and 1 hidden ability.
- ``Pokemon#rollAbility`` has been added which rerolls for a legal ability for the Pokémon.
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the Cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
- `public_spawns_to_json.py` script has been added to give the powerful spawn.json generator a simplistic UI.
- Updated Showdown with Gen 9 DLC.
- Changed mixins to be Java 17 for compatibility level instead of 16, removing a warning from startup logs.
### Datapack & Resourcepack Creators
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
- Custom fossils can be defined using a list of items and the resulting Pokémon. An example of `aerodactyl.json`:
```JSON
{
"result": "aerodactyl",
"fossils": [
"cobblemon:old_amber_fossil"
]
}
```
- Fetus models can be defined in `bedrock/fossils`.
- Fetus textures can be defined in `textures/fossils`.
- Fuel for the Restoration Machine is registered inside the `natural_materials` folder. To register more fuels, create a JSON file containing an array of objects. Each object supports the following fields:
- `content`: Integer containing the amount of fuel to add.
- `item` OR `tag`: Identifier of the item or item tag to be inserted.
- `returnItem`: Identifier of an item to return to the player after consumption.
- Added 3 new item tags: `ancient_poke_balls`, `fossils`, and `tumblestones`.
- Added a spawn rules system to modify general spawning behaviour, see the [wiki](https://wiki.cobblemon.com/index.php/Spawn_Rules) for more information.
- Added dialogue datapack folder and /opendialogue command.
- Added the item tag ``cobblemon:held/leaves_leftovers`` this can be used to flag apple-like items that can create leftovers when eaten.
- You can now add support for dynamic lighting implementations, Cobblemon ships with a default implementation for [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) and the [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), add the following to any species or form:
```JSON
{
"lightingData": {
"lightLevel": 14,
"_lightLevelCommentRemoveMe": "Above supports 0 to 15",
"liquidGlowMode": "LAND",
"_liquidGlowModeCommentRemoveMe": "Above supports LAND, UNDERWATER or BOTH"
}
}
```
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
- Added the item tag ``cobblemon:ability_changers``, contains the ``cobblemon:ability_capsule`` & ``cobblemon:ability_patch`` by default.
- Added the item tag ``cobblemon:held/is_friendship_booster``, allows items to give the Soothe Bell effect of a boost of 1.5x Friendship gained, contains ``cobblemon:soothe_bell`` by default.
## [1.4.1 (December 23rd, 2023)](#1-4-1)
### Additions
- Added battle spectating. Press R on a player in a battle and you can spectate and bully them for their tactics.
- Added the Litwick and Drifloon lines.
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn), allowing you to craft Apricorn wood furniture.
- Berries can now be used in recipes from [Farmer's Delight](https://modrinth.com/mod/farmers-delight) and [Farmer's Delight (Fabric)](https://modrinth.com/mod/farmers-delight-fabric), as well as any other mods using the same berry tags.
- Boats, signs and hanging signs are now craftable with Apricorn wood.
- Added the Fairy Feather, Iron Ball, Cleanse Tag, Flame Orb, Life Orb, Smoke Ball, and Toxic Orb held items.
- Added the Inferno, Void, and Forsaken patterns for Vivillon. These can be obtained by evolving a Spewpa in the Nether, End, or Deep Dark respectively.
- Bees can now be fed using Pep-Up Flowers.
- Mooshtank can now be milked with a bowl for Mushroom Stew.
- Updated Showdown version to use generation 9 battle data.
- Added cries to Beldum, Metang and Metagross.
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
- Added additional nickname trigger "Grumm" for Inkay's evolution.
### Changes
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
- Using a Remedy, Fine Remedy, or Superb Remedy will no longer lower friendship with a Pokémon.
- The Healing Machine now has a [much more difficult recipe](https://wiki.cobblemon.com/index.php/Healing_Machine), placing it later game.
- Made the EXP. Share recipe cheaper.
- Turtwig can now be put on your shoulder.
- Slightly lowered the volume of all cries
- Updated Pokeball animations and model.
- Turtwig can now be put on shoulder.
- Updated Zubat line model, texture, and animations.
- Updated Geodude line models and textures.
- Added animations for Hitmontop, Tyrogue, and Mightyena.
- Tweaked animations for Dusknoir, Ratatta, Bewear, Exeggutor, and Alolan Exeggutor.
- Sized Kantonian Exeggutor down. Still big, but not TOO big.
- Sized Kantonian Exeggutor down. Still big but not TOO BIG.
- Tweaked cries for Pikachu, Raichu and Alolan Raichu.
- Fixed Swimming behaviors for Wimpod line, Oshawott line, Quaxly line, and Clodsire
- Changed the way level scaling works in spawning. By default, anything with a spawn range of up to 5 either side of the party highest level and everything else will spawn per its specified ranges.
- The nature of Pokémon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied.
- Slightly lowered the volume of all cries.
- Giving Pokémon items now plays a sound
- Updated the Poké Ball model and animations.
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes, and any other modded block that follows the same connection rules.
- The config option `consumeHeldItems` has been removed, please see the Datapack & Resourcepack Creators section for instructions on the updated method.
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes and any other modded block that follows the same connection rules.
- The config option `consumeHeldItems` has been removed, please see the Datapack & Resourcepack Creators for instructions on the updated method.
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
- Using a Remedy, Fine Remedy, or Superb Remedy will no longer lower friendship with a Pokémon
- The Healing Machine now has a more difficult recipe, placing it later game.
- Heal Powder can now be composted with a 75% chance of adding a layer
- Mental, Power, White, and Mirror Herbs can now be composted with a 100% chance of adding a layer.
- Added glowing eyes to Hoothoot and Noctowl.
- Mining Evolution Stone Ores with a Fortune pickaxe will now increase the amount of items received.
- Added emissive to Hoothoot.
- Mining Evolution Stone Ores with a Fortune pickaxe will now increase the amount of items recieved
- Black Augurite can now be used to craft stone axes and obsidian.
- Using Experience Candies brings up the Party Pokémon Select screen when not targeting a Pokémon.
- Added tab completion for statuses to commands.
- Remedies can now be cooked in a Smoker and on a Campfire.
- Vertically flipped the Destiny Knot recipe.
- Added tab completion for statuses to commands
### Additions
- Added battle spectating, can disable in config
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn) allowing you to craft Apricorn wood furniture.
- Berries can now be used in recipes from [Farmer's Delight](https://modrinth.com/mod/farmers-delight) and [Farmer's Delight (Fabric)](https://modrinth.com/mod/farmers-delight-fabric), as well as any other mods using the same berry tags.
- The nature of cobblemon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied. This is the intended behaviour, because the original nature and taste of the Cobblemon does not change when a mint is applied.
- Giving Pokémon items now plays a sound
- A boat, sign and hanging sign is now craftable with Apricorn wood. The recipes are the same shape as Minecraft's equivalent with Apricorn planks as replacements.
- Added the [Cleanse Tag](https://wiki.cobblemon.com/index.php/Cleanse_Tag) and [Fairy Feather](https://wiki.cobblemon.com/index.php/Fairy_Feather)
- Added Fairy Feather drops to some pokemon
- Added the Inferno, Void, and Forsaken patterns for Vivillon. These can be obtained by evolving a Spewpa in the Nether, End, or Deep Dark respectively.
- Added the Litwick line.
- Bees can now be fed using Pep-Up Flowers.
- Mooshtank can now be milked with a bowl for Mushroom Stew.
- Added cries to Beldum, Metang and Metagross.
### Fixes
- Fixed Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund and Revavroom cries not playing.
- Fixed Alolan Ratticate animations causing a crash.
- Fixed Quaxwell not doing its cry.
- Fixed Shroomish not using its idle.
- Fixed how Weight and Height is calculated for Pokémon, fixing the damage from moves like Low Kick.
- Fixed a staggering number of battle messages.
- Fixed various stone related blocks not being valid for Big Roots to spread onto on the Fabric version.
- Fixed various stone related blocks not being valid for Big Roots to spread on the Fabric version.
- Updated the registration of compostable items to improve compatibility with Fabric forks such as Quilt. Please note this does not mean we officially support Quilt, this change was only done since it was possible by correcting the registration to use the new intended way in the Fabric API.
- Fixed Dispensers being unable to shear grown Apricorns.
- Fixed Bowl not being given back to player after using Berry Juice
- Added context for -fail and -block handlers for battle text and added 16 related battle texts for them
- Fixed Battle text for Disable, Laser Focus, Foresight, Fire Spin, Telekinesis, Curse, Recharge and Encore
- Fixed missing text for snowy weather in battles
- Fixed missing text for attempting to catch an uncatchable Pokémon
- Fixed Moonphases for Clefairy line
- Fixed issue where Potions, Super Potions, and Hyper Potions did not work during battle
- Fixed the compatibility patch with the Forge version of [Carry On](https://modrinth.com/mod/carry-on) due to a bug on the mod, the Fabric version was unchanged and is still compatible.
- Added the ability to place Berries on modded Farmland blocks.
- Shouldered Pokémon now hop off when selected in team and R is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
- Shouldered Pokémon now hop off when selected in team and r is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
- Made more items compostable and changed the process for making items compostable.
- Added the ability for Hoppers to fill Brewing Stands with Medicinal Brews and Potions.
- Apricorn blocks are now flammable. Probably should have started that way, but we got there.
- Apricorn blocks are now flammable.
- The default pose for Pokémon being passengers is now "standing".
- Fixed issue where some IVs were changing every time a player logged back in.
- Fixed issue where some IVs were changing every player relog.
- Fixed cursed battle message
- Fixed mistakes in pokemon spawning JSONs
- Fixed advancement crash from bad datapack evolution data.
- Fixed global influences being applied to TickingSpawners twice.
- Reverted the default SpawningSelector back to FlatContextWeightedSelector. This fixes multiple weight related issues, including weights with SpawningInfluences.
- Apricorn Planting advancement should work again.
- Advancement "Vivillonaire" should now allow High Plains and Icy Snow Vivillon to register.
- Advancement "Patterned Wings" should now allow High Plains and Icy Snow Vivillon to register.
- Fixed the last battle critical hits evolution requirement not working.
- Fixed the damage taken evolution requirement not saving progress.
- Fixed the defeated Pokémon evolution requirement not saving progress.
@@ -480,57 +71,22 @@ These are our compromise for having both regular and Hisuian forms of these Pok
- Fixed an exploit that could convert a single piece of Blaze Powder into an extra Medicinal Brew on the Forge version.
- Fixed an issue where health percentages would show incorrectly after healing
- Fixed the move Revival Blessing not allowing you to select from fainted party members.
- Fixed villagers not being able to pick up and plant mint seeds, vivichoke seeds, and revival herbs.
- Fixed Exeggcute faint.
- Fixed various spawn configuration issues across the board.
- Fixed Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund and Revavroom cries not playing.
- Fixed Alolan Ratticate animations causing a crash.
- Fixed Quaxwell not doing its cry.
- Fixed Shroomish not using its idle.
- Fixed a possible visual duplication of sent out Pokémon.
- Fixed battle text for Trace, Receiver, and Power of Alchemy.
- Fixed tooltips being appended too late in items.
- Fixed battles ending background music when battle music is not present.
- Fixed battles ending background music, instead of pausing, when battle music is played.
- Fixed a bunch of regionals to actually be obtainable, namely the unmodelled ones
- Fixed battle text for moves that were missing.
- Fixed a formatting error that affected Pokémon nicknames when the storage type is JSON.
- Fixed a crash that could occur on some servers relating to chunk loading and teleporting.
- Fixed an issue with Inkay's evolution requirement.
- Fixed conflicting evolution requirements that would cause the Ocean, River, Sun, and Tundra variants of Vivillon to be unobtainable through evolution.
- Fixed the Modern variant of Vivillon not being obtainable through evolution.
- Fixed Pokémon pathing through berry bushes, harming themselves in the process.
### Developer
- Fixed the `SpawnEvent` not respecting usage of `Cancelable#cancel`.
- Added the `EvolutionTestedEvent`, this allows listening and overriding the final result of evolution requirement tests.
- Rebuilt the scheduling API to more clearly force side choices and allow more local temporal frames of reference for tasks.
- Added utility script that can be used to generate all Spawn JSONS for all pokemon from the spawning spreadsheet in 1 click ([cobblemon_spawn_csv_to_json.py](utilityscripts%2Fcobblemon_spawn_csv_to_json.py)).
- The `HeldItemManager` has a new method `shouldConsumeItem`, this will return false by default to prevent breaking changes, see the documentation and update your implementations as needed.
- Added and implemented minSkyLight and maxSkyLight as config options for SpawnConditions
- Player specific battle themes can now be assigned to `PlayerData#battleTheme`.
- Changed design of `BattleStartedPreEvent`. Will now expose the `PokemonBattle`.
### Datapack & Resourcepack Creators
- Added 3 new item tags: `cobblemon:held/consumed_in_npc_battle`, `cobblemon:held/consumed_in_pvp_battle` & `cobblemon:held/consumed_in_wild_battle` these will determine which items get consumed in the implied battle types by Cobblemon, keep in mind the controller for this behaviour can be overriden by 3rd party.
- Unique wild encounter themes can now be associated with a specific species (or form) by assigning a SoundEvent identifier to the `battleTheme` field in the species' data configuration.
- Added a `structure` evolution condition, used to check if a Pokémon is in a given structure.
### Localization
- Updated translations for:
- French and Canadian French
- Simplified and Traditional Chinese
- Spanish and Mexican Spanish
- Pirate English
- German
- Thai
- Portuguese and Brazilian Portuguese
- Polish
- Italian
- Dutch
- Ukrainian
- Russian
Thank you so much to all of our community translators that bring the mod to the rest of the world!
## [1.4.0 - The Friends and Farms Update (October 13th, 2023)](#1-4-0)
#### "No, we don't provide the friends."
### Additions
- Added pasture blocks, used to let your PC Pokémon roam around an area.
- Added nicknaming from the summary menu of a Pokémon (click their name).
@@ -937,7 +493,7 @@ Thank you so much to all of our community translators that bring the mod to the
- 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.
- The various hardcoded potion shoulder effects have been removed, make use of PotionBaseEffect.
- Added ContextManager for tracking causes and contexts of conditions created during a battle. See BattleContext for types of conditions that are tracked.
- Added ContextManager for tracking causes and contexts of conditions created during a battle. See BattleContext for types of conditions that are tracked.
- Added MongoDB support for storing Pokémon and Player data. Must be enabled in config, requires MongoDB core and sync drivers (4.10.0+).
- CobblemonShowdown updated to version 10.
- Generation of a battle can be set in BattleFormat.
@@ -1071,7 +627,6 @@ Thank you so much to all of our community translators that bring the mod to the
- All the translators that contributed are amazing.
## [1.3.0 - The Foundation Update (March 17th, 2023)](#1-3-0)
#### "Now we can start doing the really cool stuff."
### Dependencies
- Upgraded Fabric API dependence to 0.75.1+1.19.2
@@ -1221,7 +776,6 @@ Thank you so much to all of our community translators that bring the mod to the
- 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)
#### "There are going to be so many fakemon..."
### Additions
- Added models for Natu and Xatu, Murkrow and Honchkrow, Wailmer and Wailord.
- Added new PC interface and it is beautiful.
@@ -11,13 +11,8 @@ repositories {
dependencies {
implementation(libs.kotlin)
implementation(libs.indra.common)
implementation(libs.licenser)
implementation(libs.shadow)
implementation(libs.loom)
implementation(libs.architectury)
implementation(libs.blossom)
implementation(libs.ideaExt)
implementation(libs.architecturyPlugin)
}
+10
View File
@@ -0,0 +1,10 @@
import ca.stellardrift.build.configurate.ConfigFormats
import ca.stellardrift.build.configurate.catalog.PolyglotVersionCatalogExtension
plugins {
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.1"
}
extensions.configure<PolyglotVersionCatalogExtension> {
from(ConfigFormats.YAML, file("../gradle/libs.versions.yml"))
}
@@ -9,31 +9,18 @@
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import utilities.ACCESS_WIDENER
val accessWidenerFile = "src/main/resources/cobblemon-common.accesswidener"
plugins {
id("java")
id("java-library")
id("net.kyori.indra")
id("net.kyori.indra.git")
java
`java-library`
id("org.cadixdev.licenser")
id("dev.architectury.loom")
id("architectury-plugin")
kotlin("jvm")
}
group = rootProject.group
version = rootProject.version
description = rootProject.description
indra {
javaVersions {
minimumToolchain(17)
target(17)
}
}
repositories {
mavenCentral()
//JEI
@@ -45,6 +32,11 @@ license {
header(rootProject.file("HEADER"))
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
architectury {
minecraft = project.property("mc_version").toString()
}
@@ -65,7 +57,8 @@ dependencies {
tasks {
withType<JavaCompile> {
options.compilerArgs.add("-Xlint:-processing,-classfile,-serial")
options.encoding = "UTF-8"
options.release.set(17)
}
withType<KotlinCompile> {
@@ -0,0 +1,32 @@
plugins {
id("cobblemon.base-conventions")
id("com.github.johnrengelman.shadow")
}
val bundle: Configuration by configurations.creating {
isCanBeConsumed = false
isCanBeResolved = true
}
tasks {
jar {
archiveBaseName.set("Cobblemon-${project.name}")
archiveClassifier.set("dev-slim")
}
shadowJar {
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}")
}
}
@@ -1,9 +1,6 @@
import utilities.VersionType
import utilities.writeVersion
plugins {
id("java")
id("java-library")
java
`java-library`
id("maven-publish")
id("dev.architectury.loom")
}
@@ -34,7 +31,7 @@ publishing {
groupId = "com.cobblemon"
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
version = project.writeVersion(VersionType.PUBLISHING)
version = rootProject.version.toString()
}
}
}
@@ -0,0 +1,21 @@
plugins {
`java-library`
}
tasks {
val collectJars by registering(Copy::class) {
val tasks = subprojects.filter { it.path != ":common" }.map { it.tasks.named("remapJar") }
dependsOn(tasks)
from(tasks)
into(buildDir.resolve("libs"))
}
assemble {
dependsOn(collectJars)
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
@@ -1,3 +1,2 @@
package utilities
const val ACCESS_WIDENER = "src/main/resources/cobblemon-common.accesswidener"
+4 -4
View File
@@ -1,12 +1,12 @@
plugins {
base
id("cobblemon.root-conventions")
id ("net.nemerosa.versioning") version "2.8.2"
}
group = "com.cobblemon.mod"
version = "${project.property("mod_version")}+${project.property("mc_version")}"
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
if (isSnapshot) {
val fixedBranchName = versioning.info.branch.substringAfter("/")
version = "$version-${fixedBranchName}-${versioning.info.build}"
}
version = "$version-SNAPSHOT"
}
+20 -55
View File
@@ -1,9 +1,3 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
/*
*
* * Copyright (C) 2023 Cobblemon Contributors
@@ -17,10 +11,6 @@ import java.time.format.DateTimeFormatter
plugins {
id("cobblemon.base-conventions")
id("cobblemon.publish-conventions")
id("net.kyori.blossom")
id("org.jetbrains.gradle.plugin.idea-ext")
id("net.nemerosa.versioning") version "2.8.2"
}
architectury {
@@ -34,26 +24,31 @@ repositories {
}
dependencies {
implementation(libs.bundles.kotlin)
modImplementation(libs.fabric.loader)
implementation(libs.stdlib)
implementation(libs.reflect)
modImplementation(libs.fabricLoader)
//Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
modApi(libs.molang)
compileOnlyApi(libs.jeiApi)
modCompileOnly(libs.adornFabric)
// Integrations
compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
// Showdown
// For Showdown
modCompileOnly(libs.graal)
// Data Storage
modCompileOnly(libs.bundles.mongo)
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
// Unit Testing
testImplementation(libs.bundles.unitTesting)
// For datastore
modCompileOnly(libs.mongoDriverCore)
modCompileOnly(libs.mongoDriverSync)
testRuntimeOnly(libs.junitEngine)
testImplementation(libs.junitApi)
testImplementation(libs.junitParams)
testImplementation(libs.mockito)
testImplementation(libs.mockk)
testImplementation(libs.classgraph)
}
tasks.withType<Test> {
@@ -63,33 +58,3 @@ tasks.withType<Test> {
setExceptionFormat("full")
}
}
sourceSets {
main {
blossom {
kotlinSources {
fun generateLicenseHeader() : String {
val builder = StringBuilder()
builder.append("/*\n")
rootProject.file("HEADER").forEachLine {
if(it.isEmpty()) {
builder.append(" *").append("\n")
} else {
builder.append(" * ").append(it).append("\n")
}
}
return builder.append(" */").append("\n").toString()
}
property("license", generateLicenseHeader())
property("modid", "cobblemon")
property("version", project.version())
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
property("gitCommit", versioning.info.commit)
property("branch", versioning.info.branch)
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
}
}
}
}
@@ -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;
import com.cobblemon.mod.common.entity.npc.NPCEntity;
import net.minecraft.entity.ai.brain.Brain;
import net.minecraft.entity.ai.brain.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.entity.ai.brain.sensor.SensorType;
import java.util.Collection;
public class GenericsCheatClass {
// For some reason, doing this in the NPCEntity class in Kotlin gives confusing generic errors I could not resolve.
public static Brain.Profile<NPCEntity> createNPCBrain(Collection<MemoryModuleType<?>> memories, Collection<SensorType<? extends Sensor<? super NPCEntity>>> sensors) {
return Brain.createProfile(memories, sensors);
}
}
@@ -6,8 +6,10 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.gui.dialogue
package com.cobblemon.mod.common.access;
import net.minecraft.text.MutableText
import net.minecraft.sound.SoundCategory;
class DialogueRenderableSpeaker(val name: MutableText?, val face: RenderableFace?)
public interface SoundManagerDuck {
void toggleCategories(SoundCategory... categories);
}
@@ -8,9 +8,12 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pose;
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
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;
@@ -1,96 +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.compat;
import com.cobblemon.mod.common.CobblemonEntities;
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.FormData;
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
// Java class due to relying on entrypoint on Fabric side
public class LambDynamicLightsCompat {
// This is all called on client side
// These things are checked every tick so try to keep it as free as possible
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
// Make sure not to call anything Fabric specific :)
public static void hookCompat() {
// Pokémon entities
DynamicLightHandlers.registerDynamicLightHandler(
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
pokemon -> resolvedPokemonLightLevel(pokemon, false),
pokemon -> true
)
);
DynamicLightHandlers.registerDynamicLightHandler(
CobblemonEntities.POKEMON,
DynamicLightHandler.makeHandler(
pokemon -> resolvedPokemonLightLevel(pokemon, true),
pokemon -> false
)
);
// Shouldered Pokémon
DynamicLightHandlers.registerDynamicLightHandler(
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
player -> resolvedShoulderLightLevel(player, false),
player -> true
)
);
DynamicLightHandlers.registerDynamicLightHandler(
EntityType.PLAYER,
DynamicLightHandler.makeHandler(
player -> resolvedShoulderLightLevel(player, true),
player -> false
)
);
}
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
}
private static int resolvedShoulderLightLevel(PlayerEntity player, boolean underwater) {
final Pair<PokemonOnShoulderRenderer.ShoulderData, PokemonOnShoulderRenderer.ShoulderData> shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getLeft(), underwater);
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getRight(), underwater);
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
}
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
return Optional.empty();
}
return Optional.of(form.getLightingData().getLightLevel());
}
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
if (shoulderData == null) {
return Optional.empty();
}
return extractFormLightLevel(shoulderData.getForm(), underwater);
}
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
}
}
@@ -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.duck;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
public interface SoundManagerDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
}
@@ -1,25 +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.duck;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface SoundSystemDuck {
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
Collection<SoundInstance> getSounds(@Nullable SoundCategory category);
}
@@ -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.CobblemonBuildDetails;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
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(CrashReport.class)
public final class CrashReportMixin {
@Inject(method = "addStackTrace", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemDetails;writeTo(Ljava/lang/StringBuilder;)V"))
public void cobblemon$printCobblemonDetails(StringBuilder builder, CallbackInfo callback) {
CrashReportSection cobblemon = new CrashReportSection("Cobblemon");
cobblemon.add("Version", CobblemonBuildDetails.VERSION);
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
cobblemon.addStackTrace(builder);
builder.append("\n\n");
}
}
@@ -1,30 +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.sherds.CobblemonSherds;
import net.minecraft.block.DecoratedPotPatterns;
import net.minecraft.item.Item;
import net.minecraft.registry.RegistryKey;
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(DecoratedPotPatterns.class)
public abstract class DecoratedPotPatternsMixin {
@Inject(method = "fromSherd", at=@At("HEAD"), cancellable = true)
private static void cobblemon$getCobblemonSherdTexture(Item sherd,
CallbackInfoReturnable<RegistryKey<String>> cir) {
if (CobblemonSherds.INSTANCE.getSherdToPattern().containsKey(sherd)) {
cir.setReturnValue(CobblemonSherds.INSTANCE.getSherdToPattern().get(sherd));
return;
}
}
}
@@ -1,33 +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 net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.village.VillagerProfession;
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;
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
import java.util.Objects;
@Mixin(VillagerEntity.class)
public abstract class EntityVillagerMixin {
@Inject(method = "canGather", at = @At(value = "RETURN"), cancellable = true)
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
final VillagerEntity villager = (VillagerEntity) (Object) this;
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canInsert(stack)) {
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
ci.setReturnValue(true);
}
}
}
@@ -8,37 +8,20 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import net.minecraft.client.MinecraftClient;
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker;
import net.minecraft.client.render.GameRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Unique
long lastTime = -1;
@Inject(
method = "render",
at = @At(value = "TAIL")
)
public void render(float tickDelta, long startTime, boolean tick, CallbackInfo ci) {
MinecraftClient client = MinecraftClient.getInstance();
long newTime = System.currentTimeMillis();
// Don't play scheduled animations when the game is paused
if (client.isPaused()) {
lastTime = newTime;
return;
}
if (lastTime != -1) {
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
}
lastTime = newTime;
ScheduledTaskTracker.INSTANCE.update();
}
}
@@ -1,69 +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.CobblemonBakingOverrides;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
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.InjectionPoint;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.points.BeforeStringInvoke;
@Mixin(ModelLoader.class)
public abstract class ModelLoaderMixin {
@Shadow protected abstract void addModel(ModelIdentifier modelId);
@Final
@Shadow
private Map<Identifier, UnbakedModel> unbakedModels;
@Final
@Shadow
private static Logger LOGGER;
@Inject(
method = "<init>",
at = @At("TAIL")
)
public void init(BlockColors blockColors,
Profiler profiler,
Map jsonUnbakedModels,
Map blockStates,
CallbackInfo ci) {
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
try {
this.unbakedModels.put(bakingOverride.getModelIdentifier(), this.loadModelFromJson(bakingOverride.getModelLocation()));
this.addModel(bakingOverride.getModelIdentifier());
} catch (IOException e) {
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
throw new RuntimeException(e);
}
});
}
@Shadow
private JsonUnbakedModel loadModelFromJson(Identifier id) throws IOException {
return null;
}
}
@@ -1,37 +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.sound.battle.BattleMusicController;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.sound.MusicTracker;
import net.minecraft.client.sound.SoundInstance;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
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(MusicTracker.class)
public class MusicTrackerMixin {
@Shadow @Final
private MinecraftClient client;
@Shadow @Nullable
private SoundInstance current;
/** Freezes the tracker while a BattleMusicInstance is in progress. Current SoundInstance being tracked will be paused by BattleMusicHandler. */
@Inject(method = "tick()V", at = @At("HEAD"), cancellable = true)
public void tick(CallbackInfo cb) {
if (this.client.getSoundManager().isPlaying(BattleMusicController.INSTANCE.getMusic())) cb.cancel();
}
}
@@ -1,37 +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.snowstorm.ParticleMaterials;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.client.particle.ParticleTextureSheet;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
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 java.util.List;
@Mixin(ParticleManager.class)
final class ParticleManagerMixin {
@Mutable
@Final
@Shadow
private static List<ParticleTextureSheet> PARTICLE_TEXTURE_SHEETS;
@Inject(at = @At("RETURN"), method = "<clinit>")
private static void lodestone$addTypes(CallbackInfo ci) {
PARTICLE_TEXTURE_SHEETS = ImmutableList.<ParticleTextureSheet>builder().addAll(PARTICLE_TEXTURE_SHEETS)
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
}
}
@@ -1,33 +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.CobblemonItems;
import net.minecraft.entity.mob.PiglinBrain;
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.CallbackInfoReturnable;
@Mixin(PiglinBrain.class)
public class PiglinBarterMixin {
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
if(!ci.getReturnValue()) {
//TODO: Make a tag?
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
ci.setReturnValue(true);
}
}
}
@@ -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.CobblemonItems;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.mob.PiglinEntity;
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(PiglinEntity.class)
public abstract class PiglinEntityMixin {
@Inject(method = "equipToOffHand", at = @At(value = "HEAD"), cancellable = true)
public void cobblemon$isValidBarteringItem(ItemStack stack, CallbackInfo ci) {
PiglinEntity entity = (PiglinEntity)(Object) this;
if (stack.isOf(CobblemonItems.RELIC_COIN_POUCH)) {
entity.equipStack(EquipmentSlot.OFFHAND, stack);
entity.updateDropChances(EquipmentSlot.OFFHAND);
ci.cancel();
}
}
}
@@ -14,7 +14,6 @@ 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.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.DataKeys;
@@ -23,8 +22,11 @@ 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;
@@ -38,6 +40,8 @@ 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 {
@@ -140,7 +144,7 @@ public abstract class PlayerMixin extends LivingEntity {
)
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
if (!getWorld().isClient) {
if (stack.isIn(CobblemonItemTags.LEAVES_LEFTOVERS) && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
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;
@@ -8,77 +8,36 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundManagerDuck;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import net.minecraft.client.sound.*;
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 net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
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(SoundManager.class)
public abstract class SoundManagerMixin implements SoundManagerDuck {
public class SoundManagerMixin implements SoundManagerDuck {
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
private boolean[] blockedCategories = new boolean[SoundCategory.values().length];
@Shadow @Final
private SoundSystem soundSystem;
// Never-ending ambient loops are a special exception (they are only initiated once) and should always be paused if filtered.
private boolean isAmbientLoop(SoundInstance sound) {
return sound instanceof BiomeEffectSoundPlayer.MusicLoop || sound instanceof AmbientSoundLoops.Underwater;
}
private boolean filterCondition(SoundInstance sound) {
return !isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
private boolean ambientLoopCondition(SoundInstance sound) {
return isAmbientLoop(sound) &&
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
}
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).pauseSounds(id, category);
public void toggleCategories(SoundCategory... categories) {
for (SoundCategory category : categories) {
int index = category.ordinal();
boolean blocked = blockedCategories[index];
blockedCategories[index] = !blocked;
}
}
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
((SoundSystemDuck)soundSystem).resumeSounds(id, category);
}
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
public void playStart(SoundInstance sound, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
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 playStart(SoundInstance sound, int delay, CallbackInfo cb) {
if (filterCondition(sound)) cb.cancel();
}
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
}
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("TAIL"))
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
public void play(SoundInstance sound, int delay, CallbackInfo cb) {
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
}
}
@@ -8,102 +8,31 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
import com.cobblemon.mod.common.duck.SoundSystemDuck;
import com.google.common.collect.Multimap;
import net.minecraft.client.sound.*;
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.Final;
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;
import java.util.Map;
@Mixin(SoundSystem.class)
public abstract class SoundSystemMixin implements SoundSystemDuck {
@Shadow
private boolean started;
public abstract class SoundSystemMixin {
@Shadow
private Multimap<SoundCategory, SoundInstance> sounds;
@Shadow @Final
private Map<SoundInstance, Channel.SourceManager> sources;
@Shadow
protected abstract void stop(SoundInstance sound);
@Shadow
public abstract boolean isPlaying(SoundInstance sound);
/** Resumes the Source belonging to the queried SoundInstance. */
private void resume(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::resume);
}
/** Pauses the Source belonging to the queried SoundInstance. */
private void pause(SoundInstance sound) {
Channel.SourceManager sourceManager = this.sources.get(sound);
if (this.started && sourceManager != null) sourceManager.run(Source::pause);
}
/** Resumes the SoundInstance(s) queried by id and/or category. */
@Override
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) resume(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::resume);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) resume(sound);
});
}
}
/** Pauses the SoundInstances queried by id and/or category. */
@Override
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
if (category != null) {
this.sounds.get(category).forEach((sound) -> {
if (id == null || sound.getId().equals(id)) pause(sound);
});
} else if (id == null) {
this.sources.keySet().forEach(this::pause);
} else {
this.sources.keySet().forEach(sound -> {
if (sound.getId().equals(id)) pause(sound);
});
}
}
/** Allows stopping all SoundInstances that belong to a queried category. */
@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) {
this.sounds.get(category).forEach(this::stop);
cb.cancel();
}
}
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
@Inject(method = "resumeAll()V", at = @At("HEAD"), cancellable = true)
public void resumeAll(CallbackInfo cb) {
if (this.isPlaying(BattleMusicController.INSTANCE.getMusic())) {
this.sounds.values().forEach(sound -> {
if (sound == BattleMusicController.INSTANCE.getMusic() || !BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory())) {
resume(sound);
}
});
sounds.get(category).forEach(this::stop);
cb.cancel();
}
}
@@ -0,0 +1,22 @@
/*
* 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,33 +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 com.cobblemon.mod.common.integration.adorn.AdornCompatibility;
import java.util.List;
import juuxel.adorn.block.variant.BlockVariantSet;
import juuxel.adorn.block.variant.BlockVariantSets;
import org.spongepowered.asm.mixin.Final;
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;
//This is a yucky hack but better than what we were doing before
@Mixin(BlockVariantSets.class)
public abstract class AdornRegisterInvoker {
@Final
@Shadow(remap = false)
private static List<BlockVariantSet> variantSets;
@Inject(method = "register()V", at = @At("HEAD"), remap = false)
void register(CallbackInfo ci) {
variantSets.add(AdornCompatibility.INSTANCE);
}
}
@@ -1,17 +0,0 @@
{{ license }}
package com.cobblemon.mod.common
object CobblemonBuildDetails {
const val MOD_ID = "{{ modid }}"
const val VERSION = "{{ version }}"
const val SNAPSHOT = {{ isSnapshot }}
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
const val BRANCH = "{{ branch | default("Not Specified") }}"
fun smallCommitHash(): String {
return this.GIT_COMMIT.substring(0, 7)
}
}
@@ -1,29 +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.client.MinecraftClient
import net.minecraft.client.render.model.BakedModel
import net.minecraft.client.util.ModelIdentifier
import net.minecraft.util.Identifier
/**
* Contains information for forcing a model to be baked
*
* @param modelLocation The location of the model
* @param modelIdentifier The identifier that the BakedModel will be registered to
*/
data class BakingOverride(
val modelLocation: Identifier,
val modelIdentifier: ModelIdentifier
) {
fun getModel(): BakedModel {
return MinecraftClient.getInstance().bakedModelManager.getModel(modelIdentifier)
}
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.Priority
@@ -17,17 +16,14 @@ import com.cobblemon.mod.common.api.data.DataProvider
import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
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.LEVEL_UP_EVENT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
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.UUIDSetDataSerializer
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
@@ -39,24 +35,17 @@ 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.IntSpeciesFeatureProvider
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.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
import com.cobblemon.mod.common.api.spawning.BestSpawner
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningContextCalculator
import com.cobblemon.mod.common.api.spawning.context.calculators.AreaSpawningInput
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.starter.StarterHandler
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
@@ -65,14 +54,12 @@ import com.cobblemon.mod.common.api.storage.adapter.flatfile.FileStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatfile.JSONStoreAdapter
import com.cobblemon.mod.common.api.storage.adapter.flatfile.NBTStoreAdapter
import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
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.storage.player.factory.JsonPlayerDataStoreFactory
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
@@ -80,7 +67,6 @@ 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.DialogueArgumentType
import com.cobblemon.mod.common.command.argument.MoveArgumentType
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
@@ -93,7 +79,6 @@ import com.cobblemon.mod.common.config.constraint.IntConstraint
import com.cobblemon.mod.common.config.starter.StarterConfig
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.FlowHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
@@ -105,16 +90,19 @@ 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.TagSeasonResolver
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.sherds.CobblemonSherds
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
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
@@ -122,6 +110,15 @@ import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
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.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
@@ -129,26 +126,14 @@ import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.util.WorldSavePath
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.*
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import kotlin.math.roundToInt
object Cobblemon {
const val MODID = CobblemonBuildDetails.MOD_ID
const val VERSION = CobblemonBuildDetails.VERSION
const val MODID = "cobblemon"
const val VERSION = "1.4.0"
const val CONFIG_PATH = "config/$MODID/main.json"
val LOGGER: Logger = LogManager.getLogger()
val LOGGER = LogManager.getLogger()
lateinit var implementation: CobblemonImplementation
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
@@ -168,7 +153,6 @@ object Cobblemon {
val bestSpawner = BestSpawner
val battleRegistry = BattleRegistry
var storage = PokemonStoreManager()
var molangData = NbtMoLangDataStoreFactory
lateinit var playerData: PlayerDataStoreManager
lateinit var starterConfig: StarterConfig
val dataProvider: DataProvider = CobblemonDataProvider
@@ -178,13 +162,6 @@ object Cobblemon {
fun preInitialize(implementation: CobblemonImplementation) {
this.implementation = implementation
this.LOGGER.info("Launching Cobblemon ${CobblemonBuildDetails.VERSION}${if(CobblemonBuildDetails.SNAPSHOT) "-SNAPSHOT" else ""} ")
if(CobblemonBuildDetails.SNAPSHOT) {
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
}
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerBlocks()
@@ -247,9 +224,6 @@ object Cobblemon {
}
}
// Register the grow_tumblestone advancement
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
PlatformEvents.CHANGE_DIMENSION.subscribe {
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
}
@@ -257,19 +231,6 @@ object Cobblemon {
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
TrackedDataHandlerRegistry.register(UUIDSetDataSerializer)
// Lowest priority because this applies after luxury ball bonus as of gen 4
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
// Our Luxury ball spec is diff from official, but we will still assume these stack
if (event.pokemon.heldItemNoCopy().isIn(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
increment += increment * 0.5F
}
event.newFriendship = event.pokemon.friendship + increment.roundToInt()
}
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
@@ -285,7 +246,6 @@ object Cobblemon {
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
SpeciesFeatures.register(
DataKeys.CAN_BE_MILKED,
@@ -297,22 +257,12 @@ object Cobblemon {
CustomPokemonProperty.register(UncatchableProperty)
CustomPokemonProperty.register(PokemonFlagProperty)
CustomPokemonProperty.register(HiddenAbilityPropertyType)
CustomPokemonProperty.register(AspectPropertyType)
CustomPokemonProperty.register(UnaspectPropertyType)
FlowHandler.setup()
ifDedicatedServer {
isDedicatedServer = true
PlatformEvents.SERVER_TICK_POST.subscribe { ScheduledTaskTracker.update() }
}
PlatformEvents.SERVER_TICK_POST.subscribe {
ServerTaskTracker.update(1/20F)
ServerRealTimeTaskTracker.update()
}
PlatformEvents.SERVER_TICK_PRE.subscribe {
ServerRealTimeTaskTracker.update()
}
PlatformEvents.SERVER_STARTING.subscribe { event ->
val server = event.server
playerData = PlayerDataStoreManager().also { it.setup(server) }
@@ -421,12 +371,9 @@ object Cobblemon {
battleRegistry.startBattle(
BattleFormat.GEN_9_SINGLES,
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
true
).ifSuccessful { it.mute = true }
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
).apply { mute = true }
}
CobblemonSherds.registerSherds()
}
fun getLevel(dimension: RegistryKey<World>): World? {
@@ -530,7 +477,6 @@ object Cobblemon {
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))
this.implementation.registerCommandArgument(cobblemonResource("dialogue"), DialogueArgumentType::class, ConstantArgumentSerializer.of(DialogueArgumentType::dialogue))
}
}
@@ -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
import net.minecraft.entity.ai.brain.Activity
object CobblemonActivities {
val activities = mutableListOf<Activity>()
val BATTLING_ACTIVITY = Activity("pokemon_battling")
val NPC_BATTLING = Activity("npc_battling")
fun register(activity: Activity): Activity {
activities.add(activity)
return activity
}
}
@@ -8,16 +8,7 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
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.block.entity.FossilAnalyzerBlockEntity
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
import com.cobblemon.mod.common.block.entity.*
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.block.entity.BlockEntityType
import net.minecraft.registry.Registries
@@ -32,13 +23,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@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 BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@JvmField
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
@JvmField
@@ -46,41 +33,4 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
CobblemonBlocks.GILDED_CHEST,
CobblemonBlocks.BLUE_GILDED_CHEST,
CobblemonBlocks.YELLOW_GILDED_CHEST,
CobblemonBlocks.PINK_GILDED_CHEST,
CobblemonBlocks.BLACK_GILDED_CHEST,
CobblemonBlocks.WHITE_GILDED_CHEST,
CobblemonBlocks.GREEN_GILDED_CHEST,
CobblemonBlocks.GIMMIGHOUL_CHEST
).build(null))
@JvmField
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.MONITOR
).build(null)
)
@JvmField
val RESTORATION_TANK: BlockEntityType<RestorationTankBlockEntity> = this.create("restoration_tank",
BlockEntityType.Builder.create({ pos, state -> RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.RESTORATION_TANK
).build(null)
)
@JvmField
val FOSSIL_ANALYZER: BlockEntityType<FossilAnalyzerBlockEntity> = this.create("fossil_analyzer",
BlockEntityType.Builder.create({ pos, state -> FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
CobblemonBlocks.FOSSIL_ANALYZER
).build(null)
)
@JvmField
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
)
}
}
@@ -11,9 +11,6 @@ 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.block.FossilAnalyzerBlock
import com.cobblemon.mod.common.block.MonitorBlock
import com.cobblemon.mod.common.block.RestorationTankBlock
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
@@ -22,13 +19,11 @@ import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import net.minecraft.block.*
import net.minecraft.block.enums.Instrument
import net.minecraft.block.piston.PistonBehavior
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.registry.Registries
@@ -58,8 +53,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
@JvmField
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
@JvmField
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
@JvmField
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
@@ -72,8 +65,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
@JvmField
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
@JvmField
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
@JvmField
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
@@ -109,17 +100,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@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).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
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).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
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).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
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).instrument(Instrument.BASS).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
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))
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
@JvmField
@@ -129,13 +120,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
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).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
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).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
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))
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
@JvmField
@@ -154,65 +145,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val YELLOW_APRICORN_SAPLING = this.create("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(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
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(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
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(CobblemonSounds.BIG_ROOT_SOUNDS)))
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(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
@JvmField
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
@JvmField
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
@JvmField
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
@JvmField
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BLOCK = this.create("sky_tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.LIGHT_BLUE)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(AbstractBlock.Settings.create()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresTool()
.instrument(Instrument.BASEDRUM)
))
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@@ -229,138 +168,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val RELIC_COIN_POUCH = create(
"relic_coin_pouch",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f)
.nonOpaque(), true
)
)
@JvmField
val RELIC_COIN_SACK = create(
"relic_coin_sack",
CoinPouchBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.RELIC_COIN_SACK_SOUNDS)
.pistonBehavior(PistonBehavior.DESTROY)
.strength(0.4f), false
))
@JvmField
val GILDED_CHEST = create(
"gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.RED
)
)
@JvmField
val BLUE_GILDED_CHEST = create(
"blue_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLUE
)
)
@JvmField
val BLACK_GILDED_CHEST = create(
"black_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.BLACK
)
)
@JvmField
val YELLOW_GILDED_CHEST = create(
"yellow_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.YELLOW
)
)
@JvmField
val WHITE_GILDED_CHEST = create(
"white_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.WHITE
)
)
@JvmField
val GREEN_GILDED_CHEST = create(
"green_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.GREEN
)
)
@JvmField
val PINK_GILDED_CHEST = create(
"pink_gilded_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.PINK
)
)
@JvmField
val GIMMIGHOUL_CHEST = create(
"gimmighoul_chest",
GildedChestBlock(
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
GildedChestBlock.Type.FAKE
)
)
@JvmField
val MONITOR = create(
"monitor",
MonitorBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.luminance { if (it.get(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }
)
)
@JvmField
val FOSSIL_ANALYZER = create(
"fossil_analyzer",
FossilAnalyzerBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.nonOpaque()
)
)
@JvmField
val RESTORATION_TANK = create(
"restoration_tank",
RestorationTankBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.IRON_GRAY)
.sounds(BlockSoundGroup.GLASS)
.pistonBehavior(PistonBehavior.BLOCK)
.requiresTool()
.strength(5.0F, 6.0F)
.nonOpaque()
)
)
@JvmField
val HEALING_MACHINE = create(
"healing_machine",
@@ -389,29 +196,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
DisplayCaseBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.STONE_GRAY)
.strength(0.3f)
)
)
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
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(CobblemonSounds.MINT_SOUNDS)))
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(CobblemonSounds.MINT_SOUNDS)))
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(CobblemonSounds.MINT_SOUNDS)))
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(CobblemonSounds.MINT_SOUNDS)))
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(CobblemonSounds.MINT_SOUNDS)))
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(
@@ -428,7 +223,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.VIVICHOKE_SOUNDS)))
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
@@ -448,15 +243,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
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 tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
return this.create(name, TumblestoneBlock(AbstractBlock.Settings.create()
.pistonBehavior(PistonBehavior.DESTROY)
.nonOpaque()
.strength(1.5F)
.sounds(CobblemonSounds.TUMBLESTONE_SOUNDS),
stage, height, xzOffset, nextStage))
}
private val berries = mutableMapOf<Identifier, BerryBlock>()
val AGUAV_BERRY = this.berryBlock("aguav")
@@ -552,7 +338,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
private fun berryBlock(name: String): BerryBlock {
val identifier = cobblemonResource("${name}_berry")
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
this.berries[identifier] = block
return block
}
@@ -46,12 +46,5 @@ object CobblemonCommands {
ClearPartyCommand.register(dispatcher)
ClearPCCommand.register(dispatcher)
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
OpenDialogueCommand.register(dispatcher)
NPCEditCommand.register(dispatcher)
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
CobblemonInfoCommand.register(dispatcher)
}
}
@@ -11,9 +11,6 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.platform.PlatformRegistry
@@ -68,34 +65,8 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
.build(CHEST_BOAT_KEY.toString())
)
@JvmField
val POKE_BOBBER_KEY = cobblemonResource("poke_bobber")
@JvmField
val POKE_BOBBER: EntityType<PokeRodFishingBobberEntity> = this.create(
POKE_BOBBER_KEY.path,
EntityType.Builder.create(::PokeRodFishingBobberEntity, SpawnGroup.MISC).setDimensions(0.5F, 0.5F).maxTrackingRange(10)
.build(POKE_BOBBER_KEY.toString())
)
@JvmField
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
@JvmField
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
GENERIC_BEDROCK_ENTITY_KEY.path,
EntityType.Builder.create({ _, world -> GenericBedrockEntity(world) }, SpawnGroup.MISC)
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
)
@JvmField
val NPC_KEY = cobblemonResource("npc")
@JvmField
val NPC: EntityType<NPCEntity> = create(
NPC_KEY.path,
EntityType.Builder.create({ _, world -> NPCEntity(world) }, SpawnGroup.CREATURE).build("$NPC_KEY")
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
consumer(NPC, NPCEntity.createAttributes())
}
}
@@ -1,74 +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.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.endsWith
import java.util.concurrent.ExecutionException
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
/**
* Holds all the flows that are loaded from the server's data packs. A flow is foldered under the event identifier,
* which can be cobblemon's namespace but can also be minecraft or any other namespace someone has added hooks for.
* The value of the map is a list of MoLang scripts that will execute when that event occurs.
*
* @author Hiroku
* @since February 24th, 2024
*/
object CobblemonFlows : DataRegistry {
override val id = cobblemonResource("flows")
override val observable = SimpleObservable<CobblemonFlows>()
override val type = ResourceType.SERVER_DATA
override fun sync(player: ServerPlayerEntity) {}
val runtime by lazy { MoLangRuntime().setup() }
val clientFlows = hashMapOf<Identifier, MutableList<ExpressionLike>>()
val flows = hashMapOf<Identifier, MutableList<ExpressionLike>>()
override fun reload(manager: ResourceManager) {
val folderBeforeNameRegex = ".*\\/([^\\/]+)\\/[^\\/]+\$".toRegex()
manager.findResources("flows") { path -> path.endsWith(CobblemonScripts.MOLANG_EXTENSION) }.forEach { (identifier, resource) ->
resource.inputStream.use { stream ->
stream.bufferedReader().use { reader ->
try {
val expression = reader.readText().asExpressionLike()
val event = folderBeforeNameRegex.find(identifier.path)?.groupValues?.get(1)
?: throw IllegalArgumentException("Invalid flow path: $identifier. Should have a folder structure that includes the name of the event being flowed.")
if (identifier.path.startsWith("flows/client/")) {
clientFlows.getOrPut(Identifier(identifier.namespace, event)) { mutableListOf() }.add(expression)
} else {
flows.getOrPut(Identifier(identifier.namespace, event)) { mutableListOf() }.add(expression)
}
} catch (exception: Exception) {
throw ExecutionException("Error loading MoLang script for flow: $identifier", exception)
}
}
}
}
Cobblemon.LOGGER.info("Loaded ${CobblemonScripts.scripts.size} flows and ${CobblemonScripts.clientScripts.size} client flows")
observable.emit(this)
}
fun run(eventIdentifier: Identifier, context: Map<String, MoValue>) {
flows[eventIdentifier]?.forEach { it.resolve(runtime, context) }
}
}
@@ -8,20 +8,16 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
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.api.text.blue
import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
@@ -33,7 +29,6 @@ import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
@@ -47,7 +42,6 @@ import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.world.World
@@ -122,38 +116,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val MASTER_BALL = pokeBallItem(PokeBalls.MASTER_BALL)
@JvmField
val CHERISH_BALL = pokeBallItem(PokeBalls.CHERISH_BALL)
@JvmField
val ANCIENT_POKE_BALL = pokeBallItem(PokeBalls.ANCIENT_POKE_BALL)
@JvmField
val ANCIENT_CITRINE_BALL = pokeBallItem(PokeBalls.ANCIENT_CITRINE_BALL)
@JvmField
val ANCIENT_VERDANT_BALL = pokeBallItem(PokeBalls.ANCIENT_VERDANT_BALL)
@JvmField
val ANCIENT_AZURE_BALL = pokeBallItem(PokeBalls.ANCIENT_AZURE_BALL)
@JvmField
val ANCIENT_ROSEATE_BALL = pokeBallItem(PokeBalls.ANCIENT_ROSEATE_BALL)
@JvmField
val ANCIENT_SLATE_BALL = pokeBallItem(PokeBalls.ANCIENT_SLATE_BALL)
@JvmField
val ANCIENT_IVORY_BALL = pokeBallItem(PokeBalls.ANCIENT_IVORY_BALL)
@JvmField
val ANCIENT_GREAT_BALL = pokeBallItem(PokeBalls.ANCIENT_GREAT_BALL)
@JvmField
val ANCIENT_ULTRA_BALL = pokeBallItem(PokeBalls.ANCIENT_ULTRA_BALL)
@JvmField
val ANCIENT_FEATHER_BALL = pokeBallItem(PokeBalls.ANCIENT_FEATHER_BALL)
@JvmField
val ANCIENT_WING_BALL = pokeBallItem(PokeBalls.ANCIENT_WING_BALL)
@JvmField
val ANCIENT_JET_BALL = pokeBallItem(PokeBalls.ANCIENT_JET_BALL)
@JvmField
val ANCIENT_HEAVY_BALL = pokeBallItem(PokeBalls.ANCIENT_HEAVY_BALL)
@JvmField
val ANCIENT_LEADEN_BALL = pokeBallItem(PokeBalls.ANCIENT_LEADEN_BALL)
@JvmField
val ANCIENT_GIGATON_BALL = pokeBallItem(PokeBalls.ANCIENT_GIGATON_BALL)
@JvmField
val ANCIENT_ORIGIN_BALL = pokeBallItem(PokeBalls.ANCIENT_ORIGIN_BALL)
@JvmField
val VIVICHOKE = compostableItem("vivichoke")
@@ -177,19 +139,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
@JvmField
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING, CobblemonBlocks.RED_APRICORN))
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
@JvmField
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING, CobblemonBlocks.YELLOW_APRICORN))
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
@JvmField
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING, CobblemonBlocks.GREEN_APRICORN))
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
@JvmField
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING, CobblemonBlocks.BLUE_APRICORN))
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
@JvmField
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING, CobblemonBlocks.PINK_APRICORN))
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
@JvmField
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING, CobblemonBlocks.BLACK_APRICORN))
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
@JvmField
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING, CobblemonBlocks.WHITE_APRICORN))
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
@JvmField
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
@@ -228,37 +190,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
@JvmField
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
@JvmField
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
@JvmField
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
@JvmField
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
@JvmField
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
@JvmField
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
@JvmField
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
@JvmField
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
@JvmField
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
@JvmField
val FOSSIL_ANALYZER = blockItem("fossil_analyzer", CobblemonBlocks.FOSSIL_ANALYZER)
@JvmField
val MONITOR = blockItem("monitor", CobblemonBlocks.MONITOR)
@JvmField
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -286,8 +224,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@@ -399,19 +335,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
@JvmField
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
@JvmField
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
@JvmField
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
@JvmField
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
@JvmField
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
@JvmField
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
@JvmField
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())), "leek")
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
@@ -561,11 +485,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
@JvmField
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
@JvmField
val ABILITY_PATCH = this.create("ability_patch", AbilityChangeItem(AbilityChanger.HIDDEN_ABILITY))
/**
* Evolution Ores and Stones
*/
@@ -586,8 +505,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val SUN_STONE_ORE = blockItem("sun_stone_ore", CobblemonBlocks.SUN_STONE_ORE)
@JvmField
val TERRACOTTA_SUN_STONE_ORE = blockItem("terracotta_sun_stone_ore", CobblemonBlocks.TERRACOTTA_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)
@@ -613,9 +530,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
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 NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
@JvmField
val DAWN_STONE = noSettingsItem("dawn_stone")
@JvmField
@@ -639,28 +553,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
// Held Items
@JvmField
val ABILITY_SHIELD = heldItem("ability_shield")
@JvmField
val ABSORB_BULB = heldItem("absorb_bulb")
@JvmField
val AIR_BALLOON = heldItem("air_balloon")
@JvmField
val ASSAULT_VEST = heldItem("assault_vest")
@JvmField
val BIG_ROOT = blockItem("big_root", CobblemonBlocks.BIG_ROOT)
@JvmField
val BINDING_BAND = heldItem("binding_band")
@JvmField
val BLACK_BELT = heldItem("black_belt")
@JvmField
val BLACK_GLASSES = heldItem("black_glasses")
@JvmField
val BLACK_SLUDGE = heldItem("black_sludge")
@JvmField
val BLUNDER_POLICY = heldItem("blunder_policy")
@JvmField
val CELL_BATTERY = heldItem("cell_battery")
@JvmField
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
@JvmField
val CHOICE_BAND = heldItem("choice_band")
@@ -670,64 +572,26 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val CHOICE_SPECS = heldItem("choice_specs")
@JvmField
val CLEANSE_TAG = heldItem("cleanse_tag")
// @JvmField
// val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
val DESTINY_KNOT = heldItem("destiny_knot")
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EJECT_BUTTON = heldItem("eject_button")
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
val EVERSTONE = heldItem("everstone")
@JvmField
val EVIOLITE = heldItem("eviolite")
@JvmField
val EXP_SHARE = heldItem("exp_share")
@JvmField
val EXPERT_BELT = heldItem("expert_belt")
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
@JvmField
val FLOAT_STONE = heldItem("float_stone")
@JvmField
val FOCUS_BAND = heldItem("focus_band")
@JvmField
val FOCUS_SASH = heldItem("focus_sash")
// @JvmField
// val GRIP_CLAW = heldItem("grip_claw")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val IRON_BALL = heldItem("iron_ball")
// @JvmField
// val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LEFTOVERS = heldItem("leftovers")
@JvmField
val LIFE_ORB = heldItem("life_orb")
@JvmField
val LIGHT_BALL = heldItem("light_ball")
@JvmField
val LIGHT_CLAY = heldItem("light_clay")
@JvmField
val LOADED_DICE = heldItem("loaded_dice")
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
// @JvmField
// val LUMINOUS_MOSS = heldItem("luminous_moss")
@JvmField
val MAGNET = heldItem("magnet")
// @JvmField
// val METRONOME = heldItem("metronome")
@JvmField
val MIRACLE_SEED = heldItem("miracle_seed")
@JvmField
@@ -738,42 +602,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val NEVER_MELT_ICE = heldItem("never_melt_ice")
@JvmField
val POISON_BARB = heldItem("poison_barb")
@JvmField
val POWER_ANKLET = heldItem("power_anklet")
@JvmField
val POWER_BAND = heldItem("power_band")
@JvmField
val POWER_BELT = heldItem("power_belt")
@JvmField
val POWER_BRACER = heldItem("power_bracer")
@JvmField
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
// @JvmField
// val PROTECTIVE_PADS = heldItem("protective_pads")
// @JvmField
// val PUNCHING_GLOVE = heldItem("punching_glove")
@JvmField
val QUICK_CLAW = heldItem("quick_claw")
@JvmField
val RED_CARD = heldItem("red_card")
@JvmField
val RING_TARGET = heldItem("ring_target")
@JvmField
val ROCKY_HELMET = heldItem("rocky_helmet")
// @JvmField
// val ROOM_SERVICE = heldItem("room_service")
@JvmField
val SAFETY_GOGGLES = heldItem("safety_goggles")
// @JvmField
// val SCOPE_LENS = heldItem("scope_lens")
@JvmField
val SHARP_BEAK = heldItem("sharp_beak")
// @JvmField
// val SHED_SHELL = heldItem("shed_shell")
@JvmField
val SHELL_BELL = heldItem("shell_bell")
@JvmField
val SILK_SCARF = heldItem("silk_scarf")
@JvmField
@@ -783,29 +619,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val SPELL_TAG = heldItem("spell_tag")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
@JvmField
val SOOTHE_BELL = heldItem("soothe_bell")
@JvmField
val STICKY_BARB = heldItem("sticky_barb")
// @JvmField
// val TERRAIN_EXTENDER = heldItem("terrain_extender")
// @JvmField
// val THROAT_SPRAY = heldItem("throat_spray")
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
@JvmField
val TWISTED_SPOON = heldItem("twisted_spoon")
// @JvmField
// val UTILITY_UMBRELLA = heldItem("utility_umbrella")
@JvmField
val WEAKNESS_POLICY = heldItem("weakness_policy")
// @JvmField
// val WIDE_LENS = heldItem("wide_lens")
@JvmField
val WISE_GLASSES = heldItem("wise_glasses")
// @JvmField
// val ZOOM_LENS = heldItem("zoom_lens")
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
@JvmField
@@ -819,12 +635,120 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val METAL_POWDER = heldItem("metal_powder")
@JvmField
val LIGHT_POWDER = heldItem("light_powder")
@JvmField
val QUICK_POWDER = heldItem("quick_powder")
@JvmField
val DAMP_ROCK = heldItem("damp_rock")
val DESTINY_KNOT = heldItem("destiny_knot")
@JvmField
val EVERSTONE = heldItem("everstone")
@JvmField
val POWER_ANKLET = heldItem("power_anklet")
@JvmField
val POWER_BAND = heldItem("power_band")
@JvmField
val POWER_BELT = heldItem("power_belt")
@JvmField
val POWER_BRACER = heldItem("power_bracer")
@JvmField
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val ABSORB_BULB = heldItem("absorb_bulb")
@JvmField
val ELECTRIC_SEED = heldItem("electric_seed")
@JvmField
val GRASSY_SEED = heldItem("grassy_seed")
@JvmField
val MISTY_SEED = heldItem("misty_seed")
@JvmField
val PSYCHIC_SEED = heldItem("psychic_seed")
@JvmField
val FLOAT_STONE = heldItem("float_stone")
@JvmField
val GRIP_CLAW = heldItem("grip_claw")
@JvmField
val LIGHT_BALL = heldItem("light_ball")
@JvmField
val SHED_SHELL = heldItem("shed_shell")
@JvmField
val STICKY_BARB = heldItem("sticky_barb")
@JvmField
val ABILITY_SHIELD = heldItem("ability_shield")
@JvmField
val AIR_BALLOON = heldItem("air_balloon")
@JvmField
val AMULET_COIN = heldItem("amulet_coin")
@JvmField
val BINDING_BAND = heldItem("binding_band")
@JvmField
val BLUNDER_POLICY = heldItem("blunder_policy")
@JvmField
val CELL_BATTERY = heldItem("cell_battery")
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
val EJECT_BUTTON = heldItem("eject_button")
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
val EXPERT_BELT = heldItem("expert_belt")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
@JvmField
val FOCUS_SASH = heldItem("focus_sash")
@JvmField
val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LIFE_ORB = heldItem("life_orb")
@JvmField
val LOADED_DICE = heldItem("loaded_dice")
@JvmField
val LUMINOUS_MOSS = heldItem("luminous_moss")
@JvmField
val METRONOME = heldItem("metronome")
@JvmField
val PROTECTIVE_PADS = heldItem("protective_pads")
@JvmField
val PUNCHING_GLOVE = heldItem("punching_glove")
@JvmField
val RED_CARD = heldItem("red_card")
@JvmField
val RING_TARGET = heldItem("ring_target")
@JvmField
val ROOM_SERVICE = heldItem("room_service")
@JvmField
val SCOPE_LENS = heldItem("scope_lens")
@JvmField
val SHELL_BELL = heldItem("shell_bell")
@JvmField
val SOOTHE_BELL = heldItem("soothe_bell")
@JvmField
val TERRAIN_EXTRUDER = heldItem("terrain_extruder")
@JvmField
val THROAT_SPRAY = heldItem("throat_spray")
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
@JvmField
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
@JvmField
val WEAKNESS_POLICY = heldItem("weakness_policy")
@JvmField
val WIDE_LENS = heldItem("wide_lens")
@JvmField
val ZOOM_LENS = heldItem("zoom_lens")
@JvmField
val IRON_BALL = heldItem("iron_ball")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
@JvmField
val HEAT_ROCK = heldItem("heat_rock")
@JvmField
val DAMP_ROCK = heldItem("damp_rock")
@JvmField
val SMOOTH_ROCK = heldItem("smooth_rock")
@JvmField
val ICY_ROCK = heldItem("icy_rock")
@@ -849,254 +773,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val SURPRISE_MULCH = mulchItem("surprise_mulch", MulchVariant.SURPRISE)
// Archaeology
@JvmField
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
@JvmField
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
@JvmField
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
@JvmField
val COVER_FOSSIL = noSettingsItem("cover_fossil")
@JvmField
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
@JvmField
val DOME_FOSSIL = noSettingsItem("dome_fossil")
@JvmField
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
@JvmField
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
@JvmField
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
@JvmField
val JAW_FOSSIL = noSettingsItem("jaw_fossil")
@JvmField
val OLD_AMBER_FOSSIL = noSettingsItem("old_amber_fossil")
@JvmField
val PLUME_FOSSIL = noSettingsItem("plume_fossil")
@JvmField
val ROOT_FOSSIL = noSettingsItem("root_fossil")
@JvmField
val SAIL_FOSSIL = noSettingsItem("sail_fossil")
@JvmField
val SKULL_FOSSIL = noSettingsItem("skull_fossil")
@JvmField
val BYGONE_SHERD = noSettingsItem("bygone_sherd")
@JvmField
val CAPTURE_SHERD = noSettingsItem("capture_sherd")
@JvmField
val DOME_SHERD = noSettingsItem("dome_sherd")
@JvmField
val HELIX_SHERD = noSettingsItem("helix_sherd")
@JvmField
val NOSTALGIC_SHERD = noSettingsItem("nostalgic_sherd")
@JvmField
val SUSPICIOUS_SHERD = noSettingsItem("suspicious_sherd")
@JvmField
val TUMBLESTONE = this.create("tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE))
@JvmField
val BLACK_TUMBLESTONE = this.create("black_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE))
@JvmField
val SKY_TUMBLESTONE = this.create("sky_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE))
@JvmField
val SMALL_BUDDING_TUMBLESTONE = blockItem("small_budding_tumblestone", CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE)
@JvmField
val MEDIUM_BUDDING_TUMBLESTONE = blockItem("medium_budding_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_TUMBLESTONE)
@JvmField
val LARGE_BUDDING_TUMBLESTONE = blockItem("large_budding_tumblestone", CobblemonBlocks.LARGE_BUDDING_TUMBLESTONE)
@JvmField
val TUMBLESTONE_CLUSTER = blockItem("tumblestone_cluster", CobblemonBlocks.TUMBLESTONE_CLUSTER)
@JvmField
val SMALL_BUDDING_SKY_TUMBLESTONE = blockItem("small_budding_sky_tumblestone", CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE)
@JvmField
val MEDIUM_BUDDING_SKY_TUMBLESTONE = blockItem("medium_budding_sky_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE)
@JvmField
val LARGE_BUDDING_SKY_TUMBLESTONE = blockItem("large_budding_sky_tumblestone", CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE)
@JvmField
val SKY_TUMBLESTONE_CLUSTER = blockItem("sky_tumblestone_cluster", CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER)
@JvmField
val SMALL_BUDDING_BLACK_TUMBLESTONE = blockItem("small_budding_black_tumblestone", CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = blockItem("medium_budding_black_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val LARGE_BUDDING_BLACK_TUMBLESTONE = blockItem("large_budding_black_tumblestone", CobblemonBlocks.LARGE_BUDDING_BLACK_TUMBLESTONE)
@JvmField
val BLACK_TUMBLESTONE_CLUSTER = blockItem("black_tumblestone_cluster", CobblemonBlocks.BLACK_TUMBLESTONE_CLUSTER)
@JvmField
val TUMBLESTONE_BLOCK = blockItem("tumblestone_block", CobblemonBlocks.TUMBLESTONE_BLOCK)
@JvmField
val SKY_TUMBLESTONE_BLOCK = blockItem("sky_tumblestone_block", CobblemonBlocks.SKY_TUMBLESTONE_BLOCK)
@JvmField
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
@JvmField
val POKEROD_SMITHING_TEMPLATE = create("pokerod_smithing_template", SmithingTemplateItem(
Text.translatable("item.minecraft.fishing_rod").blue(),
Text.translatable("item.cobblemon.smithing_template.pokerod.ingredients").blue(),
Text.translatable("upgrade.cobblemon.pokerod").gray(),
Text.translatable("item.cobblemon.smithing_template.pokerod.base_slot_description"),
Text.translatable("item.cobblemon.smithing_template.pokerod.additions_slot_description"),
listOf(cobblemonResource("item/empty_slot_fishing_rod")),
listOf(cobblemonResource("item/empty_slot_pokeball"))
))
@JvmField
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
"automaton_armor_trim_smithing_template",
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
)
val pokeRods = mutableListOf<PokerodItem>()
@JvmField
val POKE_ROD = pokerodItem(cobblemonResource("poke_rod"))
@JvmField
val CITRINE_ROD = pokerodItem(cobblemonResource("citrine_rod"))
@JvmField
val VERDANT_ROD = pokerodItem(cobblemonResource("verdant_rod"))
@JvmField
val AZURE_ROD = pokerodItem(cobblemonResource("azure_rod"))
@JvmField
val ROSEATE_ROD = pokerodItem(cobblemonResource("roseate_rod"))
@JvmField
val SLATE_ROD = pokerodItem(cobblemonResource("slate_rod"))
@JvmField
val PREMIER_ROD = pokerodItem(cobblemonResource("premier_rod"))
@JvmField
val GREAT_ROD = pokerodItem(cobblemonResource("great_rod"))
@JvmField
val ULTRA_ROD = pokerodItem(cobblemonResource("ultra_rod"))
@JvmField
val SAFARI_ROD = pokerodItem(cobblemonResource("safari_rod"))
@JvmField
val FAST_ROD = pokerodItem(cobblemonResource("fast_rod"))
@JvmField
val LEVEL_ROD = pokerodItem(cobblemonResource("level_rod"))
@JvmField
val LURE_ROD = pokerodItem(cobblemonResource("lure_rod"))
@JvmField
val HEAVY_ROD = pokerodItem(cobblemonResource("heavy_rod"))
@JvmField
val LOVE_ROD = pokerodItem(cobblemonResource("love_rod"))
@JvmField
val FRIEND_ROD = pokerodItem(cobblemonResource("friend_rod"))
@JvmField
val MOON_ROD = pokerodItem(cobblemonResource("moon_rod"))
@JvmField
val SPORT_ROD = pokerodItem(cobblemonResource("sport_rod"))
@JvmField
val PARK_ROD = pokerodItem(cobblemonResource("park_rod"))
@JvmField
val NET_ROD = pokerodItem(cobblemonResource("net_rod"))
@JvmField
val DIVE_ROD = pokerodItem(cobblemonResource("dive_rod"))
@JvmField
val NEST_ROD = pokerodItem(cobblemonResource("nest_rod"))
@JvmField
val REPEAT_ROD = pokerodItem(cobblemonResource("repeat_rod"))
@JvmField
val TIMER_ROD = pokerodItem(cobblemonResource("timer_rod"))
@JvmField
val LUXURY_ROD = pokerodItem(cobblemonResource("luxury_rod"))
@JvmField
val DUSK_ROD = pokerodItem(cobblemonResource("dusk_rod"))
@JvmField
val HEAL_ROD = pokerodItem(cobblemonResource("heal_rod"))
@JvmField
val QUICK_ROD = pokerodItem(cobblemonResource("quick_rod"))
@JvmField
val DREAM_ROD = pokerodItem(cobblemonResource("dream_rod"))
@JvmField
val BEAST_ROD = pokerodItem(cobblemonResource("beast_rod"))
@JvmField
val MASTER_ROD = pokerodItem(cobblemonResource("master_rod"))
@JvmField
val CHERISH_ROD = pokerodItem(cobblemonResource("cherish_rod"))
@JvmField
val ANCIENT_POKE_ROD = pokerodItem(cobblemonResource("ancient_poke_rod"))
@JvmField
val ANCIENT_CITRINE_ROD = pokerodItem(cobblemonResource("ancient_citrine_rod"))
@JvmField
val ANCIENT_VERDANT_ROD = pokerodItem(cobblemonResource("ancient_verdant_rod"))
@JvmField
val ANCIENT_AZURE_ROD = pokerodItem(cobblemonResource("ancient_azure_rod"))
@JvmField
val ANCIENT_ROSEATE_ROD = pokerodItem(cobblemonResource("ancient_roseate_rod"))
@JvmField
val ANCIENT_SLATE_ROD = pokerodItem(cobblemonResource("ancient_slate_rod"))
@JvmField
val ANCIENT_IVORY_ROD = pokerodItem(cobblemonResource("ancient_ivory_rod"))
@JvmField
val ANCIENT_GREAT_ROD = pokerodItem(cobblemonResource("ancient_great_rod"))
@JvmField
val ANCIENT_ULTRA_ROD = pokerodItem(cobblemonResource("ancient_ultra_rod"))
@JvmField
val ANCIENT_FEATHER_ROD = pokerodItem(cobblemonResource("ancient_feather_rod"))
@JvmField
val ANCIENT_WING_ROD = pokerodItem(cobblemonResource("ancient_wing_rod"))
@JvmField
val ANCIENT_JET_ROD = pokerodItem(cobblemonResource("ancient_jet_rod"))
@JvmField
val ANCIENT_HEAVY_ROD = pokerodItem(cobblemonResource("ancient_heavy_rod"))
@JvmField
val ANCIENT_LEADEN_ROD = pokerodItem(cobblemonResource("ancient_leaden_rod"))
@JvmField
val ANCIENT_GIGATON_ROD = pokerodItem(cobblemonResource("ancient_gigaton_rod"))
@JvmField
val ANCIENT_ORIGIN_ROD = pokerodItem(cobblemonResource("ancient_origin_rod"))
// Misc
@JvmField
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
@JvmField
val RELIC_COIN = noSettingsItem("relic_coin")
@JvmField
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
@JvmField
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
// Type Gems
@JvmField
val NORMAL_GEM = noSettingsItem("normal_gem")
@JvmField
val FIRE_GEM = noSettingsItem("fire_gem")
@JvmField
val WATER_GEM = noSettingsItem("water_gem")
@JvmField
val GRASS_GEM = noSettingsItem("grass_gem")
@JvmField
val ELECTRIC_GEM = noSettingsItem("electric_gem")
@JvmField
val ICE_GEM = noSettingsItem("ice_gem")
@JvmField
val FIGHTING_GEM = noSettingsItem("fighting_gem")
@JvmField
val POISON_GEM = noSettingsItem("poison_gem")
@JvmField
val GROUND_GEM = noSettingsItem("ground_gem")
@JvmField
val FLYING_GEM = noSettingsItem("flying_gem")
@JvmField
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
@JvmField
val BUG_GEM = noSettingsItem("bug_gem")
@JvmField
val ROCK_GEM = noSettingsItem("rock_gem")
@JvmField
val GHOST_GEM = noSettingsItem("ghost_gem")
@JvmField
val DRAGON_GEM = noSettingsItem("dragon_gem")
@JvmField
val DARK_GEM = noSettingsItem("dark_gem")
@JvmField
val STEEL_GEM = noSettingsItem("steel_gem")
@JvmField
val FAIRY_GEM = noSettingsItem("fairy_gem")
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
@@ -1115,13 +794,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
private fun candyItem(name: String, calculator: CandyItem.Calculator): CandyItem = this.create(name, CandyItem(calculator))
private fun pokerodItem(pokeRodId: Identifier): PokerodItem {
val settings = Item.Settings().maxCount(1).maxDamage(Items.FISHING_ROD.maxDamage)
val item = create(pokeRodId.path, PokerodItem(pokeRodId, settings))
pokeRods.add(item)
return item
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Settings()).also {
@@ -1130,16 +802,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
}
}
)
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
name = name,
entry = item.also {
if (remappedName != null) {
CobblemonHeldItemManager.registerRemap(it, remappedName)
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
}
}
)
private fun compostable(item: Item, increaseLevelChance: Float) = Cobblemon.implementation.registerCompostable(item, increaseLevelChance)
@@ -10,13 +10,11 @@ package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.mechanics.BerriesMechanic
import com.cobblemon.mod.common.mechanics.PotionsMechanic
import com.cobblemon.mod.common.mechanics.RemediesMechanic
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import net.minecraft.resource.ResourceManager
@@ -31,7 +29,6 @@ object CobblemonMechanics : DataRegistry {
val gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.create()
var remedies = RemediesMechanic()
@@ -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
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import java.util.Optional
import net.minecraft.entity.ai.brain.MemoryModuleType
import net.minecraft.util.Uuids
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(Uuids.INT_STREAM_CODEC))
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
memories[id] = memoryModule
return memoryModule
}
fun <U> register(id: String): MemoryModuleType<U> {
val memoryModule = MemoryModuleType<U>(Optional.empty())
memories[id] = memoryModule
return memoryModule
}
}
@@ -13,28 +13,40 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
import com.cobblemon.mod.common.client.net.battle.BattleCaptureStartHandler
import com.cobblemon.mod.common.client.net.battle.BattleChallengeExpiredHandler
import com.cobblemon.mod.common.client.net.battle.BattleChallengeNotificationHandler
import com.cobblemon.mod.common.client.net.battle.BattleEndHandler
import com.cobblemon.mod.common.client.net.battle.BattleFaintHandler
import com.cobblemon.mod.common.client.net.battle.BattleHealthChangeHandler
import com.cobblemon.mod.common.client.net.battle.BattleInitializeHandler
import com.cobblemon.mod.common.client.net.battle.BattleMadeInvalidChoiceHandler
import com.cobblemon.mod.common.client.net.battle.BattleMakeChoiceHandler
import com.cobblemon.mod.common.client.net.battle.BattleMessageHandler
import com.cobblemon.mod.common.client.net.battle.BattleMusicHandler
import com.cobblemon.mod.common.client.net.battle.BattlePersistentStatusHandler
import com.cobblemon.mod.common.client.net.battle.BattleQueueRequestHandler
import com.cobblemon.mod.common.client.net.battle.BattleSetTeamPokemonHandler
import com.cobblemon.mod.common.client.net.battle.BattleSwitchPokemonHandler
import com.cobblemon.mod.common.client.net.battle.BattleUpdateTeamPokemonHandler
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.data.DataRegistrySyncPacketHandler
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
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.npc.CloseNPCEditorHandler
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
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
@@ -59,32 +71,17 @@ 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.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
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.messages.client.data.AbilityRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.FlowRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.NPCRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
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
@@ -94,8 +91,8 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
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.SpawnGenericBedrockPacket
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
@@ -122,12 +119,7 @@ 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
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
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.*
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
@@ -137,9 +129,6 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
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.dialogue.EscapeDialoguePacket
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
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
@@ -173,10 +162,7 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
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.dialogue.EscapeDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
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
@@ -203,12 +189,12 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
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 net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import kotlin.reflect.KClass
/**
* Registers Cobblemon network packets.
@@ -247,8 +233,6 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
// Evolution start
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
@@ -301,8 +285,6 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler)
this.createClientBound(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler)
this.createClientBound(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler)
this.createClientBound(BattleReplacePokemonPacket.ID, BattleReplacePokemonPacket::decode, BattleReplacePokemonHandler)
this.createClientBound(BattleTransformPokemonPacket.ID, BattleTransformPokemonPacket::decode, BattleTransformPokemonHandler)
@@ -314,28 +296,17 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(NPCRegistrySyncPacket.ID, NPCRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(PokeRodRegistrySyncPacket.ID, PokeRodRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
this.createClientBound(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
// Effects
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
this.createClientBound(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler)
this.createClientBound(RunPosableMoLangPacket.ID, RunPosableMoLangPacket::decode, RunPosableMoLangHandler)
// 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)
this.createClientBound(SpawnGenericBedrockPacket.ID, SpawnGenericBedrockPacket::decode, SpawnExtraDataEntityHandler())
// Trade packets
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
@@ -353,7 +324,7 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
// Behaviours
this.createClientBound(PlayPoseableAnimationPacket.ID, PlayPoseableAnimationPacket::decode, PlayPoseableAnimationHandler)
this.createClientBound(PokemonCryPacket.ID, PokemonCryPacket::decode, PokemonCryHandler)
// Move select packets
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
@@ -363,14 +334,6 @@ object CobblemonNetwork : NetworkManager {
// Party move select packets
this.createClientBound(OpenPartyMoveCallbackPacket.ID, OpenPartyMoveCallbackPacket::decode, OpenPartyMoveCallbackHandler)
// Dialogue packets
this.createClientBound(DialogueClosedPacket.ID, DialogueClosedPacket::decode, DialogueClosedHandler)
this.createClientBound(DialogueOpenedPacket.ID, DialogueOpenedPacket::decode, DialogueOpenedHandler)
// NPCs
this.createClientBound(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler)
this.createClientBound(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler)
}
override fun registerServerBound() {
@@ -436,13 +399,6 @@ object CobblemonNetwork : NetworkManager {
// Party move select packets
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
// Dialogue packets
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
// NPC packets
this.createServerBound(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler)
}
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
@@ -1,29 +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.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
import java.util.function.Supplier
import net.minecraft.entity.Entity
import net.minecraft.entity.ai.brain.sensor.Sensor
import net.minecraft.entity.ai.brain.sensor.SensorType
object CobblemonSensors {
val sensors = mutableMapOf<String, SensorType<*>>()
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
val sensor = SensorType(supplier)
sensors[id] = sensor
return sensor
}
}
@@ -14,9 +14,7 @@ import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.sound.BlockSoundGroup
import net.minecraft.sound.SoundEvent
import net.minecraft.sound.SoundEvents
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
@@ -56,10 +54,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
@JvmField
val POKE_BALL_RECALL = this.create("poke_ball.recall")
@JvmField
val POKE_BALL_THROW = this.create("poke_ball.throw")
@JvmField
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
@JvmField
val ITEM_USE = this.create("item.use")
@@ -67,8 +61,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val CAN_EVOLVE = this.create("pokemon.can_evolve")
@JvmField
val EVOLVING = this.create("pokemon.evolving")
@JvmField
val EVOLVE = this.create("evolution.evolve")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@@ -85,8 +77,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
@JvmField
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
@JvmField
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
@JvmField
val BERRY_HARVEST = this.create("berry.harvest")
@@ -98,274 +88,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val MULCH_REMOVE = this.create("mulch.remove")
@JvmField
val FOSSIL_MACHINE_ACTIVATE = this.create("fossil_machine.activate")
@JvmField
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossil_machine.active_loop")
@JvmField
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossil_machine.assemble")
@JvmField
val FOSSIL_MACHINE_DNA_FULL = this.create("fossil_machine.dna_full")
@JvmField
val FOSSIL_MACHINE_FINISHED = this.create("fossil_machine.finished")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossil_machine.insert_dna")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossil_machine.insert_dna_small")
@JvmField
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossil_machine.insert_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossil_machine.retrieve_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossil_machine.retrieve_pokemon")
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
@JvmField
val RELIC_COIN_SACK_BREAK = this.create("relic_coin_sack.break")
@JvmField
val RELIC_COIN_SACK_HIT = this.create("relic_coin_sack.hit")
@JvmField
val RELIC_COIN_SACK_STEP = this.create("relic_coin_sack.step")
@JvmField
val RELIC_COIN_SACK_PLACE = this.create("relic_coin_sack.place")
@JvmField
val RELIC_COIN_POUCH_BREAK = this.create("relic_coin_pouch.break")
@JvmField
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
@JvmField
val FISHING_NOTIFICATION = this.create("fishing.notification")
@JvmField
val FISHING_SPLASH_BIG = this.create("fishing.splash_big")
@JvmField
val FISHING_SPLASH_SMALL = this.create("fishing.splash_small")
@JvmField
val FISHING_BOBBER_LAND = this.create("fishing.bobber_land")
@JvmField
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
@JvmField
val TUMBLESTONE_BLOCK_BREAK = this.create("tumblestone.block_break")
@JvmField
val TUMBLESTONE_HIT = this.create("tumblestone.hit")
@JvmField
val TUMBLESTONE_PLACE = this.create("tumblestone.place")
@JvmField
val TUMBLESTONE_STEP = this.create("tumblestone.step")
@JvmField
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
@JvmField
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
@JvmField
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
@JvmField
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
@JvmField
val BIG_ROOT_BREAK = this.create("big_root.break")
@JvmField
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
@JvmField
val VIVICHOKE_BREAK = this.create("vivichoke.break")
@JvmField
val VIVICHOKE_PLACE = this.create("vivichoke.place")
@JvmField
val MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.place")
@JvmField
val REVIVAL_HERB_BREAK = this.create("revival_herb.break")
@JvmField
val REVIVAL_HERB_PLACE = this.create("revival_herb.place")
@JvmField
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
@JvmField
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
@JvmField
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
@JvmField
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
@JvmField
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
@JvmField
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
@JvmField
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
@JvmField
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val RELIC_COIN_SACK_SOUNDS = BlockSoundGroup(1f, 1f,
RELIC_COIN_SACK_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_SACK_PLACE,
RELIC_COIN_SACK_HIT,
RELIC_COIN_SACK_STEP
)
@JvmField
val RELIC_COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
RELIC_COIN_POUCH_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_POUCH_PLACE,
RELIC_COIN_SACK_HIT,
RELIC_COIN_SACK_STEP
)
@JvmField
val IMPACT_NORMAL = this.create("impact.normal")
@JvmField
val IMPACT_BUG = this.create("impact.bug")
@JvmField
val IMPACT_DARK = this.create("impact.dark")
@JvmField
val IMPACT_DRAGON = this.create("impact.dragon")
@JvmField
val IMPACT_ELECTRIC = this.create("impact.electric")
@JvmField
val IMPACT_FAIRY = this.create("impact.fairy")
@JvmField
val IMPACT_FIGHTING = this.create("impact.fighting")
@JvmField
val IMPACT_FIRE = this.create("impact.fire")
@JvmField
val IMPACT_FLYING = this.create("impact.flying")
@JvmField
val IMPACT_GHOST = this.create("impact.ghost")
@JvmField
val IMPACT_GRASS = this.create("impact.grass")
@JvmField
val IMPACT_GROUND = this.create("impact.ground")
@JvmField
val IMPACT_ICE = this.create("impact.ice")
@JvmField
val IMPACT_POISON = this.create("impact.poison")
@JvmField
val IMPACT_PSYCHIC = this.create("impact.psychic")
@JvmField
val IMPACT_ROCK = this.create("impact.rock")
@JvmField
val IMPACT_STEEL = this.create("impact.steel")
@JvmField
val IMPACT_WATER = this.create("impact.water")
@JvmField
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
TUMBLESTONE_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val TUMBLESTONE_BLOCK_SOUNDS = BlockSoundGroup(1f, 1f,
TUMBLESTONE_BLOCK_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
BERRY_BUSH_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
BERRY_BUSH_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_STEP
)
@JvmField
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
BIG_ROOT_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
SoundEvents.BLOCK_ROOTS_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
SoundEvents.BLOCK_ROOTS_BREAK,
SoundEvents.BLOCK_ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.BLOCK_ROOTS_HIT,
SoundEvents.BLOCK_ROOTS_FALL
)
@JvmField
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
MEDICINAL_LEEK_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MEDICINAL_LEEK_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val VIVICHOKE_SOUNDS = BlockSoundGroup(1f, 1f,
VIVICHOKE_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
VIVICHOKE_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MINT_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val REVIVAL_HERB_SOUNDS = BlockSoundGroup(1f, 1f,
REVIVAL_HERB_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
REVIVAL_HERB_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
GILDED_CHEST_BREAK,
GILDED_CHEST_STEP,
GILDED_CHEST_PLACE,
GILDED_CHEST_HIT,
GILDED_CHEST_STEP
)
@JvmField
val DISPLAY_CASE_ADD_ITEM = this.create("display_case.add_item")
@JvmField
val DISPLAY_CASE_REMOVE_ITEM = this.create("display_case.remove_item")
@JvmField
val DISPLAY_CASE_BREAK = this.create("display_case.break")
@JvmField
val DISPLAY_CASE_HIT = this.create("display_case.hit")
@JvmField
val DISPLAY_CASE_PLACE = this.create("display_case.place")
@JvmField
val DISPLAY_CASE_STEP = this.create("display_case.step")
@JvmField
val DISPLAY_CASE_SOUNDS = BlockSoundGroup(1f, 1f,
DISPLAY_CASE_BREAK,
DISPLAY_CASE_STEP,
DISPLAY_CASE_PLACE,
DISPLAY_CASE_HIT,
DISPLAY_CASE_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
}
@@ -32,14 +32,7 @@ object CobblemonTradeOffers {
* @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, 24, 1, 1, 6)))
)
VillagerProfession.FISHERMAN -> listOf(
VillagerTradeOffer(VillagerProfession.FISHERMAN, 5, listOf(
TradeOffers.SellItemFactory(CobblemonItems.POKEROD_SMITHING_TEMPLATE, 12, 3, 30)
))
)
VillagerProfession.FARMER -> listOf(VillagerTradeOffer(VillagerProfession.FARMER, 3, listOf(TradeOffers.SellItemFactory(CobblemonItems.VIVICHOKE_SEEDS, 24, 1, 1, 6))))
else -> emptyList()
}
@@ -99,13 +99,6 @@ object CobblemonCriteria {
)
)
val RESURRECT_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("resurrect_pokemon"),
PickStarterCriterionCondition::class.java
)
)
val TRADE_POKEMON = this.create(
SimpleCriterionTrigger(
cobblemonResource("trade_pokemon"),
@@ -113,21 +106,6 @@ object CobblemonCriteria {
)
)
val CAST_POKE_ROD = this.create(
SimpleCriterionTrigger(
cobblemonResource("cast_poke_rod"),
CastPokeRodCriterionCondition::class.java
)
)
// Advancement criteria for [grow_tumblestone.json]
val PLANT_TUMBLESTONE = this.create(
SimpleCriterionTrigger(
cobblemonResource("plant_tumblestone"),
PlantTumblestoneCriterionCondition::class.java
)
)
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
}
@@ -1,30 +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.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
class CastPokeRodCriterionCondition(id: Identifier, predicate: LootContextPredicate): SimpleCriterionCondition<Boolean>(id, predicate) {
var hasBait: Boolean = false
override fun toJson(json: JsonObject) {
json.addProperty("hasBait", hasBait)
}
override fun fromJson(json: JsonObject) {
hasBait = json.get("hasBait").asBoolean
}
override fun matches(player: ServerPlayerEntity, context: Boolean): Boolean {
return hasBait == context
}
}
@@ -1,52 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.block.TumblestoneBlock
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
/**
* A criterion condition for when a tumblestone block is planted
* @param id The identifier of the criterion
* @param predicate The predicate for the criterion
*
* @author Aethen
* @since 02/28/2024
*/
class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
override fun toJson(json: JsonObject) {
// Add properties to json if needed. None needed for this criterion
}
override fun fromJson(json: JsonObject) {
// Parse properties from json if needed. None needed for this criterion
}
/**
* Checks if the tumblestone block can grow at the given position
* @param player The player that planted the tumblestone block
* @param context The context of the criterion
* @return True if the tumblestone block can grow at the given position, false otherwise
*/
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
return context.tumbleStoneBlock.canGrow(context.pos, player.world)
}
}
/**
* The context of the [PlantTumblestoneCriterionCondition]
* @param pos The position of the tumblestone block
* @param tumbleStoneBlock The tumblestone block
*/
open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.DataKeys
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
@@ -22,7 +21,7 @@ import net.minecraft.nbt.NbtCompound
* @author Qu
* @since January 9th, 2022
*/
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
val name: String
get() = template.name
@@ -35,26 +34,16 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
/**
* This represents the last known index of this backing ability in the species data.
* @see [Pokemon.updateAbility].
*/
var forced: Boolean = forced
internal set
/**
* This represents the last known index of this backing ability in the species data.
*
* @see [Pokemon.updateAbility].
* 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
internal set
/**
* The last known priority of this ability in the species data.
*
* @see [Pokemon.updateAbility].
* The value can be mutated however this is not recommended by API users.
*/
var priority = Priority.LOWEST
internal set
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
@@ -73,23 +62,19 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
}
open fun loadFromNBT(nbt: NbtCompound): Ability {
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
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 {
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
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
}
}
@@ -28,6 +28,7 @@ class AbilityTemplate(
*/
fun create(forced: Boolean = false) = builder(this, forced)
/**
* Returns the Ability and loads the given NBT Tag into it.
*
@@ -41,5 +42,4 @@ class AbilityTemplate(
* Ability extensions need to write and read their needed data from here.
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
}
@@ -135,31 +135,28 @@ class BattleMessage(rawMessage: String) {
return this.actorAndActivePokemon(pnx, battle)
}
/**
* Queries an argument at the given [index] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
*
* @param index The index of the argument referencing the [BattlePokemon].
* @param battle The [PokemonBattle] being queried.
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
/*
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 battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
return this.battlePokemon(actorID, pokemonID, battle)
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)
}
/**
* Queries an optional argument identified by [optionalArg] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
*
* @param optionalArg The id of the optional argument referencing the [BattlePokemon].
* @param battle The [PokemonBattle] being queried.
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
*/
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
val optional = this.optionalArguments.get(optionalArg) ?: return null
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
val uuid = pokemonID[1].trim()
return this.battlePokemon(pnx, uuid, 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)
}
/**
@@ -170,7 +167,7 @@ class BattleMessage(rawMessage: String) {
*/
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) || it.matches(PN_MATCHER) } ?: return null
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) } ?: return null
val uuid = argument[1].trim()
return pnx to uuid
}
@@ -237,7 +234,7 @@ class BattleMessage(rawMessage: String) {
null
}
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
private fun getBattlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
battle.getBattlePokemon(pnx, pokemonID)
} catch (_: Exception) {
null
@@ -8,9 +8,6 @@
package com.cobblemon.mod.common.api.battles.model
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.CobblemonNetwork
@@ -21,8 +18,6 @@ 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.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.api.text.red
@@ -40,22 +35,20 @@ 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.battles.runner.ShowdownService
import com.cobblemon.mod.common.battles.ForfeitActionResponse
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
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.evolution.progress.LastBattleCriticalHitsEvolutionProgress
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
import com.cobblemon.mod.common.util.battleLang
import com.cobblemon.mod.common.util.getPlayer
import com.cobblemon.mod.common.util.withQueryValue
import java.io.File
import java.util.UUID
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import java.util.concurrent.ConcurrentLinkedDeque
/**
* Individual battle instance
@@ -71,16 +64,11 @@ open class PokemonBattle(
) {
/** Whether logging will be silenced for this battle. */
var mute = true
val struct = this.asMoLangValue()
val runtime = MoLangRuntime().also { it.environment.structs["query"] = struct }
val onEndHandlers: MutableList<(PokemonBattle) -> Unit> = mutableListOf()
init {
side1.battle = this
side2.battle = this
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
@@ -106,22 +94,15 @@ open class PokemonBattle(
val battleLog = mutableListOf<String>()
val chatLog = mutableListOf<Text>()
var started = false
var winners = listOf<BattleActor>()
var losers = listOf<BattleActor>()
var ended = false
// TEMP battle showcase stuff
var announcingRules = false
var turn: Int = 1
private set
private var ticks: Int = 0
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
/** The current duration of the battle in seconds. */
val time: Int get() = ticks % 20
var dispatchResult = GO
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
val afterDispatches = mutableListOf<() -> Unit>()
val captureActions = mutableListOf<BattleCaptureAction>()
@@ -178,7 +159,7 @@ open class PokemonBattle(
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
/**
* Gets a [BattleActor] and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
*
* Returns null if either the pn or x is invalid.
*/
@@ -191,11 +172,6 @@ open class PokemonBattle(
return actor to pokemon
}
/**
* Gets a [BattlePokemon] from a pnx key and uuid.
*
* Returns null if the pnx key is invalid or the uuid does not exist.
*/
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
@@ -276,8 +252,8 @@ open class PokemonBattle(
}
}
sendUpdate(BattleEndPacket())
sendUpdate(BattleMusicPacket(null))
BattleRegistry.closeBattle(this)
onEndHandlers.forEach { it(this) }
}
fun finishCaptureAction(captureAction: BattleCaptureAction) {
@@ -343,12 +319,6 @@ open class PokemonBattle(
fun dispatch(dispatcher: () -> DispatchResult) {
dispatches.add(BattleDispatch { dispatcher() })
}
fun dispatchToFront(dispatcher: () -> DispatchResult) {
dispatches.addFirst(BattleDispatch { dispatcher() })
}
fun dispatchGo(dispatcher: () -> Unit) {
@@ -365,14 +335,6 @@ open class PokemonBattle(
}
}
fun dispatchFuture(future: () -> CompletableFuture<*>) {
val dispatch = BattleDispatch {
val generatedFuture = future()
return@BattleDispatch DispatchResult { generatedFuture.isDone }
}
dispatches.add(dispatch)
}
fun dispatchInsert(dispatcher: () -> Iterable<BattleDispatch>) {
dispatch {
val newDispatches = dispatcher()
@@ -388,10 +350,6 @@ open class PokemonBattle(
dispatches.add(dispatcher)
}
fun dispatchToFront(dispatcher: BattleDispatch) {
dispatches.addFirst(dispatcher)
}
fun doWhenClear(action: () -> Unit) {
afterDispatches.add(action)
}
@@ -416,9 +374,8 @@ open class PokemonBattle(
return
}
if (started) {
ticks++
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
if (started && isPvW && !ended && dispatches.isEmpty()) {
checkFlee()
}
}
@@ -460,24 +417,13 @@ open class PokemonBattle(
}
fun checkForInputDispatch() {
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
val readyToInput = actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose }
if (readyToInput && captureActions.isEmpty()) {
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
actors.forEach { it.responses.clear() ; it.request = null }
}
}
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
private fun checkForfeit(): Boolean {
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
return forfeit?.let {
this.dispatchWaiting { this.broadcastChatMessage(battleLang("forfeit", it.getName()).red()) }
writeShowdownAction(">forcelose ${it.showdownId}")
true
} ?: false
}
/**
* 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.
@@ -508,13 +454,4 @@ open class PokemonBattle(
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()
}
fun addQueryFunctions(queryStruct: QueryStruct): QueryStruct {
queryStruct.addFunction("pvp") { DoubleValue(isPvP) }
queryStruct.addFunction("pvn") { DoubleValue(isPvN) }
queryStruct.addFunction("pvw") { DoubleValue(isPvW) }
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
return queryStruct
}
}
@@ -145,7 +145,4 @@ abstract class BattleActor(
}
open fun awardExperience(battlePokemon: BattlePokemon, experience: Int) {}
open fun sendUpdate(packet: NetworkPacket<*>) {}
open fun win(otherWinners: List<BattleActor>, losers: List<BattleActor>) {}
open fun lose(winners: List<BattleActor>, otherLosers: List<BattleActor>) {}
}
@@ -1,125 +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.dialogue
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.dialogue.input.ActiveInput
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
/**
* An active instance of [Dialogue]. Bound to a player. These all need to be created through DialogueManager
* or things will go to shit.
*
* @author Hiroku
* @since December 27th, 2023
*/
class ActiveDialogue(var playerEntity: ServerPlayerEntity, var dialogueReference: Dialogue) {
val dialogueId = UUID.randomUUID()
val runtime = MoLangRuntime().setup()
var currentPage = dialogueReference.pages[0]
val playerStruct = playerEntity.asMoLangValue()
var activeInput = ActiveInput(this, currentPage.input)
init {
runtime.environment.getQueryStruct().addFunctions(
mapOf(
"dialogue" to java.util.function.Function { _ -> toMoLangStruct() },
"player" to java.util.function.Function { _ -> playerStruct }
)
)
}
val currentPageIndex
get() = dialogueReference.pages.indexOf(currentPage)
fun setPage(value: MoValue) {
val page = if (value is StringValue) {
dialogueReference.pages.find { it.id == value.value }
?: return Cobblemon.LOGGER.error("Dialogue requested page ${value.value} but it doesn't exist")
} else {
val pageNum = value.asDouble().toInt()
if (pageNum < 0 || pageNum >= dialogueReference.pages.size) {
return Cobblemon.LOGGER.error("Dialogue requested page $pageNum but it doesn't exist")
} else {
dialogueReference.pages[pageNum]
}
}
setPage(page)
}
fun isActive() = DialogueManager.activeDialogues[playerEntity.uuid] == this
fun incrementPage() {
setPage(currentPageIndex + 1)
}
fun setPage(page: DialoguePage) {
currentPage = page
activeInput = ActiveInput(this, currentPage.input)
val deadline = currentPage.input.timeout?.duration
val inputId = activeInput.inputId
if (deadline != null && deadline > 0) {
ServerRealTimeTaskTracker.after(seconds = deadline) {
if (inputId == activeInput.inputId && isActive()) {
activeInput.dialogueInput.timeout?.action?.invoke(this, null)
}
}
}
playerEntity.sendPacket(DialogueOpenedPacket(this, false))
}
fun setPage(index: Int) {
if (index == dialogueReference.pages.size) {
return close()
}
if (index < 0 || index > dialogueReference.pages.size) {
return Cobblemon.LOGGER.error("Dialogue requested page $index but it doesn't exist")
}
setPage(dialogueReference.pages[index])
}
fun toMoLangStruct(): MoStruct {
return QueryStruct(
hashMapOf(
"current_page" to java.util.function.Function { _ -> currentPage.toMoLangStruct(this) },
"current_page_number" to java.util.function.Function { _ -> DoubleValue(currentPageIndex) },
"next_page" to java.util.function.Function { _ -> incrementPage() },
"set_page" to java.util.function.Function { args -> setPage(args[0]) },
"close" to java.util.function.Function { _ -> close() },
"input" to java.util.function.Function { params -> activeInput.handle(if (params.params.size > 0) params.get<MoValue>(0).asString() else "") },
)
).addStandardFunctions()
}
fun close() {
DialogueManager.stopDialogue(playerEntity)
}
fun escape() {
val action = currentPage.escapeAction ?: dialogueReference.escapeAction
action(this, null)
}
}
@@ -1,50 +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.dialogue
import com.cobblemon.mod.common.api.molang.ExpressionLike
/**
* A dialogue that could be sent to players.
*
* @author Hiroku
* @since December 27th, 2023
*/
class Dialogue(
val pages: List<DialoguePage> = mutableListOf(),
val escapeAction: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() },
val speakers: Map<String, DialogueSpeaker> = emptyMap()
) {
companion object {
fun of(
pages: Iterable<DialoguePage>,
escapeAction: ExpressionLike,
speakers: Map<String, DialogueSpeaker>
): Dialogue {
return Dialogue(
pages = pages.toList(),
escapeAction = ExpressionLikeDialogueAction(escapeAction),
speakers = speakers
)
}
fun of(
pages: Iterable<DialoguePage>,
escapeAction: (ActiveDialogue) -> Unit,
speakers: Map<String, DialogueSpeaker>
): Dialogue {
val dialogue = Dialogue(
pages = pages.toList(),
escapeAction = FunctionDialogueAction { activeDialogue, _ -> escapeAction(activeDialogue) },
speakers = speakers
)
return dialogue
}
}
}
@@ -1,44 +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.dialogue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.resolve
/**
* Something that can happen in the context of an [ActiveDialogue]. The input field is nullable because I'm reusing
* this for dialogue input timeouts which don't have an input. It'll be fine.
*
* @author Hiroku
* @since December 29th, 2023
*/
interface DialogueAction {
companion object {
@JvmStatic
val types = mutableMapOf<String, Class<out DialogueAction>>()
}
operator fun invoke(dialogue: ActiveDialogue, input: String? = null)
}
class FunctionDialogueAction(val consumer: (ActiveDialogue, String?) -> Unit) : DialogueAction {
override fun invoke(dialogue: ActiveDialogue, input: String?) {
consumer(dialogue, input)
}
}
class ExpressionLikeDialogueAction(val expression: ExpressionLike) : DialogueAction {
override fun invoke(dialogue: ActiveDialogue, input: String?) {
if (input != null) {
dialogue.runtime.environment.setSimpleVariable("selected_option", StringValue(input))
}
dialogue.runtime.resolve(expression)
}
}
@@ -1,46 +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.dialogue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.cobblemonResource
import java.util.UUID
import net.minecraft.util.Identifier
/**
* Something that produces a dialogue's renderable face. This is sealed because the client has very particular handling for this.
*
* @author Hiroku
* @since January 1st, 2024
*/
sealed interface DialogueFaceProvider {
companion object {
val types = mutableMapOf(
"player" to PlayerDialogueFaceProvider::class.java,
"standard" to ArtificialDialogueFaceProvider::class.java,
"expression" to ExpressionLikeDialogueFaceProvider::class.java
)
}
}
class ArtificialDialogueFaceProvider(
val modelType: String = "",
val identifier: Identifier = cobblemonResource("bulbasaur"),
val aspects: Set<String> = setOf()
) : DialogueFaceProvider
class ReferenceDialogueFaceProvider(
val entityId: Int
): DialogueFaceProvider
class PlayerDialogueFaceProvider(val playerId: UUID) : DialogueFaceProvider
class ExpressionLikeDialogueFaceProvider(
val providerExpression: ExpressionLike
): DialogueFaceProvider
@@ -1,44 +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.dialogue
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
import com.cobblemon.mod.common.util.activeDialogue
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
/**
* Manages the active dialogues for players. Map is indexed by player UUID.
* You really need to make sure any dialogues you start with a player go through this otherwise
* the player won't be able to close the dialogue.
*
* @author Hiroku
* @since December 27th, 2023
*/
object DialogueManager {
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
fun startDialogue(playerEntity: ServerPlayerEntity, dialogue: Dialogue) {
startDialogue(ActiveDialogue(playerEntity, dialogue))
}
fun startDialogue(activeDialogue: ActiveDialogue) {
activeDialogues[activeDialogue.playerEntity.uuid] = activeDialogue
val packet = DialogueOpenedPacket(activeDialogue, true)
activeDialogue.playerEntity.sendPacket(packet)
}
fun stopDialogue(playerEntity: ServerPlayerEntity) {
val activeDialogue = playerEntity.activeDialogue ?: return
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
activeDialogues.remove(activeDialogue.dialogueId)
}
}
@@ -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.api.dialogue
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.struct.MoStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
import com.cobblemon.mod.common.api.dialogue.input.DialogueNoInput
import com.google.gson.JsonArray
import net.minecraft.text.MutableText
/**
* A page of a dialogue. This has lines of text and also some kind of input expected from the player.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialoguePage(
var id: String = "",
var speaker: String? = null,
var lines: MutableList<DialogueText> = mutableListOf(),
var input: DialogueInput = DialogueNoInput(),
var clientActions: MutableList<Expression> = mutableListOf(),
var escapeAction: DialogueAction? = null,
) {
companion object {
@JvmOverloads
fun of(
/** The ID is optional, but if you want to be able to jump to this page from other pages then you probably want to set this. */
id: String = "",
speaker: String? = null,
lines: Iterable<MutableText>,
input: DialogueInput = DialogueNoInput(),
clientActions: Iterable<Expression> = emptyList(),
/** The thing to do when the player presses ESC while on this page. If null, falls back to the same property on [Dialogue]. */
escapeAction: ((ActiveDialogue) -> Unit)? = null,
): DialoguePage {
return DialoguePage(
id = id,
speaker = speaker,
lines = lines.map { WrappedDialogueText(it) }.toMutableList(),
input = input,
clientActions = clientActions.toMutableList(),
escapeAction = escapeAction?.let { func -> FunctionDialogueAction { activeDialogue, _ -> func(activeDialogue) } }
)
}
}
fun toMoLangStruct(activeDialogue: ActiveDialogue): MoStruct {
return QueryStruct(
hashMapOf(
"id" to java.util.function.Function { _ -> StringValue(id) },
"input" to java.util.function.Function { _ -> activeDialogue.activeInput.struct },
"lines" to java.util.function.Function { _ ->
val array = JsonArray()
lines.forEach { array.add(it(activeDialogue).string) }
MoValue.of(array)
}
)
)
}
}
@@ -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.api.dialogue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
/**
* A predicate loaded for a particular dialogue. Tests arbitrary conditions about the dialogue context.
*
* @author Hiroku
* @since December 29th, 2023
*/
interface DialoguePredicate {
companion object {
val types = mutableMapOf<String, Class<out DialoguePredicate>>()
}
operator fun invoke(dialogue: ActiveDialogue): Boolean
}
class ExpressionLikeDialoguePredicate(val expression: ExpressionLike = "true".asExpressionLike()) : DialoguePredicate {
override fun invoke(dialogue: ActiveDialogue) = dialogue.runtime.resolveBoolean(expression)
}
class FunctionDialoguePredicate(val predicate: (ActiveDialogue) -> Boolean = { true }) : DialoguePredicate {
override fun invoke(dialogue: ActiveDialogue) = predicate(dialogue)
}
@@ -1,25 +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.dialogue
import com.cobblemon.mod.common.api.text.text
import net.minecraft.text.MutableText
/**
* A kind of speaker in a dialogue. They include a name and a face, each optional.
*
* @author Hiroku
* @since January 1st, 2024
*/
class DialogueSpeaker(
val name: DialogueText? = null,
val face: DialogueFaceProvider? = null
) {
fun of(name: MutableText = "".text(), face: DialogueFaceProvider? = null) = DialogueSpeaker(WrappedDialogueText(name), face)
}
@@ -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.dialogue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.text.text
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveString
import net.minecraft.text.MutableText
/**
* Some kind of text-resolving property. This is to hide where sometimes we want literals,
* sometimes we want the text to come from a function, and sometimes we want it to be the
* product of a MoLang script.
*
* @author Hiroku
* @since December 29th, 2023
*/
interface DialogueText {
companion object {
val types = mutableMapOf<String, Class<out DialogueText>>(
"expression" to ExpressionLikeDialogueText::class.java,
)
}
operator fun invoke(activeDialogue: ActiveDialogue): MutableText
}
class FunctionDialogueText(val function: (ActiveDialogue) -> MutableText = { "".text() }) : DialogueText {
override fun invoke(activeDialogue: ActiveDialogue) = function(activeDialogue)
}
class WrappedDialogueText(val text: MutableText = "".text()) : DialogueText {
override fun invoke(activeDialogue: ActiveDialogue) = text.copy()
}
class ExpressionLikeDialogueText(val expression: ExpressionLike = "''".asExpressionLike()) : DialogueText {
override fun invoke(activeDialogue: ActiveDialogue): MutableText {
return activeDialogue.runtime.resolveString(expression).text()
}
}
@@ -1,72 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.dialogue
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.util.adapters.DialogueActionAdapter
import com.cobblemon.mod.common.util.adapters.DialogueFaceProviderAdapter
import com.cobblemon.mod.common.util.adapters.DialogueInputAdapter
import com.cobblemon.mod.common.util.adapters.DialoguePredicateAdapter
import com.cobblemon.mod.common.util.adapters.DialogueTextAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
/**
* Registry for dialogue data.
*
* @see Dialogue
* @since December 29th, 2023
* @author Hiroku
*/
object Dialogues : JsonDataRegistry<Dialogue> {
override val id = cobblemonResource("dialogues")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<Dialogues>()
val dialogues = mutableMapOf<Identifier, Dialogue>()
/** If you need custom adapters registered, subscribe to this and register them. */
val gsonObservable: SimpleObservable<GsonBuilder> = SimpleObservable()
override fun sync(player: ServerPlayerEntity) {}
override val gson = GsonBuilder()
.registerTypeAdapter(DialogueAction::class.java, DialogueActionAdapter)
.registerTypeAdapter(DialoguePredicate::class.java, DialoguePredicateAdapter)
.registerTypeAdapter(DialogueInput::class.java, DialogueInputAdapter)
.registerTypeAdapter(DialogueFaceProvider::class.java, DialogueFaceProviderAdapter)
.registerTypeAdapter(DialogueText::class.java, DialogueTextAdapter)
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(MutableText::class.java, TextAdapter)
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.also { gsonObservable.emit(it) }
.create()
override val typeToken = TypeToken.get(Dialogue::class.java)
override val resourcePath = "dialogues"
override fun reload(data: Map<Identifier, Dialogue>) {
dialogues.putAll(data)
observable.emit(this)
}
}
@@ -1,42 +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.dialogue.input
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
import com.cobblemon.mod.common.util.server
import java.util.UUID
/**
* An active input waiting for the player as part of an [ActiveDialogue]. The purpose of this is to
* maintain some data integrity and track how long it's taken to choose an action.
*
* @author Hiroku
* @since December 27th, 2023
*/
class ActiveInput(
val activeDialogue: ActiveDialogue,
val dialogueInput: DialogueInput
) {
val inputId = UUID.randomUUID()
val startTime = server()!!.overworld.time
val struct = toMoLangStruct()
fun handle(input: String) {
val secondsToChoose = (server()!!.overworld.time - startTime) / 20F
activeDialogue.runtime.environment.setSimpleVariable("seconds_taken_to_input", DoubleValue(secondsToChoose))
dialogueInput.handle(this, input)
}
fun toMoLangStruct(): MoValue {
return dialogueInput.toMoLangStruct(this)
}
}
@@ -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.api.dialogue.input
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.dialogue.DialogueAction
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
/**
* Input that has no input but has an action that will run after a delay.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueAutoContinueInput : DialogueInput {
val delay = 5F
/** Whether the player can click to move on in a hurry or if they must wait. */
var allowSkip = true
var showTimer = false
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
override var timeout: DialogueTimeout?
get() = DialogueTimeout(duration = delay, showTimer = showTimer, action)
set(_) {}
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
override fun handle(activeInput: ActiveInput, value: String) {
if (!allowSkip) {
return Cobblemon.LOGGER.warn("A no-skip dialogue received input from ${activeInput.activeDialogue.playerEntity.gameProfile.name}, is this person a hacker or something")
}
action.invoke(activeInput.activeDialogue)
}
}
@@ -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.api.dialogue.input
import com.bedrockk.molang.runtime.struct.MoStruct
import com.cobblemon.mod.common.api.dialogue.DialoguePage
/**
* A type of input to [DialoguePage]s. This is sealed because the client needs to know about it. Sorry.
*
* @author Hiroku
* @since December 27th, 2023
*/
sealed interface DialogueInput {
var timeout: DialogueTimeout?
fun toMoLangStruct(activeInput: ActiveInput): MoStruct
fun handle(activeInput: ActiveInput, value: String)
}
@@ -1,33 +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.dialogue.input
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.cobblemon.mod.common.api.dialogue.DialogueAction
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
/**
* An input type that's really just waiting for the player to click or something.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueNoInput(
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
) : DialogueInput {
override var timeout: DialogueTimeout?
get() = null
set(_) {}
override fun toMoLangStruct(activeInput: ActiveInput) = VariableStruct()
override fun handle(activeInput: ActiveInput, value: String) {
action(activeInput.activeDialogue)
}
}
@@ -1,32 +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.dialogue.input
import com.cobblemon.mod.common.api.dialogue.DialogueAction
import com.cobblemon.mod.common.api.dialogue.DialoguePredicate
import com.cobblemon.mod.common.api.dialogue.DialogueText
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
import com.cobblemon.mod.common.api.dialogue.FunctionDialoguePredicate
import com.cobblemon.mod.common.api.dialogue.WrappedDialogueText
/**
* A choosable option as part of a [DialogueOptionSetInput].
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueOption(
var text: DialogueText = WrappedDialogueText(),
/** The value is a unique identifier so the client can tell the server what they selected. Don't forget this. */
var value: String = "",
/** The action to run when they click it. */
var action: DialogueAction = FunctionDialogueAction { _, _ -> },
val isVisible: DialoguePredicate = FunctionDialoguePredicate(),
val isSelectable: DialoguePredicate = FunctionDialoguePredicate()
)
@@ -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.dialogue.input
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
/**
* A type of [DialogueInput] that has the player choose from a list of options.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueOptionSetInput(
var options: MutableList<DialogueOption>,
override var timeout: DialogueTimeout? = null,
/** Whether the buttons should be stacked vertically. */
var vertical: Boolean = false,
) : DialogueInput {
// JSON uses this. Basically so that the main constructor can force people to specify options
constructor() : this(mutableListOf(), null, false)
fun getVisibleOptions(activeDialogue: ActiveDialogue) = options.filter { it.isVisible(activeDialogue) }
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
override fun handle(activeInput: ActiveInput, value: String) {
val option = options.firstOrNull { it.value == value }
if (option != null) {
if (!option.isSelectable(activeInput.activeDialogue)) {
Cobblemon.LOGGER.warn("Dialogue option $value is not selectable but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
activeInput.activeDialogue.close()
} else if (!option.isVisible(activeInput.activeDialogue)) {
Cobblemon.LOGGER.warn("Dialogue option $value is not visible but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
activeInput.activeDialogue.close()
}
option.action(activeInput.activeDialogue, value)
} else {
Cobblemon.LOGGER.warn("No option with value $value found in dialogue option set")
}
}
}
@@ -1,29 +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.dialogue.input
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.dialogue.DialogueAction
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
/**
* A text input for dialogues where the player can enter free text.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueTextInput : DialogueInput {
override var timeout: DialogueTimeout? = null
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.setPage(dialogue.currentPageIndex + 1) }
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
override fun handle(activeInput: ActiveInput, value: String) {
action.invoke(activeInput.activeDialogue, value)
}
}
@@ -1,25 +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.dialogue.input
import com.cobblemon.mod.common.api.dialogue.DialogueAction
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
/**
* A deadline for dialogue input. This is used to have something occur if the player spends
* too long on one page of dialogue.
*
* @author Hiroku
* @since December 27th, 2023
*/
class DialogueTimeout(
var duration: Float = 10F,
var showTimer: Boolean = true,
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() }
)
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.entity.LivingEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
@@ -89,8 +88,6 @@ class DropTable {
amount: IntRange = this.amount
) {
val drops = getDrops(amount).toMutableList()
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
@@ -31,14 +31,14 @@ import net.minecraft.util.math.Vec3d
* @author Hiroku
* @since July 24th, 2022
*/
open class ItemDropEntry : DropEntry {
class ItemDropEntry : DropEntry {
override val percentage = 100F
override val quantity = 1
open val quantityRange: IntRange? = null
val quantityRange: IntRange? = null
override val maxSelectableTimes = 1
open val dropMethod: ItemDropMethod? = null
open val item = Identifier("minecraft:fish")
open val nbt: NbtCompound? = null
val dropMethod: ItemDropMethod? = null
val item = Identifier("minecraft:fish")
val nbt: NbtCompound? = null
override fun drop(entity: LivingEntity?, world: ServerWorld, pos: Vec3d, player: ServerPlayerEntity?) {
val item = world.registryManager.get(RegistryKeys.ITEM).get(item) ?: return LOGGER.error("Unable to load drop item: $item")
@@ -12,7 +12,6 @@ import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import java.lang.reflect.Type
@@ -29,10 +28,6 @@ object EntityDimensionsAdapter : JsonSerializer<EntityDimensions>, JsonDeseriali
const val WIDTH = "width"
const val HEIGHT = "height"
val templates = mutableMapOf(
"player" to { EntityDimensions(0.6F, 1.8F, false) }
)
override fun serialize(dimensions: EntityDimensions, type: Type, ctx: JsonSerializationContext): JsonElement {
val json = JsonObject()
json.addProperty(WIDTH, dimensions.width)
@@ -41,9 +36,6 @@ object EntityDimensionsAdapter : JsonSerializer<EntityDimensions>, JsonDeseriali
}
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): EntityDimensions {
if (json is JsonPrimitive) {
return templates[json.asString]?.invoke() ?: throw IllegalStateException("Dimensions provided by template name $json but no such template is set.")
}
json as JsonObject
return EntityDimensions(json.get(WIDTH).asFloat, json.get(HEIGHT).asFloat, false)
}
@@ -8,9 +8,7 @@
package com.cobblemon.mod.common.api.entity
import com.bedrockk.molang.runtime.struct.QueryStruct
import net.minecraft.entity.Entity
import net.minecraft.entity.data.TrackedData
/**
* Represents a delegation of a portion of an entity's logic to a particular side.
@@ -18,6 +16,4 @@ import net.minecraft.entity.data.TrackedData
interface EntitySideDelegate<T : Entity> {
fun initialize(entity: T) {}
fun tick(entity: T) {}
fun onTrackedDataSet(data: TrackedData<*>) {}
fun addToStruct(struct: QueryStruct) {}
}
@@ -1,19 +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.entity
import com.cobblemon.mod.common.entity.npc.NPCEntity
/**
* A delegate for some actions that can be different for an NPC on client versus server.
*
* @author Hiroku
* @since August 25th, 2023
*/
interface NPCSideDelegate : EntitySideDelegate<NPCEntity>
@@ -1,25 +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.entity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import java.util.concurrent.CompletableFuture
/**
* Interface for custom entities that can send out and recall Pokémon. They get notified
* when either of those actions are occurring.
*
* @author Hiroku
* @since August 25th, 2023
*
*/
interface PokemonSender {
fun sendingOut(): CompletableFuture<Unit>
fun recalling(pokemonEntity: PokemonEntity): CompletableFuture<Unit>
}
@@ -1,97 +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.entity.pokemon
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.nbt.NbtCompound
import java.util.concurrent.CompletableFuture
import kotlin.reflect.KClass
/**
* Represents a temporary alteration to how a [PokemonEntity] is rendered and behaves. May include a temporary visual effect
* when applied.
*
* @author Segfault Guy
* @since March 5th, 2024
*/
interface EntityEffect {
/**
* Starts this effect for the provided [PokemonEntity].
*
* @return A [CompletableFuture] that completes after the effect has been applied. Or null if the effect failed to start.
*/
fun start(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
/**
* Ends this effect for the provided [PokemonEntity].
*
* @return A [CompletableFuture] that completes after the effect has been reverted. Or null if the effect failed to end.
*/
fun end(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
/** Saves this effect to NBT. */
fun saveToNbt(): NbtCompound
/** Loads this effect from NBT. */
fun loadFromNBT(nbt: NbtCompound)
companion object {
private val effects = mutableMapOf<String, KClass<out EntityEffect>>()
private val defaults = mutableMapOf<String, () -> EntityEffect>()
init {
register(IllusionEffect.ID, IllusionEffect::class, ::IllusionEffect)
register(TransformEffect.ID, TransformEffect::class, ::TransformEffect)
}
fun <T : EntityEffect> register(id: String, type: KClass<T>, default: () -> T) {
effects[id] = type
defaults[id] = default
}
fun createDefault(id: String): EntityEffect? = defaults[id]?.invoke()
fun loadFromNbt(nbt: NbtCompound): EntityEffect? {
if (nbt.contains(DataKeys.ENTITY_EFFECT_ID)) {
val id = nbt.getString(DataKeys.ENTITY_EFFECT_ID)
return createDefault(id)?.also { it.loadFromNBT(nbt) }
}
return null
}
}
}
/** An [EntityEffect] that modifies the dimensions of a [PokemonEntity]. */
interface PhysicalEffect : EntityEffect {
val scale: Float
}
/** An [EntityEffect] that alters the physical appearance of a [PokemonEntity] to match a [mock]. */
interface MocKEffect : PhysicalEffect {
val mock: PokemonProperties
val exposedSpecies: Species?
get() = this.mock.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
val exposedForm: FormData?
get() = this.mock.form?.let {
formID -> this.exposedSpecies?.forms?.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }
?: this.exposedSpecies?.standardForm
}
@@ -33,8 +33,6 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
@@ -67,8 +65,6 @@ object CobblemonEvents {
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@JvmField
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
@JvmField
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
@@ -104,9 +100,6 @@ object CobblemonEvents {
@JvmField
val LEVEL_UP_EVENT = EventObservable<LevelUpEvent>()
@JvmField
/** CLIENT ONLY! */
val POKEMON_INTERACTION_GUI_CREATION = EventObservable<PokemonInteractionGUICreationEvent>()
@JvmField
val POKEMON_ENTITY_SAVE = EventObservable<PokemonEntitySaveEvent>()
@JvmField
@@ -160,8 +153,4 @@ object CobblemonEvents {
val LEFTOVERS_CREATED = CancelableObservable<LeftoversCreatedEvent>()
@JvmField
val BIG_ROOT_PROPAGATED = CancelableObservable<BigRootPropagatedEvent>()
@JvmField
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
@JvmField
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
}
@@ -9,19 +9,26 @@
package com.cobblemon.mod.common.api.events.battles
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.events.Cancelable
import net.minecraft.text.MutableText
import com.cobblemon.mod.common.battles.BattleFormat
/**
* Event fired before a [PokemonBattle] is started. Canceling this event prevents the battle from being
* created and launched.
*
* @property reason The text used to inform the participants why the battle was canceled. Keep null for a default error.
*
* @author Segfault Guy
* @since March 26th 2023
*/
data class BattleStartedPreEvent (override val battle: PokemonBattle, var reason: MutableText? = null) : BattleEvent, Cancelable()
data class BattleStartedPreEvent (
val participants: Collection<BattleActor>,
val format: BattleFormat,
val isPvP: Boolean,
val isPvN: Boolean,
val isPvW: Boolean
) : Cancelable()
/**
* Event fired after a [PokemonBattle] starts.
@@ -29,4 +36,8 @@ data class BattleStartedPreEvent (override val battle: PokemonBattle, var reason
* @author Segfault Guy
* @since March 26th 2023
*/
data class BattleStartedPostEvent (override val battle: PokemonBattle) : BattleEvent
data class BattleStartedPostEvent (
override val battle: PokemonBattle
) : BattleEvent
@@ -1,56 +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.events.pokemon
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.item.ItemStack
/**
* The base for all the events related to held items.
*
* @see [Pre]
* @see [Post]
*/
interface HeldItemEvent {
/**
* The [Pokemon] triggering this event.
*/
val pokemon: Pokemon
/**
* Fired at the start of [Pokemon.swapHeldItem].
*
* This event should be used to mutate the results of this transaction.
*
* Canceling this event will prevent the operation and causes the return to be item attempted to be given originally.
*
* @property pokemon The [Pokemon] triggering this event.
* @property receiving The [ItemStack] being sent received from the transaction. By default, this is the item that triggered the interaction.
* @property returning The [ItemStack] being sent back from the transaction. By default, this is the currently held item.
* @property decrement If the operation should decrement the [receiving] [ItemStack.count], this is handled in the implementation.
*
* @see [Post]
*/
data class Pre(override val pokemon: Pokemon, var receiving: ItemStack, var returning: ItemStack, var decrement: Boolean) : HeldItemEvent, Cancelable()
/**
* Fired at the end of [Pokemon.swapHeldItem].
*
* @property pokemon The [Pokemon] triggering this event.
* @property received The [ItemStack] considered as received and set to the [pokemon]. This is a copy and mutation will not be taken into account.
* @property returned The [ItemStack] returned by the method call. This is a copy and mutation will not be taken into account.
* @property decremented If the [received] [ItemStack] got decremented.
*
* @see [Pre]
*/
data class Post(override val pokemon: Pokemon, val received: ItemStack, val returned: ItemStack, val decremented: Boolean) : HeldItemEvent
}
@@ -8,23 +8,12 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.registry.RegistryKeys
import net.minecraft.server.network.ServerPlayerEntity
data class PokemonCapturedEvent (
val pokemon: Pokemon,
val player: ServerPlayerEntity,
val pokeBallEntity: EmptyPokeBallEntity
) {
val context = mapOf<String, MoValue>(
"pokemon" to pokemon.struct,
"player" to player.asMoLangValue(),
"poke_ball" to pokeBallEntity.struct,
"item" to player.world.itemRegistry.getEntry(pokeBallEntity.pokeBall.item).asMoLangValue(RegistryKeys.ITEM)
)
}
)
@@ -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.api.events.pokemon.interaction
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.entity.LivingEntity
import net.minecraft.item.ItemStack
/**
* Event published when a held item is being updated on a [Pokemon].
* Cancelling the event will prevent any action from being taken on
* the Pokémon.
*
* [newItem] differs from [originalStack] in that the former is a
* one-sized version of the original (Pokémon cannot hold stacks) and
* changing it in any way will not affect the original item held by
* the player.
*
* @author Whatsy, Hiroku
* @since November 13th, 2023
*/
data class HeldItemUpdatedEvent(
val cause: LivingEntity?,
val pokemon: Pokemon,
val originalStack: ItemStack,
val decrement: Boolean,
val oldItem: ItemStack,
val newItem: ItemStack
) : Cancelable()
@@ -1,42 +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.events.pokemon.interaction
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelOption
import com.cobblemon.mod.common.client.gui.interact.wheel.Orientation
import com.google.common.collect.Multimap
import java.util.UUID
data class PokemonInteractionGUICreationEvent(
val pokemonID: UUID,
val mountShoulder: Boolean,
val options: Multimap<Orientation, InteractWheelOption>
) {
fun addFillingOption(option: InteractWheelOption) {
options.put(getNextFreeOrientation(), option)
}
fun addOption(orientation: Orientation, option: InteractWheelOption) {
options.put(orientation, option)
}
private fun getNextFreeOrientation(): Orientation {
var largest = Orientation.TOP_LEFT
for(orientation in Orientation.values()) {
if(!options.containsKey(orientation)) {
return orientation
} else {
if(options.get(orientation).size < options.get(largest).size) {
largest = orientation
}
}
}
return largest
}
}
@@ -1,84 +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.fishing
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.util.Identifier
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtString
data class FishingBait(
val item: Identifier,
val effects: List<Effect>,
) {
data class Effect(
val type: Identifier,
val subcategory: Identifier?,
val chance: Double = 0.0,
val value: Double = 0.0
) {
fun toNbt(): NbtCompound {
val nbt = NbtCompound()
nbt.putString("Type", type.toString())
subcategory?.let { nbt.putString("Subcategory", it.toString()) }
nbt.putDouble("Chance", chance)
nbt.putDouble("Value", value)
return nbt
}
companion object {
fun fromNbt(nbt: NbtCompound): Effect {
val type = Identifier(nbt.getString("Type"))
val subcategory = if (nbt.contains("Subcategory")) Identifier(nbt.getString("Subcategory")) else null
val chance = nbt.getDouble("Chance")
val value = nbt.getDouble("Value")
return Effect(type, subcategory, chance, value)
}
}
}
fun toNbt(): NbtCompound {
val nbt = NbtCompound()
nbt.putString("Item", item.toString())
val effectsList = NbtList()
effects.forEach { effectsList.add(it.toNbt()) }
nbt.put("Effects", effectsList)
return nbt
}
companion object {
fun fromNbt(nbt: NbtCompound): FishingBait {
val item = Identifier(nbt.getString("Item"))
val effectsList = nbt.getList("Effects", 10) // 10 is the type for NbtCompound
val effects = mutableListOf<Effect>()
for (i in 0 until effectsList.size) {
effects.add(Effect.fromNbt(effectsList.getCompound(i)))
}
return FishingBait(item, effects)
}
}
object Effects {
val NATURE = cobblemonResource("nature")
val IV = cobblemonResource("iv")
val EV = cobblemonResource("ev")
val BITE_TIME = cobblemonResource("bite_time")
val GENDER_CHANCE = cobblemonResource("gender_chance")
val LEVEL_RAISE = cobblemonResource("level_raise")
val TERA = cobblemonResource("tera")
val SHINY_REROLL = cobblemonResource("shiny_reroll")
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
val FRIENDSHIP = cobblemonResource("friendship")
val INERT = cobblemonResource("inert")
}
}
@@ -1,105 +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.fishing
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.fishing.FishingBaitRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object FishingBaits : JsonDataRegistry<FishingBait>{
override val id = cobblemonResource("fishing_baits")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<FishingBaits>()
override val typeToken: TypeToken<FishingBait> = TypeToken.get(FishingBait::class.java)
override val resourcePath = "fishing_baits"
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.setPrettyPrinting()
.create()
private val itemMap = mutableMapOf<Identifier, FishingBait>()
override fun sync(player: ServerPlayerEntity) {
FishingBaitRegistrySyncPacket(this.itemMap.values.toList()).sendToPlayer(player)
}
override fun reload(data: Map<Identifier, FishingBait>) {
itemMap.clear()
data.forEach { id, bait ->
itemMap[bait.item] = bait
}
}
fun getFromItemStack(stack: ItemStack): FishingBait? {
return itemMap[Registries.ITEM.getId(stack.item)]
}
fun isFishingBait(stack: ItemStack) = itemMap.containsKey(Registries.ITEM.getId(stack.item))
//
//
// fun getBaitSubcategory(item: ItemStack): String? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.subcategory
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.subcategory
// }
// return null
// }
//
// fun getBaitSuccessChance(item: ItemStack): Double? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.chance
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.chance
// }
// return null
// }
//
// fun getBaitEffectValue(item: ItemStack): Double? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.value
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.value
// }
// return null
// }
//
//
// fun getBaitNote(item: ItemStack): String? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.note
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.note
// }
// return null
// }
}
@@ -1,48 +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.fishing
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.pokeball.PokeBall
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
/**
* Base poke rod object
* It is intended that there is one poke rod object initialized for a given poke rod type.
*
* @property name the poke rod registry name
* @property pokeBallId The [Identifier] of the pokeball that is used as the bobber for this rod
* @property lineColor list of [RGB] values that apply to the fishing line of the Pokérod
*/
data class PokeRod(
val pokeBallId: Identifier,
//Hex string of color
val lineColor: String,
var name: Identifier?
) {
internal fun encode(buffer: PacketByteBuf) {
buffer.writeIdentifier(name)
buffer.writeIdentifier(pokeBallId)
buffer.writeString(lineColor)
}
companion object {
internal fun decode(buffer: PacketByteBuf): PokeRod {
val name = buffer.readIdentifier()
val pokeBallId = buffer.readIdentifier()
val lineColor = buffer.readString()
return PokeRod(pokeBallId, lineColor, name)
}
}
fun getPokeBall(): PokeBall? {
return PokeBalls.getPokeBall(pokeBallId)
}
}
@@ -1,62 +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.fishing
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokeRodRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
/**
* The data registry for [PokeRod]s.
* All the pokerod fields are guaranteed to exist
*/
object PokeRods : JsonDataRegistry<PokeRod> {
override val id = cobblemonResource("pokerods")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<PokeRods>()
// ToDo once datapack pokerod is implemented add required adapters here
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.setPrettyPrinting()
.create()
override val typeToken: TypeToken<PokeRod> = TypeToken.get(PokeRod::class.java)
override val resourcePath = "pokerods"
private val rods = mutableMapOf<Identifier, PokeRod>()
override fun reload(data: Map<Identifier, PokeRod>) {
data.forEach {
it.value.name = it.key
rods[it.key] = it.value
}
this.observable.emit(this)
}
override fun sync(player: ServerPlayerEntity) {
PokeRodRegistrySyncPacket(rods.values).sendToPlayer(player)
}
/**
* Gets a Pokerod from registry name.
* @return the pokerod object if found otherwise null.
*/
fun getPokeRod(name : Identifier): PokeRod? = rods[name]
}
@@ -1,80 +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.fossil
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.StringIdentifiable
class Fossil(
identifier: Identifier,
val result: PokemonProperties,
val fossils: List<NbtItemPredicate>
): StringIdentifiable {
@Transient
var identifier: Identifier = identifier
internal set
override fun asString(): String {
return identifier.toString()
}
/**
* Gets the name of the fossil.
* @return The name of the fossil.
*/
fun getName(): MutableText = Text.translatable("${identifier.namespace}.fossil.${identifier.path}.name")
/**
* Whether the fossil ingredients match this fossil.
* @param ingredients The ingredients to check.
* @return True if the ingredients match, false otherwise.
*/
fun matchesIngredients(ingredients: List<ItemStack>): Boolean {
if (this.fossils.size != ingredients.size) {
return false
}
return this.fossils.all { fossil ->
ingredients.any { fossil.item.fits(it.item, Registries.ITEM) && fossil.nbt.test(it) }
}
}
/**
* Whether the fossil ingredients match a subset of this fossil.
* @param ingredients The ingredients to check.
* @return True if the ingredients are a subset, false otherwise.
*/
fun matchesIngredientsSubSet(ingredients: List<ItemStack>): Boolean {
if (this.fossils.size < ingredients.size) {
return false
}
return ingredients.all { ingredient ->
ingredients.count { item -> ingredient.itemMatches(item.registryEntry) } <=
this.fossils.count { fossil -> fossil.item.fits(ingredient.item, Registries.ITEM) && fossil.nbt.test(ingredient) }
}
}
/**
* Whether the [ItemStack] is an ingredient for this fossil.
* @param itemStack The [ItemStack] to check.
* @return True if the [ItemStack] is an ingredient, false otherwise.
*/
fun isIngredient(itemStack: ItemStack): Boolean {
return this.fossils.any { it.item.fits(itemStack.item, Registries.ITEM) && it.nbt.test(itemStack) }
}
}
@@ -1,107 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.fossil
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapter
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object Fossils: JsonDataRegistry<Fossil> {
override val id: Identifier = cobblemonResource("fossils")
override val type: ResourceType = ResourceType.SERVER_DATA
override val observable = SimpleObservable<Fossils>()
override val gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
.create()
override val typeToken: TypeToken<Fossil> = TypeToken.get(Fossil::class.java)
override val resourcePath: String = "fossils"
private val fossils = hashMapOf<Identifier, Fossil>()
override fun reload(data: Map<Identifier, Fossil>) {
this.fossils.clear()
data.forEach { (identifier, fossil) ->
try {
fossil.identifier = identifier
this.fossils[identifier] = fossil
} catch (e: Exception) {
Cobblemon.LOGGER.error("Skipped loading the {} fossil", identifier, e)
}
}
Cobblemon.LOGGER.info("Loaded {} fossils", this.fossils.size)
this.observable.emit(this)
}
override fun sync(player: ServerPlayerEntity) {
FossilRegistrySyncPacket(this.all()).sendToPlayer(player)
}
/**
* Gets all loaded [Fossil]s.
*/
fun all() = this.fossils.values.toList()
/**
* Gets a [Fossil] by its [Identifier].
* @param identifier The identifier of the fossil.
* @return The [Fossil] if loaded, otherwise null.
*/
fun getByIdentifier(identifier: Identifier): Fossil? = this.fossils[identifier]
/**
* Looks for a [Fossil] that matches a [ItemStack].
* @param fossilStacks The fossil [ItemStack]'s.
* @return The [Fossil] if found, otherwise null.
*/
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
}
/**
* Looks for a [Fossil] that is a superset of [ItemStack].
* @param fossilStacks The fossil [ItemStack]'s.
* @return The [Fossil] if found to be a superset, otherwise null.
*/
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
}
/**
* Checks if a [ItemStack] is a fossil ingredient.
* @param itemStack The ingredient [ItemStack].
* @return true if it's a fossil ingredient, otherwise false.
*/
fun isFossilIngredient(itemStack: ItemStack): Boolean {
return this.all().any { it.isIngredient(itemStack) }
}
}
@@ -1,19 +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.fossil
import com.cobblemon.mod.common.registry.ItemTagCondition
import net.minecraft.util.Identifier
data class NaturalMaterial(
val content: Int = 0,
val item: Identifier?,
val tag: ItemTagCondition? = null,
val returnItem: Identifier? = null
)
@@ -1,90 +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.fossil
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
import com.cobblemon.mod.common.registry.ItemTagCondition
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
override val id = cobblemonResource("natural_materials")
override val type = ResourceType.SERVER_DATA
override val observable = SimpleObservable<NaturalMaterials>()
override val typeToken: TypeToken<List<NaturalMaterial>> =
TypeToken.getParameterized(List::class.java, NaturalMaterial::class.java) as TypeToken<List<NaturalMaterial>>
override val resourcePath = "natural_materials"
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
.registerTypeAdapter(ItemTagCondition::class.java, ItemLikeConditionAdapter)
.create()
private val itemMap = mutableMapOf<Identifier, NaturalMaterial>()
private val tagMap = mutableMapOf<ItemTagCondition, NaturalMaterial>()
override fun sync(player: ServerPlayerEntity) {
NaturalMaterialRegistrySyncPacket(this.itemMap.values.toList() + this.tagMap.values.toList()).sendToPlayer(player)
}
override fun reload(data: Map<Identifier, List<NaturalMaterial>>) {
data.forEach { entry ->
entry.value.forEach {
itemMap.remove(it.item)
if (it.item != null) {
itemMap[it.item] = it
}
if (it.tag != null) {
tagMap[it.tag] = it
}
}
}
}
fun isNaturalMaterial(item: ItemStack): Boolean {
val itemId = Registries.ITEM.getId(item.item)
return itemId in itemMap.keys || tagMap.keys.any {
it.fits(item.item, Registries.ITEM)
}
}
fun getContent(item: ItemStack): Int? {
val itemId = Registries.ITEM.getId(item.item)
if (itemId in itemMap.keys) {
return itemMap[itemId]?.content
}
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
if (tag != null) {
return tagMap[tag]?.content
}
return null
}
fun getReturnItem(item: ItemStack): Identifier? {
val itemId = Registries.ITEM.getId(item.item)
if (itemId in itemMap.keys) {
return itemMap[itemId]?.returnItem
}
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
if (tag != null) {
return tagMap[tag]?.returnItem
}
return null
}
}
@@ -10,11 +10,12 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.api.text.font
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay.Companion.PORTRAIT_DIAMETER
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Species
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
@@ -28,17 +29,14 @@ import net.minecraft.client.render.Tessellator
import net.minecraft.client.render.VertexFormat
import net.minecraft.client.render.VertexFormats
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.Entity
import net.minecraft.text.MutableText
import net.minecraft.text.OrderedText
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.util.math.RotationAxis
import org.joml.Matrix4f
import org.joml.Quaternionf
import org.joml.Vector3f
@JvmOverloads
fun blitk(
matrixStack: MatrixStack,
texture: Identifier? = null,
@@ -102,7 +100,6 @@ fun drawRectangle(
BufferRenderer.drawWithGlobalProgram(bufferbuilder.end())
}
@JvmOverloads
fun drawCenteredText(
context: DrawContext,
font: Identifier? = null,
@@ -117,7 +114,6 @@ fun drawCenteredText(
context.drawText(textRenderer, comp, x.toInt() - textRenderer.getWidth(comp) / 2, y.toInt(), colour, shadow)
}
@JvmOverloads
fun drawText(
context: DrawContext,
font: Identifier? = null,
@@ -149,7 +145,6 @@ fun drawText(
return isHovered
}
@JvmOverloads
fun drawText(
context: DrawContext,
text: OrderedText,
@@ -168,7 +163,6 @@ fun drawText(
context.drawText(textRenderer, text, tweakedX.toInt(), y.toInt(), colour, shadow)
}
@JvmOverloads
fun drawString(
context: DrawContext,
text: String,
@@ -187,31 +181,21 @@ fun drawString(
context.drawText(textRenderer, comp, x.toInt(), y.toInt(), colour, shadow)
}
@JvmOverloads
fun <T : Entity, M : PoseableEntityModel<T>> drawPoseablePortrait(
identifier: Identifier,
fun drawPortraitPokemon(
species: Species,
aspects: Set<String>,
matrixStack: MatrixStack,
scale: Float = 13F,
contextScale: Float = 1F,
reversed: Boolean = false,
state: PoseableEntityState<T>? = null,
repository: VaryingModelRepository<T, M>,
partialTicks: Float,
limbSwing: Float = 0F,
limbSwingAmount: Float = 0F,
ageInTicks: Float = 0F,
headYaw: Float = 0F,
headPitch: Float = 0F
state: PoseableEntityState<PokemonEntity>? = null,
partialTicks: Float
) {
val model = repository.getPoser(identifier, aspects)
val texture = repository.getTexture(identifier, aspects, state?.animationSeconds ?: 0F)
val model = PokemonModelRepository.getPoser(species.resourceIdentifier, aspects)
val texture = PokemonModelRepository.getTexture(species.resourceIdentifier, aspects, state?.animationSeconds ?: 0F)
val context = RenderContext()
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, contextScale)
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, aspects)
PokemonModelRepository.getTextureNoSubstitute(species.resourceIdentifier, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, species.getForm(aspects).baseScale)
val renderType = model.getLayer(texture)
@@ -222,12 +206,10 @@ fun <T : Entity, M : PoseableEntityModel<T>> drawPoseablePortrait(
if (state == null) {
model.setupAnimStateless(setOf(PoseType.PORTRAIT, PoseType.PROFILE))
} else {
val originalPose = state.currentPose
model.getPose(PoseType.PORTRAIT)?.let { state.setPose(it.poseName) }
state.timeEnteredPose = 0F
state.updatePartialTicks(partialTicks)
model.setupAnimStateful(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
originalPose?.let { state.setPose(it) }
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
}
matrixStack.push()
@@ -248,7 +230,7 @@ fun <T : Entity, M : PoseableEntityModel<T>> drawPoseablePortrait(
val buffer = immediate.getBuffer(renderType)
val packedLight = LightmapTextureManager.pack(11, 7)
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
model.withLayerContext(immediate, state, PokemonModelRepository.getLayers(species.resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
immediate.draw()
}
@@ -256,58 +238,5 @@ fun <T : Entity, M : PoseableEntityModel<T>> drawPoseablePortrait(
matrixStack.pop()
model.setDefault()
DiffuseLighting.enableGuiDepthLighting()
}
fun <E : Entity, M : PoseableEntityModel<E>> drawProfile(
repository: VaryingModelRepository<E, M>,
resourceIdentifier: Identifier,
aspects: Set<String>,
matrixStack: MatrixStack,
state: PoseableEntityState<E>,
partialTicks: Float,
scale: Float = 20F
) {
val model = repository.getPoser(resourceIdentifier, aspects)
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
val context = RenderContext()
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, 1F)
context.put(RenderContext.SPECIES, resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
val renderType = model.getLayer(texture)
RenderSystem.applyModelViewMatrix()
matrixStack.scale(scale, scale, -scale)
model.getPose(PoseType.PROFILE)?.let { state.setPose(it.poseName) }
state.timeEnteredPose = 0F
state.updatePartialTicks(partialTicks)
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
// matrixStack.multiply(rotation)
val quaternion1 = RotationAxis.POSITIVE_Y.rotationDegrees(-32F * if (false) -1F else 1F)
val quaternion2 = RotationAxis.POSITIVE_X.rotationDegrees(5F)
matrixStack.multiply(quaternion1)
matrixStack.multiply(quaternion2)
DiffuseLighting.method_34742()
val entityRenderDispatcher = MinecraftClient.getInstance().entityRenderDispatcher
entityRenderDispatcher.setRenderShadows(true)
val bufferSource = MinecraftClient.getInstance().bufferBuilders.entityVertexConsumers
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightmapTextureManager.pack(11, 7)
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.DEFAULT_UV, 1F, 1F, 1F, 1F)
bufferSource.draw()
}
model.setDefault()
entityRenderDispatcher.setRenderShadows(true)
DiffuseLighting.enableGuiDepthLighting()
}
@@ -1,74 +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.item.ability
import com.cobblemon.mod.common.api.abilities.*
import com.cobblemon.mod.common.item.interactive.ability.AbilityTypeChanger
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
/**
* Represents a change operation for a [Pokemon.ability].
* This is backed by the associated [PotentialAbility].
*
* @param T The type of [PotentialAbility].
*/
interface AbilityChanger<T : PotentialAbility> {
/**
* The [PotentialAbilityType] of type [T].
*/
val type: PotentialAbilityType<T>
/**
* Collects all the possible targets for the [type] and the given [pokemon].
*
* @param pokemon The [Pokemon] being queried.
* @return A set containing all their legal abilities associated with [type], can be empty.
*/
fun queryPossible(pokemon: Pokemon): Set<AbilityTemplate>
/**
* Attempts to update the ability of the given [pokemon].
*
* @param pokemon The [Pokemon] attempting to change an ability.
* @return If the operation was successful.
*/
fun performChange(pokemon: Pokemon): Boolean
/**
* Checks if the current [PotentialAbilityType] of a [Pokemon.ability] is possible to swap from with this.
*
* @param type The [PotentialAbilityType] or null if the ability is forced and/or illegal.
* @return If the operation can be performed.
*/
fun canChangeFrom(type: PotentialAbilityType<*>?): Boolean
companion object {
/**
* An implementation of [AbilityChanger] for [CommonAbility].
*
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 2 common abilities.
*/
@JvmStatic
val COMMON_ABILITY: AbilityChanger<CommonAbility> = AbilityTypeChanger(CommonAbilityType) { other -> other == CommonAbilityType }
/**
* An implementation of [AbilityChanger] for [HiddenAbility].
*
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 1 hidden ability.
*/
@JvmStatic
val HIDDEN_ABILITY: AbilityChanger<HiddenAbility> = AbilityTypeChanger(HiddenAbilityType) { other -> other == CommonAbilityType || other == HiddenAbilityType }
}
}
@@ -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.api.molang
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
/**
* An object that can be given a [MoLangRuntime] to produce a single [MoValue]. This abstracts
* the use of simple and complex [Expression]s as MoLang can be a single line or multiple.
*
* @author Hiroku
* @since October 22nd, 2023
*/
interface ExpressionLike {
override fun toString(): String
/** Produces a [MoValue] for a [MoLangRuntime] to supply an environment. */
fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue> = emptyMap()): MoValue
fun getString(): String = toString()
fun resolveDouble(runtime: MoLangRuntime) = resolve(runtime).asDouble()
fun resolveFloat(runtime: MoLangRuntime) = resolveDouble(runtime).toFloat()
fun resolveString(runtime: MoLangRuntime) = resolve(runtime).asString()
fun resolveInt(runtime: MoLangRuntime) = resolveDouble(runtime).toInt()
fun resolveBoolean(runtime: MoLangRuntime) = resolveDouble(runtime) == 1.0
fun resolveObject(runtime: MoLangRuntime) = resolve(runtime) as ObjectValue<*>
}
@@ -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.api.molang
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.util.getString
import com.cobblemon.mod.common.util.resolve
/**
* An [ExpressionLike] that produces MoValues by evaluating a series of [Expression]s.
*
* @author Hiroku
* @since October 22nd, 2023
*/
class ListExpression(val exprs: List<Expression>): ExpressionLike {
override fun toString() = exprs.joinToString("\n") { it.getString().let { if (it.endsWith(";")) it else "$it;" } }
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>) = exprs.resolve(runtime, context)
}
Loaded 100 of 7803 files, more files were not shown because too many files have changed in this diff. Show more