Compare commits

..
Author SHA1 Message Date
Licious 6dcee2b8f3 Port PokemonBehaviour to Codecs 2023-10-15 15:09:58 +01:00
Licious 224c3faa4c Port Evolution stuff to codecs, rework RegistryLikeCondition to accept any registry type without implementation need. 2023-10-15 14:06:17 +01:00
Licious c42a2a6933 Merge branch 'main' into custom-type-support
# Conflicts:
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonImplementation.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/pokemon/PokemonProperties.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/api/types/ElementalTypes.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/client/gui/battle/subscreen/BattleMoveSelection.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/entity/pokemon/PokemonEntity.kt
#	common/src/main/resources/assets/cobblemon/showdown.zip
#	fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt
#	forge/src/main/kotlin/com/cobblemon/mod/forge/CobblemonForge.kt
2023-10-13 15:57:18 +01:00
Licious 40af1f0bdf More stuff n things. 2023-10-08 18:36:37 +01:00
Licious bb8dffdf50 More work towards species. 2023-09-24 11:08:41 +01:00
Licious 952fdd8541 Add SpeciesForm 2023-09-22 23:22:00 +01:00
Licious c30789cea4 Bye bye species male ratio. 2023-09-22 23:08:37 +01:00
Licious 0ada2265ff Spacing annoyed me 2023-09-22 23:08:02 +01:00
Licious 9aacff4051 Add GenderSelector 2023-09-22 23:04:56 +01:00
Licious 3b72b558f6 StatMap & EvMap 2023-09-22 22:40:48 +01:00
Licious ba0d7299ef Bunch of random stuff, this is no longer just custom types. 2023-09-22 21:18:33 +01:00
Licious f0ef34f435 Fix loading of type data. 2023-09-21 17:09:55 +01:00
Licious 646ed14146 Implement Forge custom registry creation. 2023-09-21 15:55:10 +01:00
Licious e8d8499462 Update outdated data format on type assets. 2023-09-21 14:03:52 +01:00
Licious 7656d1e0d8 Boy that's a lot of work 2023-09-21 13:59:28 +01:00
Licious f6d298f228 Correct hidden power stat data to use Cobblemon IDs instead of Showdown. 2023-09-20 12:47:55 +01:00
Licious 44a2f9e859 Migrate types to data. 2023-09-20 12:07:09 +01:00
5511 changed files with 26510 additions and 187043 deletions
-9
View File
@@ -33,12 +33,3 @@ common/src/main/resources/assets/cobblemon/showdown
# Generated files
*/generated/resources/*
/fabric/src/generated/resources/cobblemon-common.accesswidener
/.ignored/
# Logs
common/logs
fabric/logs
forge/logs
# 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
+78 -332
View File
@@ -1,287 +1,37 @@
# Changelog
## [1.5.0](#1-5-0)
### Additions
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
- Added the Data Monitor, Fossil Compartment, and Restoration Tank. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
- Added 3 variants of Tumblestones, 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 Original Trainer functionality. 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.
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
- Added a Display Case block! Use it to display your archaeological findings, or other items.
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
- Added a Pokémon-themed armor trim, obtained from ruin structures.
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
- Added effects for many Poké Balls when sending out Pokémon or capturing.
- 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 for more complicated animations.
- Added the EV Boosting Feathers.
- Added Type Gems.
- Added various new tags for searchability and better compatibility.
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch), these have no acquisition method for now and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
- Added Gilded Chests, available in all Apricorn colors.
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
- Added 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. Who knows what might happen if it fills up?
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
### Changes
- Pokémon now transition more smoothly between different poses.
- 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.
- You can now punch grown apricorns to harvest them.
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
- Updated movesets to add Gen 9 DLC moves.
- 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 specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
### Fixes
- Re-added the recipe for the Iron Vitamin.
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
- Fixed Exeggcute not being able to evolve.
- Fixed battle lang for Poison Touch Ability
- Fixed Cubone not being able to evolve into Alolan Marowak.
- Fixed Squawkabilly forms not being recognized.
- Fixed the bounce animation for Poké Balls being delayed by like, a full second.
- 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 look away when it's meant to close.
- Adds a translation string name to the Empty Pokeball entity.
- Fixed very many issues with Bedrock particle effects.
- Fixed Arbok patterns not being as specific in spawning as they were intended.
- Fixed Pokémon not avoiding danger at all when pathfinding.
- Fixed Sobble line not being able to swim or breathe underwater.
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
- Fixed an issue that allowed Pokemon to spawn on rails.
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
## [1.?.?]()
### Developer
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks.
- Added dialogue API and data registry.
- 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 spawning API capable of non-entity spawning
- Made PokemonProperties.parse more interoperable with Java.
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
- 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 to 2 regular abilities and 1 hidden.
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
- Various breaking changes have been made to ElementalTypes, Moves and other registries, Cobblemon has migrated to make use of proper Minecraft registries.
- DamageCategory is now an Enum.
- Gender has been moved to an API package.
### 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.
## [1.4.1 (December 23rd, 2023)](#1-4-1)
- Pokémon types can now be created via datapacks. Data path is ``your_mod_namespace/cobblemon/elemental_types/path_to_your_file``.
- Custom moves are now possible via datapacks, these require JavaScript/TypeScript programming knowledge. Data path is ``your_mod_namespace/cobblemon/moves/path_to_your_file``.
- Pokémon species data path has been changed to ``your_mod_namespace/cobblemon/species/path_to_your_file``.
## [1.4.0](#1-4-0)
### 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.
- 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.
- 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.
- 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.
- 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.
### 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.
- 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
- 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.
- 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.
- 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 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.
- 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.
- Fixed potion brewing recipes not showing up JEI and similar mods on the Forge version.
- 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 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)
### 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).
- Added trading between players. Press R while looking at another player and you'll figure the rest out.
- Added mints for changing Pokémon stats. These are most commonly found at high altitudes.
- Added [Revival Herbs](https://wiki.cobblemon.com/index.php/Revival_Herb), with pep-up flowers when fully grown, growing in lush caves.
- Added [Medicinal Leeks](https://wiki.cobblemon.com/index.php/Medicinal_Leek), growing on the surface of rivers and ponds. It is a potion ingredient and can be cooked as food!.
- Added [Big Roots](https://wiki.cobblemon.com/index.php/Big_Root), generating from cave ceiling dirt which sometimes spread as energy roots.
- Added [69 Berry Trees](https://wiki.cobblemon.com/index.php/Berry_Tree) and [Berries](https://wiki.cobblemon.com/index.php/Berry). Some are found in village farms, some from planting different berries close to each other.
- Added mulches: Mulch Base, Growth Mulch, Surprise Mulch, Coarse Mulch, Humid Mulch, Rich Mulch, Loamy Mulch, Peat Mulch, and Sandy Mulch
- Added [Vivichokes](https://wiki.cobblemon.com/index.php/Vivichoke), obtainable from wandering villager trades and some loot chests.
- Added nicknaming.
- Added mints, found on mountains.
- Added revival herbs, with pep-up flowers if fully grown, growing in lush caves.
- Added medicinal leeks, growing on the surface of rivers and ponds. It is a potion ingredient!
- Added big roots, generating from cave ceiling dirt and sometimes spreading into energy roots.
- Added trading between players. Press R while looking at another player, you'll figure it out.
- Added pasture blocks, used to let your PC Pokémon roam around your base.
- Added 69 berry trees. Some are found in village farms, some from planting different berries close to each other.
- Added medicine brewing using medicinal leeks and berries in brewing stands.
- Added Pokémon cries when in battles and being sent out.
- Added medicinal items: Berry Juice, Heal Powder, Remedy, Fine Remedy, Superb Remedy, Revive, Max Revive, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Full Heal, Antidote, Awakening, Burn Heal, Ice Heal, and Paralyze Heal.
- Added battle items: X Attack, X Defence, X Sp.Atk, X Sp.Def, X Speed, Dire Hit, and Guard Spec.
- Added EV items: Power Anklet, Power Band, Power Belt, Power Bracelet, Power Lens, Power Weight.
- Added food items: Roasted Leek, Leek and Potato Stew, Braised Vivichoke, and Vivichoke Dip
- Added evolution items: Auspicious Armor and Malicious Armor, which can be used to evolve Charcadet into Armarouge or Ceruledge respectively.
- Added (mostly brewing) recipes for HP Up, Protein, Iron, Calcium, Zinc, Carbos, PP Up, PP Max, and Medicinal Leek to Magenta Dye.
- Added held items: Bright Powder, Destiny Knot
- Added AI for Nosepass to point towards world spawn when idle. We just think it's neat.
- Added shoulder mounting for Mimikyu.
- Added support for scale in animations.
- Added support for jump keyframes (i.e. pre and post keyframes)
- Added AI for Nosepass to point towards world spawn when idle.
- Added structure spawn conditions
- Added recipes for Berry Juice, Heal Powder, Remedy, Fine Remedy, Superb Remedy, Revive, Max Revive, HP Up, Protein, Iron, Calcium, Zinc, Carbos, PP Up, PP Max, Pasture, Medicinal Leek to Magenta Dye, Roasted Leek, Leek and Potato Stew, Braised Vivichoke, Vivichoke Dip, Mulch Base, Growth Mulch, Surprise Mulch, Coarse Mulch, Humid Mulch, Rich Mulch, Loamy Mulch, Peat Mulch, Sandy Mulch, X Attack, X Defense, X Special Attack, X Special Defense, X Speed, X Accuracy, Dire Hit, Guard Spec, Power Anklet, Power Band, Power Belt, Power Bracelet, Power Lens, Power Weight, Bright Powder, Destiny Knot
- Added a shoulder mount for Mimikyu
- Added Advancement trigger for defeating Pokémon and collecting varieties of Pokémon.
- Added sleep animations to Arcanine, Jigglypuff, Wigglytuff, Vulpix and Ninetales.
- Added flying placeholder animations to Pidgey, Pidgeotto, Pidgeot, Golbat, Crobat, Scyther, Scizor, Zapdos, Moltres, Articuno, Dragonite, Rowlet, Dartrix, and Decidueye.
- Added loot to various vanilla chest loot tables (Link Cable in Ancient Cities, Woodland Mansions, End Cities, and Igloos, Vivichoke Seeds in Jungle Temples, Dungeons, and Plains, Savanna, Snowy, and Taiga Villages, and all 7 Apricorn Sprouts in Desert, Plains, Savanna, Snowy, and Taiga Villages, as well as the Bonus Chest, which can also have 5 of the basic Poké Ball types)
- Added a `doShinyStarters` gamerule to make it quick and easy to be offered shiny starters.
- Added a `doPokemonLoot` gamerule to toggle Pokémon dropping items/exp on death.
- Added ability activation announcement when in battle.
- Added animations for Wailord and made it BIGGER.
- Added Cherry Torterra variant.
- Added 2 new face spots for Spinda. The number of unique Spindas increases...
- Added Forretress Shulker variant.
- Added the `/teststore <player> <store> <properties>` command allowing command block/mcfunction users to query a party, PC or both for Pokémon matching specific properties and returning the match count, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.teststore` if a permission mod is present.
- Added the `/querylearnset <player> <slot> <move>` command allowing command block/mcfunction users to query a party slot and check if the Pokémon can learn a specific move returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.querylearnset` if a permission mod is present.
- Added the `/testpcslot <player> <slot> <properties>` command allowing command block/mcfunction users to query a pc slot and check if the Pokémon matches specific properties returning a 1 if yes otherwise 0, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.testpcslot` if a permission mod is present.
@@ -289,6 +39,18 @@ Thank you so much to all of our community translators that bring the mod to the
- Added the `/clearparty <player>` command for emptying a player's party.
- Added the `/clearpc <player>` command for emptying a player's PC.
- Added the `/pokemonrestart <reset_starters>` and the `/pokemonrestartother <player> <reset_starters>` command allowing command block/mcfunction users to reset a players Pokémon data.
- Added support for "isBattle" and "isTouchingWater" properties on resource pack Pokémon poses. This allows your custom Pokémon to be posed differently when in battle.
- Added support for "isVisible" on a transformed part on resource pack Pokémon poses. This allows your custom Pokémon to have bones disappear in specific poses, such as hiding Greninja's throwing star when not in a battle pose.
- Added a "doShinyStarters" gamerule
- Added the `doPokemonLoot` gamerule to toggle Pokémon dropping items/exp on death.
- Added support for battle music. Sounds can be added to the ``battle.pvp.default`` and ``battle.pvw.default`` sound events.
- Added ability activation announcement when in battle.
- Added Auspicious Armor and Malicious Armor, which can be used to evolve Charcadet into Armarouge or Ceruledge respectively.
- Added animations for Wailord.
- Added Cherry Torterra variant.
- Added 2 new face spots for Spinda.
- Added Forretress Shulker variant.
- Added 'enabled' optional property on model layers, allowing later variations to disable previously-defined layers. See [this issue](https://gitlab.com/cable-mc/cobblemon/-/issues/335) for how this looks.
### Pokémon Added
#### Gen 2
@@ -506,36 +268,39 @@ Thank you so much to all of our community translators that bring the mod to the
- Clodsire
### Changes
- Removed the existing shoulder effects from Pokémon until we have more balanced versions of them (they're too powerful!)
- Updated models and textures of Weedle, Dwebble and Crustle, Spiritomb, Koffing and Weezing, Kadabra and Alakazam, Emolga, Oshawott, Doduo and Dodrio, Dratini and Dragonair and Dragonite, Sneasel and Weavile, Gyarados, Hitmonlee and Hitmonchan, Chesnaught, Spinda, Mamoswine, Steelix, Misdreavus and Mismagius, Buneary and Lopunny, Golduck, Meowth and Persian, Fennekin and Braixen and Delphox, Snivy and Servine and Serperior, Ratatta and Raticate, Nidorina and Nidoqueen, Nidoran Male and Nidoking, Riolu and Lucario, Haunter and Gengar, Mankey and Primeape, Mew and Mewtwo, Arcanine, Magnemite and Magneton and Magnezone, Exeggcute and Exeggutor, Elekid and Electabuzz and Electivire, Pichu and Pikachu and Raichu, Wooper, Drowzee and Hypno, Aerodactyl, Spearow and Fearow, Lickitung and Lickilicky, Pidgey and Pidgeotto and Pidgeot, Scyther and Scizor and Kleavor, Popplio and Brionne and Primarina, Torchic and Combusken and Blaziken, Happiny and Chansey and Blissey.
- Updated animations for Steelix, Turtwig and Grotle and Torterra, Ponyta and Rapidash, Piplup and Prinplup and Empoleon, Drowzee and Hypno, Farfetch'd, Exeggcute and Exeggutor, Bidoof, Chimecho, Lickitung and Lickilicky, Popplio and Brionne, Luvdisc, Chimchar and Monferno and Infernape, Sobble and Drizzile and Inteleon, Greninja, Heatmor, Aerodactyl, Ditto, Lotad and Lombre and Ludicolo, Pumpkaboo and Gourgeist.
- Updated model and textures of Spiritomb, Koffing, Weezing, Kadabra, Alakazam, Emolga, Oshawott, Doduo, Dodrio, Dratini, Dragonair, Dragonite, Sneasel, Weavile, Gyarados, Hitmonlee, Hitmonchan, Chesnaught, Spinda, Mamoswine, Steelix, Midreavus, Mismagius, Buneary, Lopunny, Golduck, Meowth, Persian, Fennekin, Braixen, Delphox, Snivy, Servine, Serperior, Ratatta, Raticate, Nidorina, Nidoqueen, NidoranM, Nidoking, Riolu, Lucario, Haunter, Mankey, Primeape, Mew, Mewtwo, Arcanine, Magnemite, Magneton, Magnezone, Exeggcute, Exeggutor, Elekid, Electabuzz, Electivire, Pichu, Pikachu, Raichu, Gengar, Wooper, Drowzee, Hypno, Aerodactyl, Spearow, Fearow, Lickitung, Pidgey, Pidgeotto, Pidgeot, Scyther, Scizor, Kleavor, Popplio, Brionne, Primarina, Torchic, Combusken, Blaziken, Aerodacyl, Scyther, Scizor, Kleavor, Lickitung, Lickilicky, Happiny, Chansey and Blissey.
- Updated animations for Steelix, Turtwig, Grotle, Torterra, Ponyta, Rapidash, Piplup, Prinplup, Empoleon, Drowzee, Hypno, Farfetch'd, Exeggcute, Exeggutor, Bidoof, Chimecho, Lickytung, Lickilicky, Popplio, Brionne, Luvdisc, Chimchar, Monferno, Infernape, Sobble, Drizzile, Inteleon, Greninja, Heatmor, Aerodactyl, Ditto, Lotad, Lombre, Ludicolo, Pumpkaboo, Gourgeist.
- Updated sprites for EV medicines, the rare candy, and the apricorn door item.
- Updated textures for apricorn doors and all the evolution stone ores.
- Ponyta and Rapidash now have animated textures; they look insane.
- Updated Apricorn Leaves color.
- Wild Pokémon now heal if you are defeated by them or flee from them.
- Doubled the default time between ambient Pokémon cries (they have cries if you're using a resource pack to add them)
- Moved spawn attempts per tick to a config option (ticksBetweenSpawnAttempts)
- PCs can now be waterlogged
- Starter selection prompt now appears as a tutorial-esque toast instead of plain text
- Cobblemon items can now all have their own tooltips via resourcepacks, to add a tooltip simply add a lang entry like "item.cobblemon.{item_id}.tooltip", if you want to add multiple tooltip lines you can do so with "item.cobblemon.{item_id}.tooltip_1" and upwards.
- Updated texture of Weedle.
- Updated shiny texture of Dwebble and Crustle.
- Reorganised the advancements recipes folder
- Pokéedit command now supports IVs and EVs.
- Reorganised creative categories
- Pokémon can now wander into non-solid blocks such as foliage
- Thrown Poké Balls now despawn after 30 seconds so that they don't fly forever.
- Pokéballs now despawn after 30 seconds
- Dive Balls will now have the same motion speed underwater as if they were thrown in the air.
- Hardcoded potion shoulder effects have been removed. You can now use any potion vanilla or otherwise with the parameters you'd like, for more information see the [Datapack & Resourcepack Creators](#datapack-&-resourcepack-creators) section.
- Clicking categories of the Stat subsection or the party reorder button in the Summary screen will now produce a click sound.
- Hardcoded potion shoulder effects have been removed, you can now use any potion vanilla or otherwise with the parameters you'd like, for more information see the [Datapack & Resourcepack Creators](#datapack-&-resourcepack-creators) section.
- Clicking categories of the Stat sub-section or the party reorder button in the Summary screen will now produce a click sound.
- Updated PC Recipe.
- Improved Pokémon AI and movement.
- Friendship will slowly increase when Pokémon are shoulder-mounted.
- Master Balls are now unable to be burned when dropped into fire/lava. They're made from stronger stuff.
- Master balls are now unable to be burned when dropped into fire/lava.
- Pokémon will appear red when hurt, like regular entities, except when they're fainting.
- Ponyta and Rapidash now have animated textures.
- Pokémon's air meter no longer depletes while battling underwater.
- Sleeping partially restores PP of Pokémon
- Item interaction evolutions and held item requirements now support NBT by creating an object JSON containing the key ``item`` for what used to be the existing condition support and a ``nbt`` key for the NBT format, this is the string [format](https://minecraft.fandom.com/wiki/NBT_format) expected in commands. Existing data does not need to be updated.
- Shoulder mounts now match the shoulder position a bit more accurately when sneaking.
- Poison Heal will now cause poisoned Pokémon to heal outside of battle.
- Updated Poké Ball, PC, UI, evolution and Healing Machine sounds.
- Updated Pokéball, PC, UI, evolution and Healing Machine sounds.
### Added cries to the following Pokémon:
- All starters and their evolutions
@@ -605,48 +370,48 @@ Thank you so much to all of our community translators that bring the mod to the
- Tatsugiri
### Fixes
- Fixed spawning moon phase dependent Pokémon only when the moon phase is wrong (that's a funny woopsy)
- Fixed spawning moon phase dependent Pokémon only when the moon phase is wrong
- Fixed large Pokémon spawning partially inside walls where they suffocate.
- Fixed custom Pokémon in your party or PC not being removed when the addon is removed, causing major issues.
- Fixed messages for entry hazards, screens, weather, damage, healing, Tailwind, Perish Song, Destiny Bond, Shed Skin, Uproar, Forewarn, Disguise, Arena Trap, Yawn, Curse, Clamp, Whirlpool, Liquid Ooze, Miracle Eye, Safeguard, Magic Bounce, Lock On, Focus Energy, Confusion, and more.
- Fixed Porygon not evolving with an Upgrade.
- Fixed super sized Pumpkaboo not having any moves.
- Fixed Infernape look animation.
- Fixed Garchomp T-posing while swimming which was very funny.
- Fixed a bug that caused sleeping Pokémon to stay asleep. Forever. The years passing them by as they dream of a world without hate...
- Fixed a bug that would freeze a battle when a Pokémon gets trapped by an ability, making the trap abilities even scarier and trap-like than they were before.
- Fixed Garchomp t-posing while swimming.
- Fixed a bug that caused sleeping Pokémon to stay asleep.
- Fixed a bug that would freeze a battle when a Pokémon gets trapped due to an ability.
- Fixed the Poké Ball close animation canceling whenever colliding with a block.
- Fixed faint animations not working properly in add-ons.
- Fixed lighting and Pokémon label issues when a Pokémon item frame is nearby.
- Fixed Pokémon being able to spawn outside the world border as a tease.
- Fixed deepslate water stone ore items looking like deepslate fire stone ores. Huh?
- Fixed a bunch of client-side logging errors when Pokémon are shoulder mounted. You didn't notice? Good.
- Fixed deepslate water stone ore items looking like deepslate fire stone ores.
- Fixed a bunch of client-side logging errors when Pokémon are shoulder mounted.
- Fixed a crash when wild Pokémon have to struggle under specific circumstances.
- Fixed uncolored pixels on Yanma's shiny texture.
- Fixed apricorn tree leaves looking gross on the Fast graphics mode.
- Fixed apricorn tree leaves looking gross on Fast graphics mode.
- Fixed hoes not breaking apricorn tree leaves any faster.
- Fixed Shiftry's PC model position.
- Fixed the /pc command not playing the opening sound.
- Fixed Shedinja not being able to recover naturally.
- Fixed different forms of Pokémon not being able to appear as different sizes.
- Fixed the Healing Machine soft locking you from using others when removed by non-players.
- Fixed animations being sped up when using the Replay Mod.
- Fixed particle animations not running when a Pokémon is off-screen.
- Fixed Pokémon variants and layers not rendering correctly when shouldered and playing on a dedicated server, existing shoulders affected will need to be retrieved and shouldered again.
- Fixed shoulder effects not staying applied through situations that remove potion effects such as drinking milk.
- Fixed Shedinja not being able to recover naturally.
- Fixed Shedinja evolving to use the consumed Poké Ball and removed the held item to prevent dupes.
- Fixed Shedinja healing above 1 HP.
- Fixed Shedinja, basically.
- Shoulder effects will now stay applied through situations that remove potion effects such as drinking milk.
- Fixed Shedinja evolving to use the consumed PokéBall and removed the held item.
- Fixed non-existent species in spawn pool file causing random species to spawn.
- Fixed shearing Pokémon dropping 0-2 wool instead of 1-3.
- Fixed some alignment issues in the stat hexagon of the summary menu. OCD people rejoice.
- Fixed some alignment issues in the stat hexagon of the summary menu.
- Fixed capture calculations not applying ball bonuses entirely correctly.
- Fixed Shedinja healing above 1 HP.
- Fixed battles soft-locking when consecutive Pokémon faint on switch-in.
- Fixed timing and color of battle window messages.
- Fixed players being able to trade, battle and let out their Pokémon while in spectator mode.
- Fixed Galarian Yamask not being able to evolve and by proxy the ``damage_taken`` evolution requirement.
- Fixed Bisharp not being able to evolve and by proxy the ``defeat`` evolution requirement.
- Fixed White-Striped Basculin not being able to evolve because of a broken ``recoil`` evolution requirement.
- Fixed Primeape, Qwilfish and Stantler not being able to evolve because of a broken ``use_move`` evolution requirement.
- Fixed Bramblin, Pawmo, and Rellor not being able to evolve because of a broken ``blocks_traveled`` evolution requirement.
- Fixed White-Striped Basculin not being able to evolve and by proxy the ``recoil`` evolution requirement.
- Fixed Primeape, Qwilfish and Stantler not being able to evolve and by proxy the ``use_move`` evolution requirement.
- Fixed Bramblin, Pawmo, and Rellor not being able to evolve and by proxy the ``blocks_traveled`` evolution requirement.
- Fixed displayName property in spawn files not doing what it's meant to do.
- Fixed Pokémon not sleeping in the wild like we wanted them to.
@@ -659,12 +424,9 @@ Thank you so much to all of our community translators that bring the mod to the
- 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 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.
- Pokémon now have ``teraType``, ``dmaxLevel``, and ``gmaxFactor`` properties. Gimmicks can be used during battle by adding the respective identifiers to ``keyItems`` in PlayerData: ``key_stone``, ``z_ring``, ``dynamax_band``, and ``tera_orb``. Dynamax is only supported in Gen 8 battles. Mega Evolution and Z-Power require custom held items to be added (e.g. an item with the path ``gengarite`` will allow Gengar to Mega Evolve). Currently custom Z-Crystals and Mega Stones are not supported.
### Datapack & Resourcepack Creators
- All potion related shoulder effects have had their IDs changed. They now all share the same type being `potion_effect` and use the vanilla Potion data [parameters](https://minecraft.fandom.com/wiki/Potion#Item_data). For example, here is the converted Pidgey asset:
- All potion related shoulder effects have had their IDs changed, they now all share the same type being `potion_effect` and use the vanilla Potion data [parameters](https://minecraft.fandom.com/wiki/Potion#Item_data), take for example the default Pidgey asset:
- ```json
{
"type": "potion_effect",
@@ -676,22 +438,6 @@ Thank you so much to all of our community translators that bring the mod to the
}
```
- Renamed the ``walked_steps`` evolution requirement to ``blocks_traveled``.
- Added support for scale in animations.
- Added support for jump keyframes (i.e. pre and post keyframes)
- Added structure spawning conditions
- Added Advancement trigger for defeating Pokémon and collecting varieties of Pokémon.
- Added support for "isBattle" and "isTouchingWater" properties on resource pack Pokémon poses. This allows your custom Pokémon to be posed differently when in battle.
- Added support for "isVisible" on a transformed part on resource pack Pokémon poses. This allows your custom Pokémon to have bones disappear in specific poses, such as hiding Greninja's throwing star when not in a battle pose.
- Added support for battle music. Sounds can be added to the ``battle.pvp.default`` and ``battle.pvw.default`` sound events.
- Added 'enabled' optional property on model layers, allowing later variations to disable previously-defined layers. See [this issue](https://gitlab.com/cable-mc/cobblemon/-/issues/335) for how this looks.
- Cobblemon items can now all have their own tooltips via resourcepacks. To add a tooltip, add a lang entry like "item.cobblemon.{item_id}.tooltip". If you want to add multiple tooltip lines you can do so with "item.cobblemon.{item_id}.tooltip_1" and upwards.
- Item interaction evolutions and held item requirements now support NBT by creating an object JSON containing the key ``item`` for what used to be the existing condition support and a ``nbt`` key for the NBT format, this is the string [format](https://minecraft.fandom.com/wiki/NBT_format) expected in commands. Existing data does not need to be updated.
- Fixed faint animations not working properly in add-ons.
- Fixed non-existent species in spawn pool files causing random species to spawn.
### Localization
- Added partial translations for Dutch, Polish, Swedish, Hungarian, Czech, Cyprus Greek, and even Esperanto.
- Updated translation for French and Canadian French, Simplified Chinese, Japanese, Korean, Spanish and Mexican Spanish, Pirate English, German, Thai, Turkish, Portuguese and Brazilian Portuguese, Ukrainian, and Russian.
## [1.3.1 (March 31st, 2023)](#1-3-1)
@@ -705,7 +451,7 @@ Thank you so much to all of our community translators that bring the mod to the
- Add lava surface spawn preset.
- Added an ``any`` evolution requirement allowing you to define ``possibilities`` of other evolution requirements, for example, this allows you to create an evolution that requires the Pokémon to be shiny or a female.
- Added the `/spawnpokemonfrompool [amount]` or `/forcespawn [amount]` command to spawn Pokémon(s) in the surrounding area using the natural spawn rates/pool of that area, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.spawnpokemon` if a permission mod is present. On a successful execution of the command, the amount of Pokémon spawned will be the output.
- Added the `/pokebox` and `/pokeboxall` commands to move Pokémon(s) to the PC from a Player's party, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pokebox` if a permission mod is present. On a successful execution of the command the output will be the number of pokemon moved to the Player's PC.
- Added the `/pokebox` and `/pokeboxall` commands to move Pokemon(s) to the PC from a Player's party, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pokebox` if a permission mod is present. On a successful execution of the command the output will be the number of pokemon moved to the Player's PC.
- Added the `/pc` command which opens up the PC UI the same way interacting with the block would, this will be a cheat command in the Minecraft permission system or use the permission `cobblemon.command.pc` if a permission mod is present.
### Changes
@@ -1037,20 +783,20 @@ Thank you so much to all of our community translators that bring the mod to the
- Fixed spawning in several biome tag categories.
- Fixed resource pack support for Pokémon models and textures.
- **Model Fixes**
- Fixed Paras and Nidoqueen looking very weird.
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
- Fixed Mankey's feet being buried in the ground.
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
- Fixed Paras and Nidoqueen looking very weird.
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
- Fixed Mankey's feet being buried in the ground.
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
- **Battle Fixes**
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
- Fixed Magnitude battle messages.
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
- Fixed Magnitude battle messages.
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
### Localization
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
## [1.0.0 (November 12th, 2022)](#1-0-0)
- Initial release.
- Initial release.
+2 -3
View File
@@ -1,7 +1,6 @@
plugins {
base
id("cobblemon.root-conventions")
id ("net.nemerosa.versioning") version "2.8.2"
}
group = "com.cobblemon.mod"
@@ -9,5 +8,5 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
if (isSnapshot) {
version = "$version-${versioning.info.branch}-${versioning.info.build}-SNAPSHOT"
}
version = "$version-SNAPSHOT"
}
+1 -4
View File
@@ -19,7 +19,6 @@ architectury {
repositories {
maven(url = "${rootProject.projectDir}/deps")
maven(url = "https://api.modrinth.com/maven")
mavenLocal()
}
@@ -29,11 +28,9 @@ dependencies {
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)
modCompileOnly(libs.flywheelFabric)
modApi(libs.molang)
compileOnlyApi(libs.jeiApi)
modCompileOnly(libs.adornFabric)
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
// For Showdown
modCompileOnly(libs.graal)
-1
View File
@@ -1 +0,0 @@
[19:57:25] [Test worker/INFO]: Booting LaxPermissionValidator, permissions will be checked using Minecrafts permission level system, see https://minecraft.fandom.com/wiki/Permission_level
@@ -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,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);
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonBlocks;
import com.cobblemon.mod.common.block.PastureBlock;
import net.minecraft.block.BlockState;
import net.minecraft.block.FenceBlock;
import net.minecraft.block.HorizontalFacingBlock;
import net.minecraft.util.math.Direction;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = FenceBlock.class)
public abstract class FenceBlockMixin {
// This could be done with a modify variable but it just doesn't seem to want to work, very crude unfinished explanation I had on Fabric discord was
// "boolean is a primitive, it isnt passed by reference but by value and you have your own object references anyway so assigning a new object to non-primitive references (variables) wont modify it after your mixin returns
//(you cant modify a random argument that mixin passes you that way, target the boolean not the FenceBlock)"
// However the issue is the only way to get all the params which we need is by passing in the entire method reference which enforces the return type.
@Redirect(method = "getStateForNeighborUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/FenceBlock;canConnect(Lnet/minecraft/block/BlockState;ZLnet/minecraft/util/math/Direction;)Z"))
private boolean cobblemon$getStateForNeighborUpdate(FenceBlock instance, BlockState state, boolean neighborIsFullSquare, Direction dir) {
return instance.canConnect(state, neighborIsFullSquare, dir) || this.cobblemon$canConnect(state, dir);
}
@Redirect(method = "getPlacementState", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/FenceBlock;canConnect(Lnet/minecraft/block/BlockState;ZLnet/minecraft/util/math/Direction;)Z"))
private boolean cobblemon$getPlacementState(FenceBlock instance, BlockState state, boolean neighborIsFullSquare, Direction dir) {
return instance.canConnect(state, neighborIsFullSquare, dir) || this.cobblemon$canConnect(state, dir);
}
private boolean cobblemon$canConnect(BlockState state, Direction dir) {
if (state.isOf(CobblemonBlocks.PASTURE) && state.get(PastureBlock.Companion.getPART()) == PastureBlock.PasturePart.BOTTOM) {
final Direction pastureFacing = state.get(HorizontalFacingBlock.FACING);
return dir == pastureFacing.rotateYClockwise() || dir == pastureFacing.rotateYCounterclockwise();
}
return false;
}
}
@@ -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;
@@ -6,9 +6,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.fabric.mixin;
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.fabric.brewing.CobblemonFabricBreweryRegistry;
import com.cobblemon.mod.common.brewing.BrewingRecipes;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.BrewingStandScreenHandler;
import org.spongepowered.asm.mixin.Mixin;
@@ -18,14 +18,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(BrewingStandScreenHandler.PotionSlot.class)
public class PotionSlotMixin {
@Inject(method = "matches", at = @At("RETURN"), cancellable = true)
private static void cobblemon$matches(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (cir.getReturnValue()) {
return;
@Inject(
method = "matches",
at = @At(value = "HEAD"),
cancellable = true
)
private static void matchesBrewable(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
if (BrewingRecipes.brewableItems.contains(stack.getItem())) {
cir.setReturnValue(true);
}
cir.setReturnValue(CobblemonFabricBreweryRegistry.INSTANCE.isValidPotionSlot(stack));
}
}
@@ -0,0 +1,44 @@
/*
* 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.spawning.mixins.CachedOnlyChunkAccessor;
import com.mojang.datafixers.util.Either;
import net.minecraft.server.world.ChunkHolder;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkManager;
import net.minecraft.world.chunk.ChunkStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.concurrent.CompletableFuture;
@Mixin(ServerChunkManager.class)
public abstract class ServerChunkManagerMixin extends ChunkManager implements CachedOnlyChunkAccessor {
@Shadow @Nullable protected abstract ChunkHolder getChunkHolder(long pos);
@Override
public Chunk cobblemon$request(int x, int z, @NotNull ChunkStatus status) {
long l = ChunkPos.toLong(x, z);
ChunkHolder holder = getChunkHolder(l);
if (holder != null) {
CompletableFuture<Either<Chunk, ChunkHolder.Unloaded>> future = holder.getFutureFor(status);
if (future.isDone()) {
return future.join().left().orElse(null);
}
}
return 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();
}
}
@@ -8,16 +8,15 @@
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.client.sound.MusicTracker;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(BoatEntity.class)
public interface BoatEntityAccessor {
@Mixin(MusicTracker.class)
public interface MusicTrackerAccessor {
@Accessor("timeUntilNextSong")
int timeUntilNextSong();
@Accessor
void setFallVelocity(double fallVelocity);
@Accessor
BoatEntity.Location getLocation();
@Accessor("timeUntilNextSong")
void setTimeUntilNextSong(int timeUntilNextSong);
}
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.invoker;
import net.minecraft.block.Block;
import org.spongepowered.asm.mixin.Mixin;
import net.minecraft.block.FireBlock;
import net.minecraft.block.Blocks;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(FireBlock.class)
public interface FireBlockInvoker {
@Invoker("registerFlammableBlock") void registerNewFlammableBlock(Block block, int burnChance, int spreadChance);
}
@@ -1,20 +0,0 @@
package com.cobblemon.mod.common.mixin.invoker;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.BlockSetType;
import net.minecraft.block.PressurePlateBlock;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.ScreenHandlerType.Factory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ScreenHandlerType.class)
public interface ScreenHandlerTypeInvoker {
@Invoker("<init>")
static <T extends ScreenHandler> ScreenHandlerType<T> cobblemon$create(Factory<T> factory, FeatureSet requiredFeatures) {
throw new UnsupportedOperationException();
}
}
@@ -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)
}
}
@@ -6,10 +6,11 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
@file:Suppress("unused")
package com.cobblemon.mod.common
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.SeasonResolver
import com.cobblemon.mod.common.api.data.DataProvider
@@ -19,11 +20,9 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
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.Vec3DataSerializer
@@ -32,17 +31,20 @@ import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalcula
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculators
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
import com.cobblemon.mod.common.api.pokemon.evolution.adapters.EvolutionRegistry
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
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.*
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.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.registry.CobblemonRegistryKeys
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.context.AreaContextResolver
@@ -55,13 +57,13 @@ 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.types.ElementalType
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
@@ -69,7 +71,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
@@ -83,7 +84,6 @@ 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.ServerTickHandler
import com.cobblemon.mod.common.item.CobblemonItem
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.permission.LaxPermissionValidator
@@ -94,12 +94,10 @@ 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.misc.GimmighoulStashHandler
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
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.DataKeys
@@ -131,7 +129,6 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.item.Items
import net.minecraft.item.NameTagItem
import net.minecraft.registry.RegistryKey
import net.minecraft.sound.SoundCategory
import net.minecraft.util.WorldSavePath
import net.minecraft.world.World
import org.apache.logging.log4j.LogManager
@@ -160,7 +157,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
@@ -170,6 +166,7 @@ object Cobblemon {
fun preInitialize(implementation: CobblemonImplementation) {
this.implementation = implementation
this.queueRegistryCreation()
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerBlocks()
@@ -197,6 +194,8 @@ object Cobblemon {
ShoulderEffectRegistry.register()
EvolutionRegistry.init()
DATA_SYNCHRONIZED.subscribe {
storage.onPlayerDataSync(it)
playerData.get(it).sendToPlayer(it)
@@ -232,9 +231,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() }
}
@@ -242,7 +238,6 @@ object Cobblemon {
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
@@ -258,7 +253,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,
@@ -273,15 +267,9 @@ object Cobblemon {
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) }
@@ -356,7 +344,7 @@ object Cobblemon {
// Ensure the config option is enabled and that the result was a ninjask and that shedinja exists
if (this.config.ninjaskCreatesShedinja && pokemon.species.resourceIdentifier == ninjaskIdentifier && PokemonSpecies.getByIdentifier(Pokemon.SHEDINJA) != null) {
val player = pokemon.getOwnerPlayer() ?: return@subscribe
if (player.isCreative || player.inventory.containsAny { it.item is PokeBallItem }) {
if (player.inventory.containsAny { it.item is PokeBallItem }) {
var pokeball = Items.AIR
player.inventory.combinedInventory.forEach {
it.forEach {
@@ -365,12 +353,7 @@ object Cobblemon {
}
}
}
if (!player.isCreative) {
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
}
if (pokeball == Items.AIR) {
pokeball = CobblemonItems.POKE_BALL
}
player.inventory.removeAmountIf(1) { it.item is PokeBallItem }
val properties = event.evolution.result.copy()
properties.species = Pokemon.SHEDINJA.toString()
val product = pokemon.clone()
@@ -378,7 +361,6 @@ object Cobblemon {
properties.apply(product)
product.caughtBall = (pokeball as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(product)
CobblemonCriteria.EVOLVE_POKEMON.trigger(player, EvolvePokemonContext(event.pokemon.preEvolution!!.species.resourceIdentifier, product.species.resourceIdentifier, playerData.get(player).advancementData.totalEvolvedCount))
}
}
}
@@ -390,12 +372,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? {
@@ -499,7 +478,10 @@ 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))
}
private fun queueRegistryCreation() {
this.implementation.createRegistry(CobblemonRegistryKeys.ELEMENTAL_TYPE, ElementalType.CODEC, ElementalType.NETWORK_CODEC)
}
}
@@ -1,21 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import net.minecraft.entity.ai.brain.Activity
object CobblemonActivities {
val activities = mutableListOf<Activity>()
val BATTLING_ACTIVITY = Activity("pokemon_battling")
fun register(activity: Activity): Activity {
activities.add(activity)
return activity
}
}
@@ -12,12 +12,6 @@ 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,57 +26,10 @@ 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
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.create(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
@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 TM_BLOCK: BlockEntityType<TMBlockEntity> = this.create("tm_block", BlockEntityType.Builder.create(::TMBlockEntity, CobblemonBlocks.TM_MACHINE).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,7 @@ 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
@@ -42,8 +33,6 @@ import net.minecraft.util.math.intprovider.UniformIntProvider
@Suppress("SameParameterValue", "HasPlatformType", "MemberVisibilityCanBePrivate", "unused")
object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<Block>>, Block>() {
override val registry: Registry<Block> = Registries.BLOCK
override val registryKey: RegistryKey<Registry<Block>> = RegistryKeys.BLOCK
@@ -58,8 +47,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")
@@ -107,33 +94,28 @@ 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))
// Tag was removed be sure to add it back when implemented
//val APRICORN_SIGN = queue("apricorn_sign") { StandingSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE) }
//val APRICORN_WALL_SIGN = queue("apricorn_wall_sign") { WallSignBlock(AbstractBlock.Settings.of(Material.WOOD).noCollission().strength(1.0f).sounds(BlockSoundGroup.WOOD).dropsLike(APRICORN_SIGN), APRICORN_WOOD_TYPE) }
@JvmField
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_WALL_SIGN = this.create("apricorn_wall_sign", CobblemonWallSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_SIGN), APRICORN_WOOD_TYPE))
@JvmField
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", CobblemonHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_WALL_HANGING_SIGN), APRICORN_WOOD_TYPE))
@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
@@ -152,66 +134,14 @@ 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(BlockSoundGroup.CROP)))
@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)
))
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
@@ -227,138 +157,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.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.COIN_POUCH_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",
@@ -385,55 +183,19 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
.luminance { if ((it.get(PCBlock.ON) as Boolean) && (it.get(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }
)
)
val TM_MACHINE = create(
"tm_machine",
TMBlock(
AbstractBlock.Settings.create()
.mapColor(MapColor.GREEN)
.sounds(BlockSoundGroup.METAL)
.pistonBehavior(PistonBehavior.BLOCK)
.nonOpaque()
.luminance { if (it.get(TMBlock.ON) as Boolean) 10 else 0 }
)
)
@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(BlockSoundGroup.CROP)))
@JvmField
val MODIFICATION_STATION = create(
"modification_station",
ModStationBlock(
AbstractBlock.Settings.create()
.sounds(BlockSoundGroup.WOOD)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.BROWN)
.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 BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).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 CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).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 PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).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 GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).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)))
@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(
@@ -456,67 +218,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
@JvmField
val NORMAL_TYPE_GEM_BLOCK = this.create("normal_type_gem_block", Block(AbstractBlock.Settings.copy(Blocks.AMETHYST_BLOCK)))
@JvmField
val NORMAL_TYPE_GEM = typeGem(
"normal_type_gem",
GrowableStoneBlock.STAGE_3,
7,
3,
null,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val LARGE_BUDDING_NORMAL_TYPE_GEM = typeGem(
"large_budding_normal_type_gem",
GrowableStoneBlock.STAGE_2,
5,
3,
NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val MEDIUM_BUDDING_NORMAL_TYPE_GEM = typeGem(
"medium_budding_normal_type_gem",
GrowableStoneBlock.STAGE_1,
4,
3,
LARGE_BUDDING_NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
@JvmField
val SMALL_BUDDING_NORMAL_TYPE_GEM = typeGem(
"small_budding_normal_type_gem",
GrowableStoneBlock.STAGE_0,
3,
4,
MEDIUM_BUDDING_NORMAL_TYPE_GEM,
NORMAL_TYPE_GEM_BLOCK
)
private fun typeGem(
name: String,
stage: Int,
height: Int,
xzOffset: Int,
nextStage: Block?,
baseBlock: Block
): TypeGemBlock {
return this.create(name, TypeGemBlock(
settings = AbstractBlock.Settings.create()
.pistonBehavior(PistonBehavior.DESTROY)
.nonOpaque()
.strength(1.5F)
.sounds(CobblemonSounds.TYPE_GEM_SOUNDS),
stage = stage,
height = height,
xzOffset = xzOffset,
nextStage = nextStage,
baseBlock = baseBlock
))
}
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
*
@@ -529,15 +230,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")
@@ -610,57 +302,24 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
val WIKI_BERRY = this.berryBlock("wiki")
val YACHE_BERRY = this.berryBlock("yache")
init {
/**
* Makes all blocks in array flammable by adding them to FireBlock's flammableRegistry.
* second value is burn chance and third value is spread chance
*/
arrayOf(
Triple(APRICORN_LOG, 5, 5),
Triple(STRIPPED_APRICORN_LOG, 5, 5),
Triple(APRICORN_WOOD, 5, 5),
Triple(STRIPPED_APRICORN_WOOD, 5, 5),
Triple(APRICORN_PLANKS, 5, 20),
Triple(APRICORN_LEAVES, 30, 60),
Triple(APRICORN_FENCE, 5, 20),
Triple(APRICORN_FENCE_GATE, 5, 20),
Triple(APRICORN_SLAB, 5, 20),
Triple(APRICORN_STAIRS, 5, 20)
).onEach{ data -> setFlammable(data.first, data.second, data.third) }
}
fun berries() = this.berries.toMap()
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
}
/**
* Calls helper method from Vanilla
* Helper method for creating logs
* copied over from Vanilla
*/
private fun log(name: String, arg: MapColor = MapColor.DIRT_BROWN, arg2: MapColor = MapColor.DIRT_BROWN): PillarBlock {
val block = BlocksInvoker.createLogBlock(arg, arg2)
return this.create(name, block)
}
/**
* Method uses generic E in order to keep the block as the same return type.
* If E is not a block then it will not be set as flammable.
* Calls Vanilla implementation of registering a flammable block.
* Mixins looks cursed but it is java's fault.
*/
private fun <E> setFlammable(block: E, burnChance: Int, spreadChance: Int): E {
if(block !is Block) return block
var fireBlock: FireBlock = Blocks.FIRE as FireBlock
//Cursed Mixin stuff
(fireBlock as FireBlockInvoker).registerNewFlammableBlock(block as Block, burnChance, spreadChance)
return block
}
private fun evolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)))
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)))
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common
import java.util.function.Supplier
import net.minecraft.block.Block
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.BlockEntityType
@@ -18,14 +19,11 @@ import net.minecraft.client.particle.ParticleFactory
import net.minecraft.client.particle.SpriteProvider
import net.minecraft.client.render.RenderLayer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.entity.EntityRendererFactory
import net.minecraft.client.render.entity.model.EntityModelLayer
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.item.Item
import net.minecraft.particle.ParticleEffect
import net.minecraft.particle.ParticleType
import java.util.function.Supplier
import net.minecraft.resource.SynchronousResourceReloader
interface CobblemonClientImplementation {
fun registerLayer(modelLayer: EntityModelLayer, supplier: Supplier<TexturedModelData>)
@@ -40,7 +38,5 @@ interface CobblemonClientImplementation {
fun registerBlockColors(provider: BlockColorProvider, vararg blocks: Block)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<out T>, factory: BlockEntityRendererFactory<T>)
fun <T : Entity> registerEntityRenderer(type: EntityType<out T>, factory: EntityRendererFactory<T>)
fun <T : BlockEntity> registerBlockEntityRenderer(type: BlockEntityType<T>, factory: BlockEntityRendererFactory<T>)
}
@@ -46,7 +46,5 @@ object CobblemonCommands {
ClearPartyCommand.register(dispatcher)
ClearPCCommand.register(dispatcher)
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
OpenDialogueCommand.register(dispatcher)
}
}
@@ -9,9 +9,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.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
@@ -48,33 +45,6 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
.build(EMPTY_POKEBALL_KEY.toString())
)
@JvmField
val BOAT_KEY = cobblemonResource("boat")
@JvmField
val BOAT: EntityType<CobblemonBoatEntity> = this.create(
BOAT_KEY.path,
EntityType.Builder.create(::CobblemonBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(BOAT_KEY.toString())
)
@JvmField
val CHEST_BOAT_KEY = cobblemonResource("chest_boat")
@JvmField
val CHEST_BOAT: EntityType<CobblemonChestBoatEntity> = this.create(
CHEST_BOAT_KEY.path,
EntityType.Builder.create(::CobblemonChestBoatEntity, SpawnGroup.MISC).setDimensions(1.375F, 0.5625F).maxTrackingRange(10)
.build(CHEST_BOAT_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())
)
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
consumer(POKEMON, PokemonEntity.createAttributes())
}
@@ -13,28 +13,27 @@ import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.mojang.brigadier.arguments.ArgumentType
import com.mojang.serialization.Codec
import kotlin.reflect.KClass
import net.minecraft.advancement.criterion.Criterion
import net.minecraft.block.ComposterBlock
import net.minecraft.command.argument.serialize.ArgumentSerializer
import net.minecraft.item.ItemConvertible
import net.minecraft.network.PacketByteBuf
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.tag.TagKey
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader
import net.minecraft.resource.ResourceType
import net.minecraft.screen.ScreenHandlerType
import net.minecraft.server.MinecraftServer
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.Identifier
import net.minecraft.world.GameRules
import net.minecraft.world.biome.Biome
import net.minecraft.world.gen.GenerationStep
import net.minecraft.world.gen.feature.PlacedFeature
import org.jetbrains.annotations.ApiStatus
interface CobblemonImplementation {
val modAPI: ModAPI
@@ -159,8 +158,6 @@ interface CobblemonImplementation {
*/
fun registerResourceReloader(identifier: Identifier, reloader: ResourceReloader, type: ResourceType, dependencies: Collection<Identifier>)
fun registerScreenHandlerType(identifier: Identifier, screenHandlerType: ScreenHandlerType<*>)
/**
* TODO
*
@@ -175,43 +172,33 @@ interface CobblemonImplementation {
* @param manager The [ResourceManager] to reload from.
*/
fun <T> reloadJsonRegistry(registry: JsonDataRegistry<T>, manager: ResourceManager): HashMap<Identifier, T>
/**
* Registers an item to the [ComposterBlock].
* Queue the creation of a registry in the implementation.
* This registry will not be immediately available for access.
*
* @param item The [ItemConvertible] being registered.
* @param chance The chance % of increasing the composter level, 0 to 1 expected.
*/
fun registerCompostable(item: ItemConvertible, chance: Float)
/**
* Registers a builtin resource pack.
* @param T The type of the registry entries.
* @param registryKey The [RegistryKey] of this registry.
* @param codec The [Codec] used for this registry entries to be parsed on the server.
* @param networkCodec The [Codec] used when the client is synchronizing this registry from the server. If this is null the client will not require the registry aka not load any data.
*
* @param id The unique [Identifier] of this pack.
* @param title The title displayed in the resource pack GUI, the description is still a part of the pack metadata.
* @param activationBehaviour The [ResourcePackActivationBehaviour] for this pack.
* @see getRegistry
*/
fun registerBuiltinResourcePack(id: Identifier, title: Text, activationBehaviour: ResourcePackActivationBehaviour)
}
enum class ResourcePackActivationBehaviour {
@ApiStatus.Internal
fun <T> createRegistry(registryKey: RegistryKey<Registry<T>>, codec: Codec<T>, networkCodec: Codec<T>? = null)
/**
* The resource pack will start disabled.
* Fetches a registry.
* This is intended for Cobblemon registries but can be used for any.
*
* @param T The type of the registry.
* @param registryKey The [RegistryKey] of the registry being fetched.
* @return The registry if present.
*
* @throws Exception If the registry doesn't exist or isn't loaded yet.
* @see createRegistry
*/
NORMAL,
/**
* The resource pack will start enabled.
*/
DEFAULT_ENABLED,
/**
* The resource pack will always be enabled.
* The user can reorder it but cannot remove it.
*/
ALWAYS_ENABLED;
@ApiStatus.Internal
fun <T> getRegistry(registryKey: RegistryKey<Registry<T>>): Registry<T>
}
@@ -8,18 +8,14 @@
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.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
@@ -30,23 +26,17 @@ import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
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.ability.AbilityChangeItem
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.block.Block
import net.minecraft.block.ComposterBlock
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.BlockItem
import net.minecraft.item.FoodComponent
import net.minecraft.item.HangingSignItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.SignItem
import net.minecraft.item.SmithingTemplateItem
import net.minecraft.item.StewItem
import net.minecraft.item.*
import net.minecraft.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
@@ -125,74 +115,42 @@ 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")
val VIVICHOKE = create("vivichoke", Item(Item.Settings()))
@JvmField
val VIVICHOKE_SEEDS = compostableItem("vivichoke_seeds", VivichokeItem(CobblemonBlocks.VIVICHOKE_SEEDS))
val VIVICHOKE_SEEDS = create("vivichoke_seeds", VivichokeItem(CobblemonBlocks.VIVICHOKE_SEEDS))
@JvmField
val RED_APRICORN = apricornItem("red", ApricornItem(CobblemonBlocks.RED_APRICORN))
val RED_APRICORN = create("red_apricorn", ApricornItem(CobblemonBlocks.RED_APRICORN))
@JvmField
val YELLOW_APRICORN = apricornItem("yellow", ApricornItem(CobblemonBlocks.YELLOW_APRICORN))
val YELLOW_APRICORN = create("yellow_apricorn", ApricornItem(CobblemonBlocks.YELLOW_APRICORN))
@JvmField
val GREEN_APRICORN = apricornItem("green", ApricornItem(CobblemonBlocks.GREEN_APRICORN))
val GREEN_APRICORN = create("green_apricorn", ApricornItem(CobblemonBlocks.GREEN_APRICORN))
@JvmField
val BLUE_APRICORN = apricornItem("blue", ApricornItem(CobblemonBlocks.BLUE_APRICORN))
val BLUE_APRICORN = create("blue_apricorn", ApricornItem(CobblemonBlocks.BLUE_APRICORN))
@JvmField
val PINK_APRICORN = apricornItem("pink", ApricornItem(CobblemonBlocks.PINK_APRICORN))
val PINK_APRICORN = create("pink_apricorn", ApricornItem(CobblemonBlocks.PINK_APRICORN))
@JvmField
val BLACK_APRICORN = apricornItem("black", ApricornItem(CobblemonBlocks.BLACK_APRICORN))
val BLACK_APRICORN = create("black_apricorn", ApricornItem(CobblemonBlocks.BLACK_APRICORN))
@JvmField
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
val WHITE_APRICORN = create("white_apricorn", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
@JvmField
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING, CobblemonBlocks.RED_APRICORN))
val RED_APRICORN_SEED = create("red_apricorn_seed", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
@JvmField
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING, CobblemonBlocks.YELLOW_APRICORN))
val YELLOW_APRICORN_SEED = create("yellow_apricorn_seed", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
@JvmField
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING, CobblemonBlocks.GREEN_APRICORN))
val GREEN_APRICORN_SEED = create("green_apricorn_seed", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
@JvmField
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING, CobblemonBlocks.BLUE_APRICORN))
val BLUE_APRICORN_SEED = create("blue_apricorn_seed", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
@JvmField
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING, CobblemonBlocks.PINK_APRICORN))
val PINK_APRICORN_SEED = create("pink_apricorn_seed", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
@JvmField
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING, CobblemonBlocks.BLACK_APRICORN))
val BLACK_APRICORN_SEED = create("black_apricorn_seed", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
@JvmField
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING, CobblemonBlocks.WHITE_APRICORN))
val WHITE_APRICORN_SEED = create("white_apricorn_seed", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
@JvmField
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
@@ -205,11 +163,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val APRICORN_PLANKS = blockItem("apricorn_planks", CobblemonBlocks.APRICORN_PLANKS)
@JvmField
val APRICORN_LEAVES = compostableBlockItem("apricorn_leaves", CobblemonBlocks.APRICORN_LEAVES)
@JvmField
val APRICORN_BOAT = create("apricorn_boat", CobblemonBoatItem(CobblemonBoatType.APRICORN, false, Item.Settings().maxCount(1)))
@JvmField
val APRICORN_CHEST_BOAT = create("apricorn_chest_boat", CobblemonBoatItem(CobblemonBoatType.APRICORN, true, Item.Settings().maxCount(1)))
val APRICORN_LEAVES = blockItem("apricorn_leaves", CobblemonBlocks.APRICORN_LEAVES).also {
val compostChance = ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE.getFloat(Items.OAK_LEAVES)
// Should always pass unless Mojang reworks leaves to no longer work in the Composter, in that case we already updated w.o doing anything
if (compostChance != ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE.defaultReturnValue()) {
ComposterBlock.ITEM_TO_LEVEL_INCREASE_CHANCE[it] = compostChance
}
}
@JvmField
val APRICORN_DOOR = blockItem("apricorn_door", CobblemonBlocks.APRICORN_DOOR)
@@ -223,48 +183,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val APRICORN_BUTTON = blockItem("apricorn_button", CobblemonBlocks.APRICORN_BUTTON)
@JvmField
val APRICORN_PRESSURE_PLATE = blockItem("apricorn_pressure_plate", CobblemonBlocks.APRICORN_PRESSURE_PLATE)
//@JvmField
// val APRICORN_SIGN = create("apricorn_sign", SignItem(Item.Properties().stacksTo(16).tab(CreativeModeTab.TAB_DECORATIONS), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
@JvmField
val APRICORN_SLAB = blockItem("apricorn_slab", CobblemonBlocks.APRICORN_SLAB)
@JvmField
val APRICORN_STAIRS = blockItem("apricorn_stairs", CobblemonBlocks.APRICORN_STAIRS)
@JvmField
val 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)
val TM_MACHINE = blockItem("tm_machine", CobblemonBlocks.TM_MACHINE)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val MOD_STATION = blockItem("modification_station", CobblemonBlocks.MODIFICATION_STATION)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -403,18 +334,6 @@ 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 = 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())))
@@ -434,11 +353,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
}
})
@JvmField
val ENERGY_ROOT = compostableItem("energy_root", EnergyRootItem(CobblemonBlocks.ENERGY_ROOT, Item.Settings().food(FoodComponent.Builder().hunger(1).snack().saturationModifier(0.2f).build())))
val ENERGY_ROOT = create("energy_root", EnergyRootItem(CobblemonBlocks.ENERGY_ROOT, Item.Settings().food(FoodComponent.Builder().hunger(1).snack().saturationModifier(0.2f).build())))
@JvmField
val REVIVAL_HERB = compostableItem("revival_herb", RevivalHerbItem(CobblemonBlocks.REVIVAL_HERB))
val REVIVAL_HERB = create("revival_herb", RevivalHerbItem(CobblemonBlocks.REVIVAL_HERB))
@JvmField
val PEP_UP_FLOWER = compostableBlockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
val PEP_UP_FLOWER = blockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
@JvmField
val MEDICINAL_BREW = create("medicinal_brew", Item(Item.Settings()))
@JvmField
@@ -473,74 +392,72 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val PP_MAX = create("pp_max", PPUpItem(3))
@JvmField
val RED_MINT_SEEDS = mintSeed("red", MintType.RED.getCropBlock())
val RED_MINT_SEEDS = blockItem("red_mint_seeds", MintType.RED.getCropBlock())
@JvmField
val RED_MINT_LEAF = mintLeaf("red", MintLeafItem(MintType.RED))
val RED_MINT_LEAF = create("red_mint_leaf", MintLeafItem(MintType.RED))
@JvmField
val BLUE_MINT_SEEDS = mintSeed("blue", MintType.BLUE.getCropBlock())
val BLUE_MINT_SEEDS = blockItem("blue_mint_seeds", MintType.BLUE.getCropBlock())
@JvmField
val BLUE_MINT_LEAF = mintLeaf("blue", MintLeafItem(MintType.BLUE))
val BLUE_MINT_LEAF = create("blue_mint_leaf", MintLeafItem(MintType.BLUE))
@JvmField
val CYAN_MINT_SEEDS = mintSeed("cyan", MintType.CYAN.getCropBlock())
val CYAN_MINT_SEEDS = blockItem("cyan_mint_seeds", MintType.CYAN.getCropBlock())
@JvmField
val CYAN_MINT_LEAF = mintLeaf("cyan", MintLeafItem(MintType.CYAN))
val CYAN_MINT_LEAF = create("cyan_mint_leaf", MintLeafItem(MintType.CYAN))
@JvmField
val PINK_MINT_SEEDS = mintSeed("pink", MintType.PINK.getCropBlock())
val PINK_MINT_SEEDS = blockItem("pink_mint_seeds", MintType.PINK.getCropBlock())
@JvmField
val PINK_MINT_LEAF = mintLeaf("pink", MintLeafItem(MintType.PINK))
val PINK_MINT_LEAF = create("pink_mint_leaf", MintLeafItem(MintType.PINK))
@JvmField
val GREEN_MINT_SEEDS = mintSeed("green", MintType.GREEN.getCropBlock())
val GREEN_MINT_SEEDS = blockItem("green_mint_seeds", MintType.GREEN.getCropBlock())
@JvmField
val GREEN_MINT_LEAF = mintLeaf("green", MintLeafItem(MintType.GREEN))
val GREEN_MINT_LEAF = create("green_mint_leaf", MintLeafItem(MintType.GREEN))
@JvmField
val WHITE_MINT_SEEDS = mintSeed("white", MintType.WHITE.getCropBlock())
val WHITE_MINT_SEEDS = blockItem("white_mint_seeds", MintType.WHITE.getCropBlock())
@JvmField
val WHITE_MINT_LEAF = mintLeaf("white", MintLeafItem(MintType.WHITE))
val mints = mutableMapOf<String, MintItem>()
val WHITE_MINT_LEAF = create("white_mint_leaf", MintLeafItem(MintType.WHITE))
@JvmField
val LONELY_MINT = mintItem("lonely_mint", MintItem(Natures.LONELY))
val LONELY_MINT = create("lonely_mint", MintItem(Natures.LONELY))
@JvmField
val ADAMANT_MINT = mintItem("adamant_mint", MintItem(Natures.ADAMANT))
val ADAMANT_MINT = create("adamant_mint", MintItem(Natures.ADAMANT))
@JvmField
val NAUGHTY_MINT = mintItem("naughty_mint", MintItem(Natures.NAUGHTY))
val NAUGHTY_MINT = create("naughty_mint", MintItem(Natures.NAUGHTY))
@JvmField
val BRAVE_MINT = mintItem("brave_mint", MintItem(Natures.BRAVE))
val BRAVE_MINT = create("brave_mint", MintItem(Natures.BRAVE))
@JvmField
val BOLD_MINT = mintItem("bold_mint", MintItem(Natures.BOLD))
val BOLD_MINT = create("bold_mint", MintItem(Natures.BOLD))
@JvmField
val IMPISH_MINT = mintItem("impish_mint", MintItem(Natures.IMPISH))
val IMPISH_MINT = create("impish_mint", MintItem(Natures.IMPISH))
@JvmField
val LAX_MINT = mintItem("lax_mint", MintItem(Natures.LAX))
val LAX_MINT = create("lax_mint", MintItem(Natures.LAX))
@JvmField
val RELAXED_MINT = mintItem("relaxed_mint", MintItem(Natures.RELAXED))
val RELAXED_MINT = create("relaxed_mint", MintItem(Natures.RELAXED))
@JvmField
val MODEST_MINT = mintItem("modest_mint", MintItem(Natures.MODEST))
val MODEST_MINT = create("modest_mint", MintItem(Natures.MODEST))
@JvmField
val MILD_MINT = mintItem("mild_mint", MintItem(Natures.MILD))
val MILD_MINT = create("mild_mint", MintItem(Natures.MILD))
@JvmField
val RASH_MINT = mintItem("rash_mint", MintItem(Natures.RASH))
val RASH_MINT = create("rash_mint", MintItem(Natures.RASH))
@JvmField
val QUIET_MINT = mintItem("quiet_mint", MintItem(Natures.QUIET))
val QUIET_MINT = create("quiet_mint", MintItem(Natures.QUIET))
@JvmField
val CALM_MINT = mintItem("calm_mint", MintItem(Natures.CALM))
val CALM_MINT = create("calm_mint", MintItem(Natures.CALM))
@JvmField
val GENTLE_MINT = mintItem("gentle_mint", MintItem(Natures.GENTLE))
val GENTLE_MINT = create("gentle_mint", MintItem(Natures.GENTLE))
@JvmField
val CAREFUL_MINT = mintItem("careful_mint", MintItem(Natures.CAREFUL))
val CAREFUL_MINT = create("careful_mint", MintItem(Natures.CAREFUL))
@JvmField
val SASSY_MINT = mintItem("sassy_mint", MintItem(Natures.SASSY))
val SASSY_MINT = create("sassy_mint", MintItem(Natures.SASSY))
@JvmField
val TIMID_MINT = mintItem("timid_mint", MintItem(Natures.TIMID))
val TIMID_MINT = create("timid_mint", MintItem(Natures.TIMID))
@JvmField
val HASTY_MINT = mintItem("hasty_mint", MintItem(Natures.HASTY))
val HASTY_MINT = create("hasty_mint", MintItem(Natures.HASTY))
@JvmField
val JOLLY_MINT = mintItem("jolly_mint", MintItem(Natures.JOLLY))
val JOLLY_MINT = create("jolly_mint", MintItem(Natures.JOLLY))
@JvmField
val NAIVE_MINT = mintItem("naive_mint", MintItem(Natures.NAIVE))
val NAIVE_MINT = create("naive_mint", MintItem(Natures.NAIVE))
@JvmField
val SERIOUS_MINT = mintItem("serious_mint", MintItem(Natures.SERIOUS))
val SERIOUS_MINT = create("serious_mint", MintItem(Natures.SERIOUS))
@JvmField val X_ACCURACY = create("x_${Stats.ACCURACY.identifier.path}", XStatItem(Stats.ACCURACY))
@JvmField val X_ATTACK = create("x_${Stats.ATTACK.identifier.path}", XStatItem(Stats.ATTACK))
@@ -565,11 +482,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
*/
@@ -615,9 +527,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
@@ -659,14 +568,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val CHOICE_SPECS = heldItem("choice_specs")
@JvmField
val CLEANSE_TAG = heldItem("cleanse_tag")
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EXP_SHARE = heldItem("exp_share")
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FOCUS_BAND = heldItem("focus_band")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@@ -711,13 +616,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val WISE_GLASSES = heldItem("wise_glasses")
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
val MENTAL_HERB = heldItem("mental_herb")
@JvmField
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
val MIRROR_HERB = heldItem("mirror_herb")
@JvmField
val POWER_HERB = compostableHeldItem("power_herb", null, 1F)
val POWER_HERB = heldItem("power_herb")
@JvmField
val WHITE_HERB = compostableHeldItem("white_herb", null, 1F)
val WHITE_HERB = heldItem("white_herb")
@JvmField
val BRIGHT_POWDER = heldItem("bright_powder")
@JvmField
@@ -740,14 +645,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
@JvmField
val LIFE_ORB = heldItem("life_orb")
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
// Mulch
@JvmField
@@ -769,149 +666,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 AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
"automaton_armor_trim_smithing_template",
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
)
// 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)
@JvmField
val TECHNICAL_MACHINE = this.create("technical_machine", TechnicalMachineItem(Item.Settings()))
@JvmField
val BLANK_TM = this.create("blank_tm", CobblemonItem(Item.Settings()))
// 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()))
@@ -939,12 +696,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
}
)
private fun compostable(item: Item, increaseLevelChance: Float) = Cobblemon.implementation.registerCompostable(item, increaseLevelChance)
private fun berryItem(name: String, berryBlock: BerryBlock): BerryItem {
val finalName = "${name}_berry"
val item = this.create(finalName, BerryItem(berryBlock))
compostable(item, .65f)
this.berries[cobblemonResource(finalName)] = item
return item
}
@@ -952,62 +706,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
private fun berryItem(name: String, berryItem: BerryItem): BerryItem {
val finalName = "${name}_berry"
val item = this.create(finalName, berryItem)
compostable(item, .65f)
this.berries[cobblemonResource(finalName)] = item
return item
}
private fun mintItem(name: String, mintItem: MintItem): MintItem {
val item = this.create(name, mintItem)
mints[item.nature.displayName] = item
compostable(item, .65f)
return item
}
private fun apricornItem(name: String, apricornItem: ApricornItem): ApricornItem {
val finalName = "${name}_apricorn"
val item = this.create(finalName, apricornItem)
compostable(item, .65f)
return item
}
private fun apricornSeedItem(name: String, apricornSeedItem: ApricornSeedItem): ApricornSeedItem {
val finalName = "${name}_apricorn_seed"
val item = this.create(finalName, apricornSeedItem)
compostable(item, .65f)
return item
}
private fun mintSeed(name: String, mintBlock: MintBlock): Item {
val finalName = "${name}_mint_seeds"
val item = this.blockItem(finalName, mintBlock)
compostable(item, .65f)
return item
}
private fun mintLeaf(name: String, mintLeafItem: MintLeafItem): MintLeafItem {
val finalName = "${name}_mint_leaf"
val item = this.create(finalName, mintLeafItem)
compostable(item, .65f)
return item
}
private fun compostableItem(name: String, item: Item? = null, increaseLevelChance: Float = .65f): Item {
val createdItem = this.create(name, item ?: Item(Item.Settings()))
compostable(createdItem, increaseLevelChance)
return createdItem
}
private fun compostableHeldItem(name: String, remappedName: String? = null, increaseLevelChance: Float = .65f): CobblemonItem {
val createdItem = heldItem(name, remappedName)
compostable(createdItem, increaseLevelChance)
return createdItem
}
private fun compostableBlockItem(name: String, block: Block, increaseLevelChance: Float = .65f): Item {
val createdItem = this.blockItem(name, block)
compostable(createdItem, increaseLevelChance)
return createdItem
}
}
@@ -11,40 +11,14 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
import com.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.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.battle.*
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.effect.RunPosableMoLangHandler
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.SpawnSnowstormEntityParticleHandler
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
import com.cobblemon.mod.common.client.net.gui.CraftBlankTMPacketHandler
import com.cobblemon.mod.common.client.net.gui.CraftTMPacketHandler
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.pasture.ClosePastureHandler
@@ -53,6 +27,7 @@ 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
@@ -76,28 +51,14 @@ import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.net.messages.client.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.GlobalSpeciesFeatureSyncPacket
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.data.*
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.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.pasture.ClosePasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
@@ -107,8 +68,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
@@ -133,22 +94,20 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacke
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.ui.CraftBlankTMPacket
import com.cobblemon.mod.common.net.messages.client.ui.CraftTMPacket
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.*
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.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonSelectedPacket
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
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
@@ -172,18 +131,13 @@ import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptanceP
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.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.pasture.PasturePokemonHandler
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
@@ -211,12 +165,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.
@@ -255,8 +209,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())
@@ -283,7 +235,6 @@ object CobblemonNetwork : NetworkManager {
// UI Packets
this.createClientBound(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler)
this.createClientBound(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler)
this.createClientBound(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler)
// Starter packets
this.createClientBound(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler)
@@ -322,23 +273,15 @@ object CobblemonNetwork : NetworkManager {
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::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())
// 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)
@@ -356,7 +299,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)
@@ -366,10 +309,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)
}
override fun registerServerBound() {
@@ -381,7 +320,6 @@ object CobblemonNetwork : NetworkManager {
// Interaction Packets
this.createServerBound(InteractPokemonPacket.ID, InteractPokemonPacket::decode, InteractPokemonHandler)
this.createServerBound(RequestPlayerInteractionsPacket.ID, RequestPlayerInteractionsPacket::decode, RequestInteractionsHandler)
// Storage Packets
this.createServerBound(SendOutPokemonPacket.ID, SendOutPokemonPacket::decode, SendOutPokemonHandler)
@@ -409,8 +347,6 @@ object CobblemonNetwork : NetworkManager {
// Battle packets
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
@@ -435,14 +371,6 @@ object CobblemonNetwork : NetworkManager {
// Party move select packets
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
// TM Machine packets
this.createServerBound(CraftTMPacket.ID, CraftTMPacket::decode, CraftTMPacketHandler)
this.createServerBound(CraftBlankTMPacket.ID, CraftBlankTMPacket::decode, CraftBlankTMPacketHandler)
// Dialogue packets
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
}
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
@@ -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,237 +88,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val MULCH_REMOVE = this.create("mulch.remove")
@JvmField
val FOSSIL_MACHINE_ACTIVATE = this.create("fossilmachine.activate")
@JvmField
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossilmachine.active_loop")
@JvmField
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossilmachine.assemble")
@JvmField
val FOSSIL_MACHINE_DNA_FULL = this.create("fossilmachine.dna_full")
@JvmField
val FOSSIL_MACHINE_FINISHED = this.create("fossilmachine.finished")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossilmachine.insert_dna")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossilmachine.insert_dna_small")
@JvmField
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossilmachine.insert_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossilmachine.retrieve_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossilmachine.retrieve_pokemon")
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
@JvmField
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
@JvmField
val COIN_POUCH_STEP = this.create("coin_pouch.step")
@JvmField
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
@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 MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.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 COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
COIN_POUCH_BREAK,
COIN_POUCH_STEP,
COIN_POUCH_PLACE,
COIN_POUCH_HIT,
COIN_POUCH_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 TM_USE = this.create("tm.use")
@JvmField
val TMM_CRAFT = this.create("tmm.craft")
@JvmField
val TMM_CRAFT_BLANK = this.create("tmm.craft_blank")
@JvmField
val TMM_OFF = this.create("tmm.off")
@JvmField
val TMM_ON = this.create("tmm.on")
@JvmField
val TYPE_GEM_SOUNDS = TUMBLESTONE_BLOCK_SOUNDS
@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 MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
MINT_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)))
}
@@ -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,14 +106,6 @@ object CobblemonCriteria {
)
)
// 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)
}
@@ -8,6 +8,7 @@
package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
@@ -30,7 +31,11 @@ class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPred
override fun fromJson(json: JsonObject) {
super.fromJson(json)
type = json.get("type")?.asString ?: "any"
var stored = json.get("type")?.asString
if (stored != null && stored != "any") {
stored = stored.asIdentifierDefaultingNamespace().toString()
}
type = stored ?: "any"
}
override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
@@ -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
}
}
@@ -12,6 +12,8 @@ import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.PrioritizedList
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.pokemon.Species
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
/**
* A pool of potential abilities, as a [PrioritizedList]. The added logic of this subclass
@@ -35,4 +37,22 @@ open class AbilityPool : PrioritizedList<PotentialAbility>() {
Exception().printStackTrace()
return Abilities.first().create() to Priority.LOWEST
}
companion object {
@JvmField
val CODEC: Codec<AbilityPool> = Codec.list(Codec.STRING)
.comapFlatMap(
{ raw ->
val pool = AbilityPool()
if (raw.isEmpty()) {
return@comapFlatMap DataResult.error { "Cannot create ability pool from an empty list" }
}
raw.forEach { }
DataResult.success(pool)
}
)
}
}
@@ -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)
}
@@ -10,9 +10,12 @@ package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.google.gson.JsonElement
import com.mojang.serialization.Codec
interface PotentialAbilityType<T : PotentialAbility> {
fun parseFromJSON(element: JsonElement): T?
fun codec(): Codec<out PotentialAbilityType<*>>
}
/**
@@ -45,6 +48,10 @@ object CommonAbilityType : PotentialAbilityType<CommonAbility> {
}
}
}
override fun codec(): Codec<out PotentialAbilityType<*>> {
TODO("Not yet implemented")
}
}
open class CommonAbility(override val template: AbilityTemplate) : PotentialAbility {
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.ai
import com.cobblemon.mod.common.api.serialization.StringIdentifiedObjectAdapter
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import net.minecraft.entity.ai.TargetPredicate
import net.minecraft.util.math.Box
@@ -44,6 +46,11 @@ interface SleepDepth {
"normal" to normal
)
val adapter = StringIdentifiedObjectAdapter { depths[it] ?: throw IllegalArgumentException("Unknown sleep depth: $it") }
val CODEC: Codec<SleepDepth> = Codec.STRING.flatXmap(
{ string -> depths[string]?.let { DataResult.success(it) } ?: DataResult.error { "Cannot find a SleepDepth with the ID $string" } },
{ depth -> depths.entries.firstOrNull { it.value == depth }?.let { DataResult.success(it.key) } ?: DataResult.error { "Cannot resolve a ID for the SleepDepth $depth" } }
)
}
fun canSleep(pokemonEntity: PokemonEntity): Boolean
@@ -8,13 +8,9 @@
package com.cobblemon.mod.common.api.battles.model
import com.bedrockk.molang.runtime.MoLangEnvironment
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
import com.cobblemon.mod.common.Environment
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
@@ -22,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.addFunction
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
@@ -46,15 +40,14 @@ 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 java.io.File
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import java.util.concurrent.ConcurrentLinkedDeque
/**
* Individual battle instance
@@ -62,7 +55,6 @@ import java.util.concurrent.ConcurrentLinkedDeque
* @since January 16th, 2022
* @author Deltric, Hiroku
*/
@Suppress("unused", "MemberVisibilityCanBePrivate")
open class PokemonBattle(
val format: BattleFormat,
val side1: BattleSide,
@@ -75,11 +67,8 @@ open class PokemonBattle(
side1.battle = this
side2.battle = this
this.actors.forEach { actor ->
actor.battle = this
actor.pokemonList.forEach { battlePokemon ->
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
.forEach { it.reset() }
battlePokemon.criticalHits = 0
}
}
}
@@ -93,13 +82,12 @@ open class PokemonBattle(
val playerUUIDs: Iterable<UUID>
get() = actors.flatMap { it.getPlayerUUIDs() }
val players = playerUUIDs.mapNotNull { it.getPlayer() }
val spectators = mutableSetOf<UUID>()
val spectators = mutableListOf<UUID>()
val battleId = UUID.randomUUID()
val showdownMessages = mutableListOf<String>()
val battleLog = mutableListOf<String>()
val chatLog = mutableListOf<Text>()
var started = false
var ended = false
// TEMP battle showcase stuff
@@ -109,7 +97,7 @@ open class PokemonBattle(
var dispatchResult = GO
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
val afterDispatches = mutableListOf<() -> Unit>()
val captureActions = mutableListOf<BattleCaptureAction>()
@@ -187,8 +175,11 @@ open class PokemonBattle(
}
fun broadcastChatMessage(component: Text) {
chatLog.add(component)
sendSpectatorUpdate(BattleMessagePacket(component))
spectators.forEach { spectatorId ->
spectatorId.getPlayer()?.let {
CobblemonNetwork.sendPacketToPlayer(it, BattleMessagePacket(component))
}
}
return actors.forEach { it.sendMessage(component) }
}
@@ -259,6 +250,7 @@ open class PokemonBattle(
}
}
sendUpdate(BattleEndPacket())
sendUpdate(BattleMusicPacket(null))
BattleRegistry.closeBattle(this)
}
@@ -325,12 +317,6 @@ open class PokemonBattle(
fun dispatch(dispatcher: () -> DispatchResult) {
dispatches.add(BattleDispatch { dispatcher() })
}
fun dispatchToFront(dispatcher: () -> DispatchResult) {
dispatches.addFirst(BattleDispatch { dispatcher() })
}
fun dispatchGo(dispatcher: () -> Unit) {
@@ -362,10 +348,6 @@ open class PokemonBattle(
dispatches.add(dispatcher)
}
fun dispatchToFront(dispatcher: BattleDispatch) {
dispatches.addFirst(dispatcher)
}
fun doWhenClear(action: () -> Unit) {
afterDispatches.add(action)
}
@@ -470,13 +452,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
}
}
@@ -26,20 +26,13 @@ abstract class AIBattleActor(
super.sendUpdate(packet)
if (packet is BattleMakeChoicePacket) {
this.onChoiceRequested()
}
}
/**
* Called when the AI is requested to make a choice.
*/
open fun onChoiceRequested() {
try {
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose))
} catch (exception: IllegalActionChoiceException) {
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
exception.printStackTrace()
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
try {
setActionResponses(request!!.iterate(this.activePokemon, battleAI::choose))
} catch (exception: IllegalActionChoiceException) {
LOGGER.error("AI was unable to choose a move, we're going to need to pass!")
exception.printStackTrace()
setActionResponses(request!!.iterate(this.activePokemon) { _, _, _ -> PassActionResponse })
}
}
}
}
@@ -0,0 +1,20 @@
/*
* 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.conditional
import net.minecraft.registry.Registry
import net.minecraft.util.Identifier
class RegistryElementCondition<T>(val element: T, private val source: Identifier) : RegistryLikeCondition<T> {
override fun fits(value: T, registry: Registry<T>): Boolean = value == this.element
override fun pretty(): String = this.source.toString()
}
@@ -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.api.conditional
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import java.lang.reflect.Type
/**
* Adapter for [RegistryLikeCondition]s. Its logic is that the implementation of this adapter must
* provide a list of resolvers, and the deserializer will find the first resolver that returns a non-null
* value for the [JsonElement].
*
* @author Hiroku
* @since July 17th, 2022
*/
interface RegistryLikeAdapter<B> : JsonDeserializer<RegistryLikeCondition<B>> {
val registryLikeConditions: MutableList<(JsonElement) -> RegistryLikeCondition<B>?>
override fun deserialize(json: JsonElement, type: Type, ctx: JsonDeserializationContext): RegistryLikeCondition<B> {
return registryLikeConditions.firstNotNullOfOrNull { it(json) }
?: throw IllegalArgumentException("Unable to deserialize $json")
}
}
@@ -8,7 +8,11 @@
package com.cobblemon.mod.common.api.conditional
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import net.minecraft.registry.Registry
import net.minecraft.registry.tag.TagKey
import net.minecraft.util.Identifier
/**
* A condition which applies to an entry in some [Registry].
@@ -16,6 +20,43 @@ import net.minecraft.registry.Registry
* @author Hiroku
* @since July 16th, 2022
*/
interface RegistryLikeCondition<T> {
fun fits(t: T, registry: Registry<T>): Boolean
sealed interface RegistryLikeCondition<T> {
/**
* Checks if a given [value] matches this condition.
*
* @param value The value being matched against this condition.
* @param registry The [Registry] of type [T] being queried.
* @return If the condition is fulfilled.
*/
fun fits(value: T, registry: Registry<T>): Boolean
/**
* Generates a string like human-friendly representation used by the Codec when serializing.
*
* @return The string like human-friendly representation.
*/
fun pretty(): String
companion object {
@JvmStatic
fun <T> createCodec(registryAccessor: () -> Registry<T>): Codec<RegistryLikeCondition<T>> = Codec.STRING.comapFlatMap(
{ string ->
val registry = registryAccessor.invoke()
val isTag = string.startsWith("#")
val rawIdentifier = if (isTag) string.substringAfter("#") else string
val identifier = Identifier.tryParse(rawIdentifier) ?: return@comapFlatMap DataResult.error { "Cannot resolve identifier/tag from the string $string" }
if (isTag) {
val tag = TagKey.of(registry.key, identifier)
return@comapFlatMap DataResult.success(RegistryTagCondition(tag))
}
val element = registry.get(identifier) ?: return@comapFlatMap DataResult.error { "Cannot find an element in registry ${registry.key.value} with the ID $identifier" }
return@comapFlatMap DataResult.success(RegistryElementCondition(element, identifier))
},
{ it.pretty() }
)
}
}
@@ -1,28 +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.conditional
import com.google.gson.JsonElement
import net.minecraft.registry.Registry
import net.minecraft.util.Identifier
/**
* A condition for some registry type which asserts that the entry must have the given [Identifier].
*
* @author Hiroku
* @since July 16th, 2022
*/
open class RegistryLikeIdentifierCondition<T>(val identifier: Identifier) : RegistryLikeCondition<T> {
companion object {
fun <T> resolver(
constructor: (Identifier) -> RegistryLikeIdentifierCondition<T>
): (JsonElement) -> RegistryLikeIdentifierCondition<T>? = { constructor(Identifier(it.asString)) }
}
override fun fits(t: T, registry: Registry<T>) = registry.getId(t) == identifier
}
@@ -1,54 +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.conditional
import com.google.gson.JsonElement
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.tag.TagKey
import net.minecraft.util.Identifier
/**
* A condition for some registry type that asserts that the entry must be inside the given [TagKey]. This is presented
* in JSONs as an identifier prefixed with a hash.
*
* @author Hiroku
* @since July 16th, 2022
*/
open class RegistryLikeTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
companion object {
const val PREFIX = "#"
fun <T> resolver(
registryKey: RegistryKey<Registry<T>>,
constructor: (TagKey<T>) -> RegistryLikeTagCondition<T>
): (JsonElement) -> RegistryLikeTagCondition<T>? = {
val firstSymbol = it.asString.substring(0, 1)
if (firstSymbol == PREFIX) {
val identifier = Identifier(it.asString.substring(1))
constructor(TagKey.of(registryKey, identifier))
} else {
null
}
}
}
override fun fits(t: T, registry: Registry<T>): Boolean {
// val registryHasTag = registry.containsTag(tag)
// if (!registryHasTag) {
//// LOGGER.warn("No tag in registry: ${tag.id}")
// return false
// }
return registry.getKey(t)
.flatMap(registry::getEntry)
.map { entry -> entry.isIn(tag) }
.orElse(false)
}
}
@@ -0,0 +1,20 @@
/*
* 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.conditional
import net.minecraft.registry.Registry
import net.minecraft.registry.tag.TagKey
class RegistryTagCondition<T>(val tag: TagKey<T>) : RegistryLikeCondition<T> {
override fun fits(value: T, registry: Registry<T>): Boolean = registry.getEntry(value).isIn(this.tag)
override fun pretty(): String = "#${this.tag.id}"
}
@@ -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,41 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.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) {
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
activeDialogues[playerEntity.uuid] = activeDialogue
val packet = DialogueOpenedPacket(activeDialogue, includeFaces = true)
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,12 +10,11 @@ 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 kotlin.random.Random
import net.minecraft.entity.LivingEntity
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.Vec3d
import kotlin.random.Random
/**
* A table of drops that can produce a list of [DropEntry]. You can produce a drop list from [getDrops] to
@@ -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")
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.entity
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.
@@ -17,5 +16,4 @@ import net.minecraft.entity.data.TrackedData
interface EntitySideDelegate<T : Entity> {
fun initialize(entity: T) {}
fun tick(entity: T) {}
fun onTrackedDataSet(data: TrackedData<*>) {}
}
@@ -8,11 +8,7 @@
package com.cobblemon.mod.common.api.events
import com.cobblemon.mod.common.api.events.battles.BattleFaintedEvent
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.events.battles.BattleStartedPostEvent
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
import com.cobblemon.mod.common.api.events.battles.*
import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
@@ -31,10 +27,7 @@ import com.cobblemon.mod.common.api.events.pokemon.*
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionAcceptedEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
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
@@ -62,13 +55,9 @@ object CobblemonEvents {
@JvmField
val EVOLUTION_DISPLAY = EventObservable<EvolutionDisplayEvent>()
@JvmField
val EVOLUTION_TESTED = EventObservable<EvolutionTestedEvent>()
@JvmField
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 +93,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
@@ -116,14 +102,12 @@ object CobblemonEvents {
@JvmField
val ENTITY_SPAWN = CancelableObservable<SpawnEvent<*>>()
@Suppress("UNCHECKED_CAST")
@JvmField
val POKEMON_ENTITY_SPAWN = ENTITY_SPAWN
.pipe(
filter { it.entity is PokemonEntity },
map {
@Suppress("UNCHECKED_CAST")
it as SpawnEvent<PokemonEntity>
}
map { it as SpawnEvent<PokemonEntity> }
)
@JvmField
@@ -160,8 +144,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
}
@@ -23,6 +23,6 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @since April 28th, 2022
*/
data class EvolutionAcceptedEvent(
override val pokemon: Pokemon,
override val evolution: Evolution
) : Cancelable(), EvolutionEvent
val pokemon: Pokemon,
val evolution: Evolution
) : Cancelable()
@@ -21,6 +21,6 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @since October 2nd, 2022
*/
data class EvolutionCompleteEvent(
override val pokemon: Pokemon,
override val evolution: Evolution
) : EvolutionEvent
val pokemon: Pokemon,
val evolution: Evolution
)
@@ -25,7 +25,7 @@ import com.cobblemon.mod.common.pokemon.Pokemon
* @since May 3rd, 2022
*/
data class EvolutionDisplayEvent(
override val pokemon: Pokemon,
val pokemon: Pokemon,
var display: EvolutionDisplay,
override val evolution: Evolution
) : EvolutionEvent
val evolution: Evolution
)
@@ -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.events.pokemon.evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* The root of the various evolution related events.
*/
interface EvolutionEvent {
/**
* The Pokémon impacted in this event.
*/
val pokemon: Pokemon
/**
* The evolution triggering this event.
*/
val evolution: Evolution
}
@@ -1,28 +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.evolution
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
import com.cobblemon.mod.common.pokemon.Pokemon
/**
* An event fired when [Evolution.test] has been performed.
* The final state [result] will be the return value of the test function.
*
* @property pokemon The [Pokemon] being tested against.
* @property evolution The [Evolution] instance performing the test.
* @property originalResult The base result from the Cobblemon implementation.
* @property result The final value returned by [Evolution.test].
*/
data class EvolutionTestedEvent(
override val pokemon: Pokemon,
override val evolution: Evolution,
val originalResult: Boolean,
var result: Boolean
) : EvolutionEvent
@@ -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,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
}
}
@@ -122,27 +122,16 @@ fun drawText(
y: Number,
centered: Boolean = false,
colour: Int,
shadow: Boolean = true,
pMouseX: Number? = null,
pMouseY: Number? = null
): Boolean {
shadow: Boolean = true
) {
val comp = if (font == null) text else text.setStyle(text.style.withFont(font))
val textRenderer = MinecraftClient.getInstance().textRenderer
var x = x
val width = textRenderer.getWidth(comp)
if (centered) {
val width = textRenderer.getWidth(comp)
x = x.toDouble() - width / 2
}
context.drawText(textRenderer, comp, x.toInt(), y.toInt(), colour, shadow)
var isHovered = false
if (pMouseY != null && pMouseX != null) {
if (pMouseX.toInt() >= x.toInt() && pMouseX.toInt() <= x.toInt() + width &&
pMouseY.toInt() >= y.toInt() && pMouseY.toInt() <= y.toInt() + textRenderer.fontHeight
) {
isHovered = true
}
}
return isHovered
}
fun drawText(
@@ -196,8 +185,6 @@ fun drawPortraitPokemon(
val context = RenderContext()
PokemonModelRepository.getTextureNoSubstitute(species.resourceIdentifier, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, species.getForm(aspects).baseScale)
context.put(RenderContext.SPECIES, species.resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
val renderType = model.getLayer(texture)
@@ -208,12 +195,10 @@ fun drawPortraitPokemon(
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, 0F, 0F, 0F, 0F, 0F)
originalPose?.let { state.setPose(it) }
}
matrixStack.push()
@@ -66,15 +66,7 @@ interface PokemonSelectingItem {
return if (entity != null) {
val pokemon = entity.pokemon
if (entity.ownerUuid == player.uuid) {
val typedActionResult = applyToPokemon(player, stack, pokemon)
if (typedActionResult != null)
{
CobblemonCriteria.POKEMON_INTERACT.trigger(player, PokemonInteractContext(pokemon.species.resourceIdentifier, Registries.ITEM.getId(stack.item)))
typedActionResult
}
else {
TypedActionResult.pass(stack)
}
applyToPokemon(player, stack, pokemon) ?: TypedActionResult.pass(stack)
} else {
TypedActionResult.fail(stack)
}
@@ -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,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.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 {
/** Produces a [MoValue] for a [MoLangRuntime] to supply an environment. */
fun resolve(runtime: MoLangRuntime): MoValue
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,23 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.molang
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
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 resolve(runtime: MoLangRuntime) = exprs.resolve(runtime)
}
@@ -1,196 +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.MoLangEnvironment
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.MoParams
import com.bedrockk.molang.runtime.struct.ArrayStruct
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
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.api.dialogue.PlayerDialogueFaceProvider
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
import com.cobblemon.mod.common.util.isInt
import com.cobblemon.mod.common.util.itemRegistry
import net.minecraft.block.Block
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtDouble
import net.minecraft.nbt.NbtElement
import net.minecraft.nbt.NbtList
import net.minecraft.nbt.NbtString
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
import net.minecraft.registry.entry.RegistryEntry
import net.minecraft.registry.tag.TagKey
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.world.World
import net.minecraft.world.biome.Biome
import net.minecraft.world.dimension.DimensionType
/**
* Holds a bunch of useful MoLang trickery that can be used or extended in API
*
* @author Hiroku
* @since October 2nd, 2023
*/
object MoLangFunctions {
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>(
"is_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().isInt()) },
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
"to_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toIntOrNull() ?: 0) },
"to_string" to java.util.function.Function { params -> StringValue(params.get<MoValue>(0).asString()) },
"do_effect_walks" to java.util.function.Function { _ ->
DoubleValue(Cobblemon.config.walkingInBattleAnimations)
},
"random" to java.util.function.Function { params ->
val options = mutableListOf<MoValue>()
var index = 0
while (params.contains(index)) {
options.add(params.get(index))
index++
}
return@Function options.random() // Can throw an exception if they specified no args. They'd be idiots though.
},
"curve" to java.util.function.Function { params ->
val curveName = params.getString(0)
val curve = WaveFunctions.functions[curveName] ?: throw IllegalArgumentException("Unknown curve: $curveName")
return@Function ObjectValue(curve)
},
"array" to java.util.function.Function { params ->
val values = params.params
val array = ArrayStruct(hashMapOf())
values.forEachIndexed { index, moValue -> array.setDirectly("$index", moValue) }
return@Function array
}
)
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
val playerFunctions = mutableListOf<(ServerPlayerEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
{ player ->
hashMapOf(
"username" to java.util.function.Function { _ -> StringValue(player.gameProfile.name) },
"uuid" to java.util.function.Function { _ -> StringValue(player.gameProfile.id.toString()) },
"data" to java.util.function.Function { _ -> return@Function Cobblemon.molangData.load(player.uuid) },
"save_data" to java.util.function.Function { _ -> Cobblemon.molangData.save(player.uuid) },
"main_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.mainHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
"off_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.offHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
"face" to java.util.function.Function { _ -> ObjectValue(PlayerDialogueFaceProvider(player.uuid)) }
)
}
)
fun RegistryEntry<Biome>.asBiomeMoLangValue() = asMoLangValue(RegistryKeys.BIOME).addFunctions(biomeFunctions)
fun RegistryEntry<World>.asWorldMoLangValue() = asMoLangValue(RegistryKeys.WORLD).addFunctions(worldFunctions)
fun RegistryEntry<Block>.asBlockMoLangValue() = asMoLangValue(RegistryKeys.BLOCK).addFunctions(blockFunctions)
fun RegistryEntry<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(RegistryKeys.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
fun ServerPlayerEntity.asMoLangValue(): ObjectValue<ServerPlayerEntity> {
val value = ObjectValue(
obj = this,
stringify = { it.entityName }
)
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
return value
}
fun <T> RegistryEntry<T>.asMoLangValue(key: RegistryKey<Registry<T>>): ObjectValue<RegistryEntry<T>> {
val value = ObjectValue(
obj = this,
stringify = { it.key.get().value.toString() }
)
value.functions.put("is_in") {
val tag = TagKey.of(key, Identifier(it.getString(0).replace("#", "")))
return@put DoubleValue(if (value.obj.isIn(tag)) 1.0 else 0.0)
}
value.functions.put("is_of") {
val identifier = Identifier(it.getString(0))
return@put DoubleValue(if (value.obj.matchesId(identifier)) 1.0 else 0.0)
}
return value
}
fun QueryStruct.addStandardFunctions(): QueryStruct {
functions.putAll(generalFunctions)
return this
}
fun <T : QueryStruct> T.addFunctions(functions: Map<String, java.util.function.Function<MoParams, Any>>): T {
this.functions.putAll(functions)
return this
}
fun <T : QueryStruct> T.addFunction(name: String, function: java.util.function.Function<MoParams, Any>): T {
this.functions[name] = function
return this
}
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
fun MoLangRuntime.setup(): MoLangRuntime {
environment.getQueryStruct().addStandardFunctions()
return this
}
fun writeMoValueToNBT(value: MoValue): NbtElement? {
return when (value) {
is DoubleValue -> NbtDouble.of(value.value)
is StringValue -> NbtString.of(value.value)
is ArrayStruct -> {
val list = value.map.values
val nbtList = NbtList()
list.mapNotNull(::writeMoValueToNBT).forEach(nbtList::add)
nbtList
}
is VariableStruct -> {
val nbt = NbtCompound()
value.map.forEach { (key, value) ->
val element = writeMoValueToNBT(value) ?: return@forEach
nbt.put(key, element)
}
nbt
}
else -> null
}
}
fun readMoValueFromNBT(nbt: NbtElement): MoValue {
return when (nbt) {
is NbtDouble -> DoubleValue(nbt.doubleValue())
is NbtString -> StringValue(nbt.asString())
is NbtList -> {
val array = ArrayStruct(hashMapOf())
var index = 0
nbt.forEach { element ->
val value = readMoValueFromNBT(element)
array.setDirectly("$index", value)
index++
}
array
}
is NbtCompound -> {
val variable = VariableStruct(hashMapOf())
nbt.keys.toList().forEach { key ->
val value = readMoValueFromNBT(nbt[key]!!)
variable.map[key] = value
}
variable
}
else -> null
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
}
}
@@ -1,28 +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.struct.QueryStruct
import com.bedrockk.molang.runtime.value.MoValue
/**
* A [MoValue] that just wraps around some other object value. It's for good and valid reasons.
*
* @author Hiroku
* @since October 2nd, 2023
*/
class ObjectValue<T>(
var obj: T,
val stringify: (T) -> String = { it.toString() },
val doublify: (T) -> Double = { throw NotImplementedError("Doublify not implemented for this object value, are you doing weird molang") }
) : QueryStruct(hashMapOf()) {
override fun value() = this
override fun asDouble() = doublify(obj)
override fun asString() = stringify(obj)
}
@@ -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.molang
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.util.resolve
/**
* A simple implementation of [ExpressionLike] that is just a single [Expression]. This
* is as opposed to [ListExpression]s.
*
* @author Hiroku
* @since October 22nd, 2023
*/
class SingleExpression(val expr: Expression) : ExpressionLike {
override fun resolve(runtime: MoLangRuntime) = runtime.resolve(expr)
}

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