Compare commits

..
Author SHA1 Message Date
Lily 1e261966ed run button works 2024-02-28 19:07:26 -05:00
3886 changed files with 15618 additions and 206028 deletions
+4 -132
View File
@@ -1,6 +1,5 @@
# 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.
@@ -15,133 +14,23 @@
- 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.
- You'll also find Terracotta Sun Stone Ore in Badlands biomes.
- 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 various new tags for searchability and better compatibility.
- Added Type Gems. These items hold no functionality for now. Start collecting though...
- Added 6 custom Pottery Sherds, obtained from ruin structures.
- Added cries to Meowth, Alolan Meowth, Galaraian Meowth,
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
### Pokémon Added
#### Gen 2
- Sentret
- Furret
- Qwilfish
- Heracross
- Skarmory
- Ferroseed
- Ferrothorn
#### Gen 3
- Lileep
- Cradily
- Anorith
- Armaldo
- Tropius
- Roselia
#### Gen 4
- Shieldon
- Bastiodon
- Cranidos
- Rampardos
- Budew
- Roserade
#### Gen 5
- Tirtouga
- Carracosta
- Archen
- Archeops
- Zorua
- Zoroark
- Petilil
- Lilligant
- Darumaka
- Darmanitan
- Woobat
- Swoobat
- Sandile
- Krokorok
- Krookodile
- Frillish
- Jellicent
- Cubchoo
- Beartic
- Deino
- Zweilous
- Hydreigon
- Larvesta
- Volcarona
#### Gen 6
- Tyrunt
- Tyrantrum
- Amaura
- Aurorus
- Goomy
- Sliggoo
- Goodra
#### Gen 7
- Turtonator
- Fomantis
- Lurantis
- Salandit
- Salazzle
- Jangmo-o
- Hakamo-o
- Kommo-o
#### Gen 8
- Gossifleur
- Eldegoss
- Arctozolt
- Arctovish
- Dracozolt
- Dracovish
- Basculegion
- Hisuian Zorua
- Hisuian Zoroark
- Hisuian Voltorb
- Hisuian Electrode
- Hisuian Qwilfish
- Overqwil
- Hisuian Sneasel
- Sneasler
- Stonjourner
- Cufant
- Copperajah
- Dreepy
- Drakloak
- Dragapult
- Hisuian Sliggoo
- Hisuian Goodra
#### Gen 9
- Gimmighoul.
- 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?
### Changes
- Pokémon now transition more smoothly between different poses.
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Omanyte, Omastar, Growlithe, Swinub, Piloswine, Basculine, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, and Raboot.
- Updated animations for Diglett, Dugtrio, Dragonite, Omanyte, Omastar, Pinsir, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Drifloon, and Drifblim.
- 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.
@@ -152,16 +41,9 @@
- 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.
- Starter Toast now closes once corresponding button is pressed once.
- Moved some items in the vanilla Food & Drinks category.
- Stacked Cobblemon Potion Bases can now be quick moved into Brewing Stands.
- Changed Healer recipe to swap the Max Revive for a Revive.
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%.
- Pokémon with a low Blaze Powder drop chance now drop it more frequently in the Nether.
- Reorganised a few advancements.
- Using the run button in battle will now actually flee the battle.
### Fixes
- Resized Snorlax.
- 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.
@@ -180,8 +62,6 @@
- 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.
### Developer
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
@@ -193,13 +73,7 @@
- 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.
- 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.
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
- `public_spawns_to_json.py` script has been added to give the powerful spawn.json generator a simplistic UI.
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
### Datapack & Resourcepack Creators
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
@@ -234,8 +108,6 @@
}
```
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
- Added the item tag ``cobblemon:ability_changers``, contains the ``cobblemon:ability_capsule`` & ``cobblemon:ability_patch`` by default.
- Added the item tag ``cobblemon:held/is_friendship_booster``, allows items to give the Soothe Bell effect of a boost of 1.5x Friendship gained, contains ``cobblemon:soothe_bell`` by default.
## [1.4.1 (December 23rd, 2023)](#1-4-1)
@@ -1171,4 +1043,4 @@ Thank you so much to all of our community translators that bring the mod to the
- 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.
-3
View File
@@ -15,7 +15,4 @@ dependencies {
implementation(libs.shadow)
implementation(libs.loom)
implementation(libs.architecturyPlugin)
implementation(libs.blossom)
implementation(libs.ideaExt)
}
@@ -1,6 +1,3 @@
import extensions.VersionType
import extensions.writeVersion
plugins {
java
`java-library`
@@ -34,7 +31,7 @@ publishing {
groupId = "com.cobblemon"
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
version = project.writeVersion(VersionType.PUBLISHING)
version = rootProject.version.toString()
}
}
}
@@ -1,24 +0,0 @@
package extensions
import org.gradle.api.Project
fun Project.version(): String {
return rootProject.property("mod_version").toString()
}
fun Project.isSnapshot(): Boolean {
return rootProject.property("snapshot") == "true"
}
fun Project.writeVersion(type: VersionType = VersionType.FULL): String {
val version = "${rootProject.property("mod_version")}+${rootProject.property("mc_version")}"
return when (type) {
VersionType.PUBLISHING -> if(this.isSnapshot()) "$version-SNAPSHOT" else version
VersionType.FULL -> if(this.isSnapshot()) rootProject.version.toString() else version
}
}
enum class VersionType {
PUBLISHING,
FULL
}
+2 -2
View File
@@ -9,5 +9,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}"
}
version = "$version-SNAPSHOT-${versioning.info.branch}-${versioning.info.build}"
}
+2 -42
View File
@@ -1,9 +1,3 @@
import extensions.isSnapshot
import extensions.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
/*
*
* * Copyright (C) 2023 Cobblemon Contributors
@@ -17,10 +11,6 @@ import java.time.format.DateTimeFormatter
plugins {
id("cobblemon.base-conventions")
id("cobblemon.publish-conventions")
id("net.kyori.blossom")
id("org.jetbrains.gradle.plugin.idea-ext")
id ("net.nemerosa.versioning") version "2.8.2"
}
architectury {
@@ -54,7 +44,8 @@ dependencies {
modCompileOnly(libs.mongoDriverCore)
modCompileOnly(libs.mongoDriverSync)
testImplementation(libs.fabricJunit)
testRuntimeOnly(libs.junitEngine)
testImplementation(libs.junitApi)
testImplementation(libs.junitParams)
testImplementation(libs.mockito)
testImplementation(libs.mockk)
@@ -68,34 +59,3 @@ tasks.withType<Test> {
setExceptionFormat("full")
}
}
sourceSets {
main {
blossom {
kotlinSources {
fun generateLicenseHeader() : String {
val builder = StringBuilder()
builder.append("/*\n")
rootProject.file("HEADER").forEachLine {
if(it.isEmpty()) {
builder.append(" *").append("\n")
} else {
builder.append(" * ").append(it).append("\n")
}
}
return builder.append(" */").append("\n").toString()
}
property("license", generateLicenseHeader())
property("modid", "cobblemon")
property("version", project.version())
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
property("gitCommit", versioning.info.commit)
property("branch", versioning.info.branch)
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
}
}
}
}
@@ -1,35 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.CobblemonBuildDetails;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(CrashReport.class)
public final class CrashReportMixin {
@Inject(method = "addStackTrace", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemDetails;writeTo(Ljava/lang/StringBuilder;)V"))
public void cobblemon$printCobblemonDetails(StringBuilder builder, CallbackInfo callback) {
CrashReportSection cobblemon = new CrashReportSection("Cobblemon");
cobblemon.add("Version", CobblemonBuildDetails.VERSION);
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
cobblemon.add("Timestamp", CobblemonBuildDetails.TIMESTAMP);
cobblemon.addStackTrace(builder);
builder.append("\n\n");
}
}
@@ -9,23 +9,18 @@
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.Item;
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;
import org.spongepowered.asm.mixin.injection.Redirect;
@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();
}
public class PiglinEntityMixin {
@Redirect(method = "equipToOffHand", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z"))
public boolean cobblemon$isValidBarteringItem(ItemStack stack, Item item) {
//TODO: Make a tag?
return stack.isOf(item) || stack.isOf(CobblemonItems.RELIC_COIN_POUCH);
}
}
@@ -1,18 +0,0 @@
{{ license }}
package com.cobblemon.mod.common
object CobblemonBuildDetails {
const val MOD_ID = "{{ modid }}"
const val VERSION = "{{ version }}"
const val SNAPSHOT = {{ isSnapshot }}
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
const val BRANCH = "{{ branch | default("Not Specified") }}"
const val TIMESTAMP = "{{ timestamp }}"
fun smallCommitHash(): String {
return this.GIT_COMMIT.substring(0, 7)
}
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.Priority
@@ -17,10 +16,10 @@ import com.cobblemon.mod.common.api.data.DataProvider
import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.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
@@ -36,10 +35,7 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
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.ChoiceSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
import com.cobblemon.mod.common.api.pokemon.feature.*
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
@@ -66,14 +62,24 @@ import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.*
import com.cobblemon.mod.common.battles.BagItems
import com.cobblemon.mod.common.battles.BattleFormat
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.battles.BattleSide
import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.command.argument.*
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
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.config.LastChangedVersion
import com.cobblemon.mod.common.config.constraint.IntConstraint
import com.cobblemon.mod.common.config.starter.StarterConfig
import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.events.AdvancementHandler
import com.cobblemon.mod.common.events.ServerTickHandler
@@ -87,6 +93,7 @@ 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
@@ -94,7 +101,13 @@ import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
import com.cobblemon.mod.common.sherds.CobblemonSherds
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.trade.TradeManager
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.DataKeys
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.ifDedicatedServer
import com.cobblemon.mod.common.util.isLaterVersion
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.removeAmountIf
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
@@ -102,35 +115,31 @@ import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.io.PrintWriter
import java.util.UUID
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import net.minecraft.client.MinecraftClient
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer
import net.minecraft.entity.data.TrackedDataHandlerRegistry
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
import org.apache.logging.log4j.Logger
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.util.*
import kotlin.collections.filterIsInstance
import kotlin.collections.forEach
import kotlin.collections.listOf
import kotlin.collections.set
import kotlin.math.roundToInt
import kotlin.properties.Delegates
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
object Cobblemon {
const val MODID = "cobblemon"
const val VERSION = "1.4.0"
const val CONFIG_PATH = "config/$MODID/main.json"
val LOGGER: Logger = LogManager.getLogger()
val LOGGER = LogManager.getLogger()
lateinit var implementation: CobblemonImplementation
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
@@ -152,6 +161,7 @@ object Cobblemon {
var storage = PokemonStoreManager()
var molangData = NbtMoLangDataStoreFactory
lateinit var playerData: PlayerDataStoreManager
lateinit var starterConfig: StarterConfig
val dataProvider: DataProvider = CobblemonDataProvider
var permissionValidator: PermissionValidator by Delegates.observable(LaxPermissionValidator().also { it.initialize() }) { _, _, newValue -> newValue.initialize() }
var statProvider: StatProvider = CobblemonStatProvider
@@ -159,14 +169,6 @@ object Cobblemon {
fun preInitialize(implementation: CobblemonImplementation) {
this.implementation = implementation
this.LOGGER.info("Launching Cobblemon ${CobblemonBuildDetails.VERSION}${if(CobblemonBuildDetails.SNAPSHOT) "-SNAPSHOT" else ""} ")
if(CobblemonBuildDetails.SNAPSHOT) {
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
this.LOGGER.info(" - Timestamp: ${CobblemonBuildDetails.TIMESTAMP}")
}
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerBlocks()
@@ -229,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() }
}
@@ -241,16 +240,6 @@ object Cobblemon {
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
// Lowest priority because this applies after luxury ball bonus as of gen 4
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
// Our Luxury ball spec is diff from official, but we will still assume these stack
if (event.pokemon.heldItemNoCopy().isIn(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
increment += increment * 0.5F
}
event.newFriendship = event.pokemon.friendship + increment.roundToInt()
}
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
@@ -462,6 +451,27 @@ object Cobblemon {
this.saveConfig()
bestSpawner.loadConfig()
PokemonSpecies.observable.subscribe { starterConfig = this.loadStarterConfig() }
}
fun loadStarterConfig(): StarterConfig {
if (config.exportStarterConfig) {
val file = File("config/cobblemon/starters.json")
file.parentFile.mkdirs()
if (!file.exists()) {
val config = StarterConfig()
val pw = PrintWriter(file)
StarterConfig.GSON.toJson(config, pw)
pw.close()
return config
}
val reader = FileReader(file)
val config = StarterConfig.GSON.fromJson(reader, StarterConfig::class.java)
reader.close()
return config
} else {
return StarterConfig()
}
}
fun saveConfig() {
@@ -17,7 +17,6 @@ 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
@@ -78,9 +77,4 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
CobblemonBlocks.FOSSIL_ANALYZER
).build(null)
)
@JvmField
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
)
}
@@ -72,8 +72,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@JvmField
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
@JvmField
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
@JvmField
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
@JvmField
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
@@ -160,7 +158,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
@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)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
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)
@@ -389,18 +387,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
DisplayCaseBlock(
AbstractBlock.Settings.create()
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
.nonOpaque()
.pistonBehavior(PistonBehavior.BLOCK)
.mapColor(MapColor.STONE_GRAY)
.strength(0.3f)
)
)
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@JvmField
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
@@ -428,7 +414,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
)
@JvmField
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.VIVICHOKE_SOUNDS)))
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
@JvmField
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(StatusEffects.LEVITATION, 10, AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().breakInstantly().sounds(BlockSoundGroup.GRASS).offset(AbstractBlock.OffsetType.XZ).pistonBehavior(PistonBehavior.DESTROY)))
@JvmField
@@ -48,9 +48,5 @@ object CobblemonCommands {
PokemonRestartCommand.register(dispatcher)
BedrockParticleCommand.register(dispatcher)
OpenDialogueCommand.register(dispatcher)
// Possibly lock down registration if and only if under dev environment or running in an environment
// with a certain system environment variable set
CobblemonInfoCommand.register(dispatcher)
}
}
@@ -8,7 +8,6 @@
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
@@ -30,8 +29,6 @@ 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.PotionItem
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
@@ -40,7 +37,14 @@ import net.minecraft.block.Block
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.effect.StatusEffectInstance
import net.minecraft.entity.effect.StatusEffects
import net.minecraft.item.*
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.registry.Registries
import net.minecraft.registry.Registry
import net.minecraft.registry.RegistryKey
@@ -254,8 +258,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -283,8 +285,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
@@ -408,7 +408,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
@JvmField
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())), "leek")
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
@JvmField
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
@JvmField
@@ -558,11 +558,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
*/
@@ -583,8 +578,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val SUN_STONE_ORE = blockItem("sun_stone_ore", CobblemonBlocks.SUN_STONE_ORE)
@JvmField
val TERRACOTTA_SUN_STONE_ORE = blockItem("terracotta_sun_stone_ore", CobblemonBlocks.TERRACOTTA_SUN_STONE_ORE)
@JvmField
val THUNDER_STONE_ORE = blockItem("thunder_stone_ore", CobblemonBlocks.THUNDER_STONE_ORE)
@JvmField
val WATER_STONE_ORE = blockItem("water_stone_ore", CobblemonBlocks.WATER_STONE_ORE)
@@ -636,28 +629,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
// Held Items
@JvmField
val ABILITY_SHIELD = heldItem("ability_shield")
@JvmField
val ABSORB_BULB = heldItem("absorb_bulb")
@JvmField
val AIR_BALLOON = heldItem("air_balloon")
@JvmField
val ASSAULT_VEST = heldItem("assault_vest")
@JvmField
val BIG_ROOT = blockItem("big_root", CobblemonBlocks.BIG_ROOT)
@JvmField
val BINDING_BAND = heldItem("binding_band")
@JvmField
val BLACK_BELT = heldItem("black_belt")
@JvmField
val BLACK_GLASSES = heldItem("black_glasses")
@JvmField
val BLACK_SLUDGE = heldItem("black_sludge")
@JvmField
val BLUNDER_POLICY = heldItem("blunder_policy")
@JvmField
val CELL_BATTERY = heldItem("cell_battery")
@JvmField
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
@JvmField
val CHOICE_BAND = heldItem("choice_band")
@@ -668,64 +649,26 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val CLEANSE_TAG = heldItem("cleanse_tag")
@JvmField
val CLEAR_AMULET = heldItem("clear_amulet")
@JvmField
val COVERT_CLOAK = heldItem("covert_cloak")
@JvmField
val DESTINY_KNOT = heldItem("destiny_knot")
@JvmField
val DRAGON_FANG = heldItem("dragon_fang")
@JvmField
val EJECT_BUTTON = heldItem("eject_button")
@JvmField
val EJECT_PACK = heldItem("eject_pack")
@JvmField
val EVERSTONE = heldItem("everstone")
@JvmField
val EVIOLITE = heldItem("eviolite")
@JvmField
val EXP_SHARE = heldItem("exp_share")
@JvmField
val EXPERT_BELT = heldItem("expert_belt")
@JvmField
val FAIRY_FEATHER = heldItem("fairy_feather")
@JvmField
val FLAME_ORB = heldItem("flame_orb")
@JvmField
val FLOAT_STONE = heldItem("float_stone")
@JvmField
val FOCUS_BAND = heldItem("focus_band")
@JvmField
val FOCUS_SASH = heldItem("focus_sash")
@JvmField
val GRIP_CLAW = heldItem("grip_claw")
@JvmField
val HARD_STONE = heldItem("hard_stone")
@JvmField
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
@JvmField
val IRON_BALL = heldItem("iron_ball")
@JvmField
val LAGGING_TAIL = heldItem("lagging_tail")
@JvmField
val LEFTOVERS = heldItem("leftovers")
@JvmField
val LIFE_ORB = heldItem("life_orb")
@JvmField
val LIGHT_BALL = heldItem("light_ball")
@JvmField
val LIGHT_CLAY = heldItem("light_clay")
@JvmField
val LOADED_DICE = heldItem("loaded_dice")
@JvmField
val LUCKY_EGG = heldItem("lucky_egg")
@JvmField
val LUMINOUS_MOSS = heldItem("luminous_moss")
@JvmField
val MAGNET = heldItem("magnet")
@JvmField
val METRONOME = heldItem("metronome")
@JvmField
val MIRACLE_SEED = heldItem("miracle_seed")
@JvmField
val MUSCLE_BAND = heldItem("muscle_band")
@@ -736,42 +679,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val POISON_BARB = heldItem("poison_barb")
@JvmField
val POWER_ANKLET = heldItem("power_anklet")
@JvmField
val POWER_BAND = heldItem("power_band")
@JvmField
val POWER_BELT = heldItem("power_belt")
@JvmField
val POWER_BRACER = heldItem("power_bracer")
@JvmField
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val PROTECTIVE_PADS = heldItem("protective_pads")
@JvmField
val PUNCHING_GLOVE = heldItem("punching_glove")
@JvmField
val QUICK_CLAW = heldItem("quick_claw")
@JvmField
val RED_CARD = heldItem("red_card")
@JvmField
val RING_TARGET = heldItem("ring_target")
@JvmField
val ROCKY_HELMET = heldItem("rocky_helmet")
@JvmField
val ROOM_SERVICE = heldItem("room_service")
@JvmField
val SAFETY_GOGGLES = heldItem("safety_goggles")
@JvmField
val SCOPE_LENS = heldItem("scope_lens")
@JvmField
val SHARP_BEAK = heldItem("sharp_beak")
@JvmField
val SHED_SHELL = heldItem("shed_shell")
@JvmField
val SHELL_BELL = heldItem("shell_bell")
@JvmField
val SILK_SCARF = heldItem("silk_scarf")
@JvmField
val SILVER_POWDER = heldItem("silver_powder")
@@ -780,30 +695,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val SPELL_TAG = heldItem("spell_tag")
@JvmField
val SMOKE_BALL = heldItem("smoke_ball")
@JvmField
val SOOTHE_BELL = heldItem("soothe_bell")
@JvmField
val STICKY_BARB = heldItem("sticky_barb")
@JvmField
val TERRAIN_EXTENDER = heldItem("terrain_extender")
@JvmField
val THROAT_SPRAY = heldItem("throat_spray")
@JvmField
val TOXIC_ORB = heldItem("toxic_orb")
@JvmField
val TWISTED_SPOON = heldItem("twisted_spoon")
@JvmField
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
@JvmField
val WEAKNESS_POLICY = heldItem("weakness_policy")
@JvmField
val WIDE_LENS = heldItem("wide_lens")
@JvmField
val WISE_GLASSES = heldItem("wise_glasses")
@JvmField
val ZOOM_LENS = heldItem("zoom_lens")
@JvmField
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
@JvmField
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
@@ -818,13 +713,29 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
@JvmField
val QUICK_POWDER = heldItem("quick_powder")
@JvmField
val DAMP_ROCK = heldItem("damp_rock")
val DESTINY_KNOT = heldItem("destiny_knot")
@JvmField
val HEAT_ROCK = heldItem("heat_rock")
val EVERSTONE = heldItem("everstone")
@JvmField
val SMOOTH_ROCK = heldItem("smooth_rock")
val POWER_ANKLET = heldItem("power_anklet")
@JvmField
val ICY_ROCK = heldItem("icy_rock")
val POWER_BAND = heldItem("power_band")
@JvmField
val POWER_BELT = heldItem("power_belt")
@JvmField
val POWER_BRACER = heldItem("power_bracer")
@JvmField
val POWER_LENS = heldItem("power_lens")
@JvmField
val POWER_WEIGHT = heldItem("power_weight")
@JvmField
val 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
@@ -1011,16 +922,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
}
}
)
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
name = name,
entry = item.also {
if (remappedName != null) {
CobblemonHeldItemManager.registerRemap(it, remappedName)
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
}
}
)
private fun compostable(item: Item, increaseLevelChance: Float) = Cobblemon.implementation.registerCompostable(item, increaseLevelChance)
@@ -135,6 +135,7 @@ 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.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
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
@@ -170,6 +171,7 @@ 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.FleeBattlePacketHandler
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
@@ -407,6 +409,7 @@ object CobblemonNetwork : NetworkManager {
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
this.createServerBound(FleeBattlePacket.ID, FleeBattlePacket::decode, FleeBattlePacketHandler)
// Trade
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
@@ -99,27 +99,27 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
val MULCH_REMOVE = this.create("mulch.remove")
@JvmField
val FOSSIL_MACHINE_ACTIVATE = this.create("fossil_machine.activate")
val FOSSIL_MACHINE_ACTIVATE = this.create("fossilmachine.activate")
@JvmField
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossil_machine.active_loop")
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossilmachine.active_loop")
@JvmField
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossil_machine.assemble")
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossilmachine.assemble")
@JvmField
val FOSSIL_MACHINE_DNA_FULL = this.create("fossil_machine.dna_full")
val FOSSIL_MACHINE_DNA_FULL = this.create("fossilmachine.dna_full")
@JvmField
val FOSSIL_MACHINE_FINISHED = this.create("fossil_machine.finished")
val FOSSIL_MACHINE_FINISHED = this.create("fossilmachine.finished")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossil_machine.insert_dna")
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossilmachine.insert_dna")
@JvmField
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossil_machine.insert_dna_small")
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossilmachine.insert_dna_small")
@JvmField
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossil_machine.insert_fossil")
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossilmachine.insert_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossil_machine.retrieve_fossil")
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossilmachine.retrieve_fossil")
@JvmField
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossil_machine.retrieve_pokemon")
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossilmachine.retrieve_pokemon")
@JvmField
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
@JvmField
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
@@ -155,21 +155,11 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
@JvmField
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
@JvmField
val VIVICHOKE_BREAK = this.create("vivichoke.break")
@JvmField
val VIVICHOKE_PLACE = this.create("vivichoke.place")
@JvmField
val MINT_BREAK = this.create("mint.break")
@JvmField
val MINT_PLACE = this.create("mint.place")
@JvmField
val REVIVAL_HERB_BREAK = this.create("revival_herb.break")
@JvmField
val REVIVAL_HERB_PLACE = this.create("revival_herb.place")
@JvmField
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
@JvmField
@@ -287,15 +277,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val VIVICHOKE_SOUNDS = BlockSoundGroup(1f, 1f,
VIVICHOKE_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
VIVICHOKE_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
MINT_BREAK,
@@ -305,15 +286,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val REVIVAL_HERB_SOUNDS = BlockSoundGroup(1f, 1f,
REVIVAL_HERB_BREAK,
SoundEvents.BLOCK_GRASS_STEP,
REVIVAL_HERB_PLACE,
SoundEvents.BLOCK_GRASS_HIT,
SoundEvents.BLOCK_GRASS_FALL
)
@JvmField
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
GILDED_CHEST_BREAK,
@@ -323,27 +295,5 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
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)))
}
@@ -113,14 +113,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)
}
@@ -1,52 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.advancement.criterion
import com.cobblemon.mod.common.block.TumblestoneBlock
import com.google.gson.JsonObject
import net.minecraft.predicate.entity.LootContextPredicate
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
import net.minecraft.util.math.BlockPos
/**
* A criterion condition for when a tumblestone block is planted
* @param id The identifier of the criterion
* @param predicate The predicate for the criterion
*
* @author Aethen
* @since 02/28/2024
*/
class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
override fun toJson(json: JsonObject) {
// Add properties to json if needed. None needed for this criterion
}
override fun fromJson(json: JsonObject) {
// Parse properties from json if needed. None needed for this criterion
}
/**
* Checks if the tumblestone block can grow at the given position
* @param player The player that planted the tumblestone block
* @param context The context of the criterion
* @return True if the tumblestone block can grow at the given position, false otherwise
*/
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
return context.tumbleStoneBlock.canGrow(context.pos, player.world)
}
}
/**
* The context of the [PlantTumblestoneCriterionCondition]
* @param pos The position of the tumblestone block
* @param tumbleStoneBlock The tumblestone block
*/
open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.abilities
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.DataKeys
import com.google.gson.JsonObject
import net.minecraft.nbt.NbtCompound
@@ -22,7 +21,7 @@ import net.minecraft.nbt.NbtCompound
* @author Qu
* @since January 9th, 2022
*/
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
val name: String
get() = template.name
@@ -35,26 +34,16 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
/**
* This represents the last known index of this backing ability in the species data.
* @see [Pokemon.updateAbility].
*/
var forced: Boolean = forced
internal set
/**
* This represents the last known index of this backing ability in the species data.
*
* @see [Pokemon.updateAbility].
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
* The value can be mutated however this is not recommended by API users.
*/
var index: Int = -1
internal set
/**
* The last known priority of this ability in the species data.
*
* @see [Pokemon.updateAbility].
* The value can be mutated however this is not recommended by API users.
*/
var priority = Priority.LOWEST
internal set
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
@@ -73,23 +62,19 @@ open class Ability internal constructor(var template: AbilityTemplate, forced: B
}
open fun loadFromNBT(nbt: NbtCompound): Ability {
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
}
return this
}
open fun loadFromJSON(json: JsonObject): Ability {
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
}
return this
}
}
@@ -28,6 +28,7 @@ class AbilityTemplate(
*/
fun create(forced: Boolean = false) = builder(this, forced)
/**
* Returns the Ability and loads the given NBT Tag into it.
*
@@ -41,5 +42,4 @@ class AbilityTemplate(
* Ability extensions need to write and read their needed data from here.
*/
fun create(json: JsonObject) = create().loadFromJSON(json)
}
@@ -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 }
}
}
@@ -35,8 +35,8 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
itemStack: ItemStack?
) {
if (world is ServerWorld) {
val multiblockEntity = world.getBlockEntity(pos) as? MultiblockEntity
multiblockEntity?.multiblockBuilder?.validate(world)
val multiblockEntity = world.getBlockEntity(pos) as MultiblockEntity
multiblockEntity.multiblockBuilder?.validate(world)
}
super.onPlaced(world, pos, state, placer, itemStack)
}
@@ -52,8 +52,8 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
if(hand == Hand.OFF_HAND) {
return ActionResult.SUCCESS
}
val entity = world.getBlockEntity(pos) as MultiblockEntity?
if (entity?.multiblockStructure != null) {
val entity = world.getBlockEntity(pos) as MultiblockEntity
if (entity.multiblockStructure != null) {
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
}
return super.onUse(state, world, pos, player, hand, hit)
@@ -205,8 +205,8 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
// Luxury ball effect
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOWEST) { event ->
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
if (increment <= 1F) {
event.pokemon.caughtBall.effects.filterIsInstance<FriendshipEarningBoostEffect>()
@@ -13,14 +13,12 @@ import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.abilities.Ability
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.pokemon.status.Statuses
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.api.types.tera.TeraTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.*
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
@@ -296,18 +294,6 @@ open class PokemonProperties {
)
fun apply(pokemon: Pokemon) {
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
this.customProperties.forEach { it.apply(pokemon) }
this.commonApply(pokemon)
}
fun apply(pokemonEntity: PokemonEntity) {
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
this.customProperties.forEach { it.apply(pokemonEntity) }
this.commonApply(pokemonEntity.pokemon)
}
private fun commonApply(pokemon: Pokemon) {
species?.let {
return@let try {
if (it == "random") {
@@ -327,8 +313,8 @@ open class PokemonProperties {
friendship?.let { pokemon.setFriendship(it) }
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
ability?.let { this.createAbility(it, pokemon.form)?.let(pokemon::updateAbility) }
status?.let { Statuses.getStatus(it)?.let { status -> if (status is PersistentStatus) pokemon.applyStatus(status) } }
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemon.ability = ability } }
status?.let { Statuses.getStatus(it)?.let { pokemon.applyStatus(it as PersistentStatus) } }
customProperties.forEach { it.apply(pokemon) }
ivs?.let { ivs ->
ivs.forEach { stat ->
@@ -340,7 +326,7 @@ open class PokemonProperties {
pokemon.setEV(stat.key, stat.value)
}
}
teraType?.let { TeraTypes.get(it.asIdentifierDefaultingNamespace())?.let { type -> pokemon.teraType = type } }
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemon.teraType = type } }
dmaxLevel?.let { pokemon.dmaxLevel = it }
gmaxFactor?.let { pokemon.gmaxFactor = it }
tradeable?.let { pokemon.tradeable = it }
@@ -369,17 +355,69 @@ open class PokemonProperties {
pokemon.updateAspects()
}
fun apply(pokemonEntity: PokemonEntity) {
species?.let {
return@let try {
if (it == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace())
}
} catch (e: InvalidIdentifierException) {
null
}
}?.let { pokemonEntity.pokemon.species = it }
nickname?.let { pokemonEntity.pokemon.nickname = it }
form?.let { formID -> pokemonEntity.pokemon.species.forms.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }?.let { form -> pokemonEntity.pokemon.form = form }
level?.let { pokemonEntity.pokemon.level = it }
shiny?.let { pokemonEntity.pokemon.shiny = it }
gender?.let { pokemonEntity.pokemon.gender = it }
friendship?.let { pokemonEntity.pokemon.setFriendship(it) }
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemonEntity.pokemon.caughtBall = pokeball } }
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemonEntity.pokemon.nature = nature } }
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemonEntity.pokemon.ability = ability } }
status?.let { Statuses.getStatus(it)?.let { pokemonEntity.pokemon.applyStatus(it as PersistentStatus) } }
customProperties.forEach { it.apply(pokemonEntity) }
ivs?.let { ivs ->
ivs.forEach { stat ->
pokemonEntity.pokemon.setIV(stat.key, stat.value)
}
}
evs?.let { evs ->
evs.forEach { stat ->
pokemonEntity.pokemon.setEV(stat.key, stat.value)
}
}
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemonEntity.pokemon.teraType = type } }
dmaxLevel?.let { pokemonEntity.pokemon.dmaxLevel = it }
gmaxFactor?.let { pokemonEntity.pokemon.gmaxFactor = it }
tradeable?.let { pokemonEntity.pokemon.tradeable = it }
// If it has been explicitly set to NONE, clear the stored information, including the originalTrainer property
originalTrainerType?.let {
if (it == OriginalTrainerType.NONE) {
pokemonEntity.pokemon.removeOriginalTrainer()
originalTrainer = null
}
}
originalTrainer?.let { ot ->
val type = originalTrainerType ?: pokemonEntity.pokemon.originalTrainerType
when (type) {
OriginalTrainerType.PLAYER -> {
when (ot.length) {
in 3..16 -> server()?.userCache?.findByName(ot)?.get()?.id // OT is a Username
36 -> UUID.fromString(ot) // OT is a UUID
else -> null // OT is invalid
}?.let { uuid -> pokemonEntity.pokemon.setOriginalTrainer(uuid) }
}
OriginalTrainerType.NPC -> pokemonEntity.pokemon.setOriginalTrainer(ot)
else -> {}
}
pokemonEntity.pokemon.refreshOriginalTrainer()
}
pokemonEntity.pokemon.updateAspects()
}
fun matches(pokemon: Pokemon): Boolean {
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
return this.commonMatches(pokemon) && this.customProperties.none { !it.matches(pokemon) }
}
fun matches(pokemonEntity: PokemonEntity): Boolean {
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
return this.commonMatches(pokemonEntity.pokemon) && this.customProperties.none { !it.matches(pokemonEntity) }
}
private fun commonMatches(pokemon: Pokemon): Boolean {
level?.takeIf { it != pokemon.level }?.let { return false }
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
gender?.takeIf { it != pokemon.gender }?.let { return false }
@@ -397,7 +435,7 @@ open class PokemonProperties {
return false
}
}
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
nickname?.takeIf { it != pokemon.nickname }?.let { return false }
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
@@ -410,23 +448,59 @@ open class PokemonProperties {
evs?.forEach{ stat ->
if (stat.value != pokemon.evs[stat.key]) { return false }
}
teraType?.takeIf { it.asIdentifierDefaultingNamespace() != pokemon.teraType.id }?.let { return false }
teraType?.takeIf { it != pokemon.teraType.name }?.let { return false }
dmaxLevel?.takeIf { it != pokemon.dmaxLevel }?.let { return false }
gmaxFactor?.takeIf { it != pokemon.gmaxFactor }?.let { return false }
tradeable?.takeIf { it != pokemon.tradeable }?.let { return false }
originalTrainer?.takeIf { it != pokemon.originalTrainer }?.let{ return false }
originalTrainerType?.takeIf { it != pokemon.originalTrainerType }?.let{ return false }
return true
return customProperties.none { !it.matches(pokemon) }
}
fun matches(pokemonEntity: PokemonEntity): Boolean {
level?.takeIf { it != pokemonEntity.pokemon.level }?.let { return false }
shiny?.takeIf { it != ("shiny" in pokemonEntity.pokemon.aspects) }?.let { return false }
gender?.takeIf { it != pokemonEntity.pokemon.gender }?.let { return false }
species?.run {
try {
val species = if (this == "random") {
PokemonSpecies.species.random()
} else {
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
}
if (pokemonEntity.pokemon.species != species) {
return false
}
} catch (e: InvalidIdentifierException) {}
}
nickname?.takeIf { it != pokemonEntity.pokemon.nickname }?.let { return false }
form?.takeIf { !it.equals(pokemonEntity.pokemon.form.name, true) }?.let { return false }
friendship?.takeIf { it != pokemonEntity.pokemon.friendship }?.let { return false }
pokeball?.takeIf { it != pokemonEntity.pokemon.caughtBall.name.toString() }?.let { return false }
nature?.takeIf { it != pokemonEntity.pokemon.nature.name.toString() }?.let { return false }
ability?.takeIf { it != pokemonEntity.pokemon.ability.name }?.let { return false }
status?.takeIf { it != pokemonEntity.pokemon.status?.status?.showdownName }?.let { return false }
ivs?.forEach{ stat ->
if (stat.value != pokemonEntity.pokemon.ivs[stat.key]) { return false }
}
evs?.forEach{ stat ->
if (stat.value != pokemonEntity.pokemon.evs[stat.key]) { return false }
}
teraType?.takeIf { it != pokemonEntity.pokemon.teraType.name }?.let { return false }
dmaxLevel?.takeIf { it != pokemonEntity.pokemon.dmaxLevel }?.let { return false }
gmaxFactor?.takeIf { it != pokemonEntity.pokemon.gmaxFactor }?.let { return false }
tradeable?.takeIf { it != pokemonEntity.pokemon.tradeable }?.let { return false }
originalTrainer?.takeIf { it != pokemonEntity.pokemon.originalTrainer }?.let{ return false }
originalTrainerType?.takeIf { it != pokemonEntity.pokemon.originalTrainerType }?.let{ return false }
return customProperties.none { !it.matches(pokemonEntity) }
}
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
fun isSubSetOf(properties: PokemonProperties): Boolean {
level?.takeIf { it != properties.level }?.let { return false }
shiny?.takeIf { it != ("shiny" in properties.aspects) }?.let { return false }
gender?.takeIf { it != properties.gender }?.let { return false }
species?.run {
try {
// TODO get context on this bit, it's highly unlikely two randoms would result in the same Pokémon, doesn't mean the prop is not equal?
val species = if (this == "random") {
PokemonSpecies.species.random()
} else {
@@ -435,9 +509,9 @@ open class PokemonProperties {
if (properties.species != species.toString()) {
return false
}
} catch (_: InvalidIdentifierException) {}
} catch (e: InvalidIdentifierException) {}
}
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
nickname?.takeIf { it != properties.nickname }?.let { return false }
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
friendship?.takeIf { it != properties.friendship }?.let { return false }
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
@@ -477,18 +551,20 @@ open class PokemonProperties {
// TEST YOUR LUCK!
fun roll(pokemon: Pokemon) {
val baseTypes = pokemon.form.types.toList()
val baseTypes = pokemon.species.types.toList()
if (this.shiny == null) pokemon.shiny = Cobblemon.config.shinyRate.checkRate()
if (this.teraType == null) pokemon.teraType =
if (Cobblemon.config.teraTypeRate.checkRate()) TeraTypes.random(true)
else TeraTypes.forElementalType(baseTypes.random())
if (Cobblemon.config.teraTypeRate.checkRate()) ElementalTypes.all().filter { !baseTypes.contains(it) }.random()
else baseTypes.random()
}
// If the config value is at least 1, then do 1/x and use that as the property chance
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
fun createEntity(world: World): PokemonEntity {
return PokemonEntity(world, create())
}
// TODO Codecs at some point
fun saveToNBT(): NbtCompound {
val nbt = NbtCompound()
originalString.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
@@ -517,7 +593,6 @@ open class PokemonProperties {
return nbt
}
// TODO Codecs at some point
fun loadFromNBT(tag: NbtCompound): PokemonProperties {
originalString = tag.getString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)
level = if (tag.contains(DataKeys.POKEMON_LEVEL)) tag.getInt(DataKeys.POKEMON_LEVEL) else null
@@ -546,7 +621,6 @@ open class PokemonProperties {
return this
}
// TODO Codecs at some point
fun saveToJSON(): JsonObject {
val json = JsonObject()
originalString.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
@@ -576,7 +650,6 @@ open class PokemonProperties {
return json
}
// TODO Codecs at some point
fun loadFromJSON(json: JsonObject): PokemonProperties {
originalString = json.get(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)?.asString ?: ""
level = json.get(DataKeys.POKEMON_LEVEL)?.asInt
@@ -654,21 +727,4 @@ open class PokemonProperties {
fun copy(): PokemonProperties {
return PokemonProperties().loadFromJSON(saveToJSON())
}
// If the config value is at least 1, then do 1/x and use that as the property chance
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
/**
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
*
* @param id The literal ID of the [Ability] being mapped.
* @param form The [FormData] whose [FormData.abilities] is queried for legality.
* @return The [Ability] with the [Ability.forced] state necessary for the given [form].
*/
private fun createAbility(id: String, form: FormData): Ability? {
val ability = Abilities.get(id) ?: return null
val potentialAbility = form.abilities.firstOrNull { potential -> potential.template == ability } ?: return ability.create(true)
return potentialAbility.template.create(false)
}
}
@@ -20,6 +20,7 @@ import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* Effect details for the actual particles of a particle effect.
@@ -43,106 +44,48 @@ class BedrockParticle(
var cameraMode: ParticleCameraMode = RotateXYZCameraMode(),
var tinting: ParticleTinting = ExpressionParticleTinting(),
var collision: ParticleCollision = ParticleCollision(),
var environmentLighting: Boolean = false,
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
var timeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf())
var environmentLighting: Boolean = false
) {
class ExpressionSet(
val sizeX: Expression,
val sizeY: Expression,
val maxAge: Expression,
val killExpression: Expression,
val updateExpressions: MutableList<Expression>,
val renderExpressions: MutableList<Expression>
)
/*
"creation_event": "event_sendspark",
"expiration_event": ["event_spark", "event_afterspark", "event_capturestar"],
"timeline": {
"21.00": "event_spark"
}
*/
class EventSet(
val creationEvents: MutableList<SimpleEventTrigger>,
val expirationEvents: MutableList<SimpleEventTrigger>,
val timeline: EventTriggerTimeline
)
// kill plane maybe
companion object {
val EXPRESSION_SET_CODEC = RecordCodecBuilder.create<ExpressionSet> { instance ->
instance.group(
EXPRESSION_CODEC.fieldOf("sizeX").forGetter { it.sizeX },
EXPRESSION_CODEC.fieldOf("sizeY").forGetter { it.sizeY },
EXPRESSION_CODEC.fieldOf("maxAge").forGetter { it.maxAge },
EXPRESSION_CODEC.fieldOf("killExpression").forGetter { it.killExpression },
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions }
).apply(instance, ::ExpressionSet)
}
val EVENT_SET_CODEC = RecordCodecBuilder.create<EventSet> { instance ->
instance.group(
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
EventTriggerTimeline.CODEC.fieldOf("timeline").forGetter { it.timeline }
).apply(instance, ::EventSet)
}
val CODEC: Codec<BedrockParticle> = RecordCodecBuilder.create { instance ->
instance.group(
Identifier.CODEC.fieldOf("texture").forGetter { it.texture },
PrimitiveCodec.STRING.fieldOf("material").forGetter { it.material.name },
ParticleUVMode.codec.fieldOf("uvMode").forGetter { it.uvMode },
EXPRESSION_SET_CODEC.fieldOf("expressionSet").forGetter {
ExpressionSet(
it.sizeX,
it.sizeY,
it.maxAge,
it.killExpression,
it.updateExpressions,
it.renderExpressions
)
},
EXPRESSION_CODEC.fieldOf("sizeX").forGetter { it.sizeX },
EXPRESSION_CODEC.fieldOf("sizeY").forGetter { it.sizeY },
EXPRESSION_CODEC.fieldOf("maxAge").forGetter { it.maxAge },
EXPRESSION_CODEC.fieldOf("killExpression").forGetter { it.killExpression },
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions },
ParticleMotion.codec.fieldOf("motion").forGetter { it.motion },
ParticleRotation.codec.fieldOf("rotation").forGetter { it.rotation },
ParticleViewDirection.codec.fieldOf("viewDirection").forGetter { it.viewDirection },
ParticleCameraMode.codec.fieldOf("cameraMode").forGetter { it.cameraMode },
ParticleTinting.codec.fieldOf("tinting").forGetter { it.tinting },
ParticleCollision.CODEC.fieldOf("collision").forGetter { it.collision },
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting },
EVENT_SET_CODEC.fieldOf("eventSet").forGetter {
EventSet(
it.creationEvents,
it.expirationEvents,
it.timeline
)
}
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting }
).apply(instance) {
texture, materialStr, uvMode, expressionSet, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting, eventSet ->
texture, materialStr, uvMode, sizeX, sizeY, maxAge, killExpression, updateExpressions,
renderExpressions, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting ->
BedrockParticle(
texture = texture,
material = ParticleMaterial.valueOf(materialStr),
uvMode = uvMode,
sizeX = expressionSet.sizeX,
sizeY = expressionSet.sizeY,
maxAge = expressionSet.maxAge,
killExpression = expressionSet.killExpression,
updateExpressions = expressionSet.updateExpressions,
renderExpressions = expressionSet.renderExpressions,
sizeX = sizeX,
sizeY = sizeY,
maxAge = maxAge,
killExpression = killExpression,
updateExpressions = updateExpressions,
renderExpressions = renderExpressions,
motion = motion,
rotation = rotation,
viewDirection = viewDirection,
cameraMode = cameraMode,
tinting = tinting,
collision = collision,
environmentLighting = environmentLighting,
creationEvents = eventSet.creationEvents,
expirationEvents = eventSet.expirationEvents,
timeline = eventSet.timeline
environmentLighting = environmentLighting
)
}
}
@@ -165,9 +108,6 @@ class BedrockParticle(
ParticleTinting.writeToBuffer(buffer, tinting)
collision.writeToBuffer(buffer)
buffer.writeBoolean(environmentLighting)
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
timeline.encode(buffer)
}
fun readFromBuffer(buffer: PacketByteBuf) {
@@ -187,8 +127,5 @@ class BedrockParticle(
tinting = ParticleTinting.readFromBuffer(buffer)
collision.readFromBuffer(buffer)
environmentLighting = buffer.readBoolean()
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
timeline.decode(buffer)
}
}
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.snowstorm
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import com.mojang.serialization.codecs.UnboundedMapCodec
import net.minecraft.network.PacketByteBuf
import net.minecraft.util.Identifier
@@ -29,8 +27,7 @@ class BedrockParticleEffect(
var emitter: BedrockParticleEmitter = BedrockParticleEmitter(),
var particle: BedrockParticle = BedrockParticle(),
var curves: MutableList<MoLangCurve> = mutableListOf(),
var space: ParticleSpace = ParticleSpace(),
var events: MutableMap<String, ParticleEvent> = mutableMapOf()
var space: ParticleSpace = ParticleSpace()
) {
companion object {
val CODEC: Codec<BedrockParticleEffect> = RecordCodecBuilder.create { instance ->
@@ -39,16 +36,14 @@ class BedrockParticleEffect(
BedrockParticleEmitter.CODEC.fieldOf("emitter").forGetter { it.emitter },
BedrockParticle.CODEC.fieldOf("particle").forGetter { it.particle },
ListCodec(MoLangCurve.codec).fieldOf("curves").forGetter { it.curves },
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space },
UnboundedMapCodec(PrimitiveCodec.STRING, ParticleEvent.CODEC).fieldOf("events").forGetter { it.events }
).apply(instance) { id, emitter, particle, curves, space, events ->
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space }
).apply(instance) { id, emitter, particle, curves, space ->
BedrockParticleEffect(
id = id,
emitter = emitter,
particle = particle,
curves = curves.toMutableList(),
space = space,
events = events
space = space
)
}
}
@@ -60,7 +55,6 @@ class BedrockParticleEffect(
particle.writeToBuffer(buffer)
buffer.writeCollection(curves) { pb, curve -> MoLangCurve.writeToBuffer(buffer, curve) }
space.writeToBuffer(buffer)
buffer.writeMap(events, { _, v -> buffer.writeString(v) }) { _, event -> event.encode(buffer) }
}
fun readFromBuffer(buffer: PacketByteBuf) {
@@ -69,6 +63,5 @@ class BedrockParticleEffect(
particle.readFromBuffer(buffer)
curves = buffer.readList { MoLangCurve.readFromBuffer(buffer) }
space.readFromBuffer(buffer)
events = buffer.readMap({ buffer.readString() }) { ParticleEvent().also { it.decode(buffer) } }
}
}
@@ -29,12 +29,7 @@ class BedrockParticleEmitter(
var updateExpressions: MutableList<Expression> = mutableListOf(),
var rate: ParticleEmitterRate = InstantParticleEmitterRate(),
var shape: ParticleEmitterShape = SphereParticleEmitterShape(),
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0)),
var eventTimeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
var travelDistanceEvents: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
var loopingTravelDistanceEvents: MutableList<LoopingTravelDistanceEventTrigger> = mutableListOf()
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0))
) {
companion object {
val CODEC: Codec<BedrockParticleEmitter> = RecordCodecBuilder.create { instance ->
@@ -43,24 +38,14 @@ class BedrockParticleEmitter(
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
ParticleEmitterRate.codec.fieldOf("rate").forGetter { it.rate },
ParticleEmitterShape.codec.fieldOf("shape").forGetter { it.shape },
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime },
EventTriggerTimeline.CODEC.fieldOf("eventTimeline").forGetter { it.eventTimeline },
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
EventTriggerTimeline.CODEC.fieldOf("travelDistanceEvents").forGetter { it.travelDistanceEvents },
ListCodec(LoopingTravelDistanceEventTrigger.CODEC).fieldOf("loopingTravelDistanceEvents").forGetter { it.loopingTravelDistanceEvents }
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime, eventTimeline, creationEvents, expirationEvents, travelDistanceEvents, loopingTravelDistanceEvents ->
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime }
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime ->
BedrockParticleEmitter(
startExpressions = startExpressions,
updateExpressions = updateExpressions,
shape = shape,
rate = rate,
lifetime = lifetime,
eventTimeline = eventTimeline,
creationEvents = creationEvents,
expirationEvents = expirationEvents,
travelDistanceEvents = travelDistanceEvents,
loopingTravelDistanceEvents = loopingTravelDistanceEvents
lifetime = lifetime
)
}
}
@@ -72,11 +57,6 @@ class BedrockParticleEmitter(
ParticleEmitterRate.writeToBuffer(buffer, rate)
ParticleEmitterShape.writeToBuffer(buffer, shape)
ParticleEmitterLifetime.writeToBuffer(buffer, lifetime)
eventTimeline.encode(buffer)
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
travelDistanceEvents.encode(buffer)
buffer.writeCollection(loopingTravelDistanceEvents) { pb, event -> event.encode(pb) }
}
fun readFromBuffer(buffer: PacketByteBuf) {
@@ -85,10 +65,5 @@ class BedrockParticleEmitter(
rate = ParticleEmitterRate.readFromBuffer(buffer)
shape = ParticleEmitterShape.readFromBuffer(buffer)
lifetime = ParticleEmitterLifetime.readFromBuffer(buffer)
eventTimeline.decode(buffer)
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
travelDistanceEvents.decode(buffer)
loopingTravelDistanceEvents = buffer.readList { LoopingTravelDistanceEventTrigger(0.0, mutableListOf()).also { it.decode(buffer) } }
}
}
@@ -136,11 +136,6 @@ class LoopingEmitterLifetime(var activeTime: Expression = 1.0.asExpression(), va
val interval = activeTimeValue + sleepTime
val displacement = emitterAge % interval
runtime.environment.setSimpleVariable("emitter_lifetime", activeTime)
if (emitterAge > activeTimeValue && sleepTime == 0.0) {
return ParticleEmitterAction.STOP
}
return if (displacement < activeTimeValue) {
ParticleEmitterAction.GO
} else {
@@ -145,7 +145,7 @@ class PointParticleEmitterShape(
override val type = ParticleEmitterShapeType.POINT
override fun getNewParticlePosition(runtime: MoLangRuntime, entity: Entity?) = runtime.resolveVec3d(offset)
override fun getCenter(runtime: MoLangRuntime, entity: Entity?): Vec3d {
return Vec3d.ZERO
return getNewParticlePosition(runtime, entity) // Questionable
}
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
@@ -1,174 +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.snowstorm
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.cobblemon.mod.common.util.asExpressionLike
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.network.PacketByteBuf
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent
import net.minecraft.util.Identifier
import net.minecraft.util.math.Vec3d
/**
* An event that can be referenced from various particle event triggers. The events are not necessarily particles,
* but can be combinations of particles, sounds, and MoLang expressions.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class ParticleEvent(
var particleEffect: EventParticleEffect? = null,
var soundEffect: EventSoundEffect? = null,
var expression: ExpressionLike? = null
): Encodable, Decodable {
companion object {
val CODEC: Codec<ParticleEvent> = RecordCodecBuilder.create { instance ->
instance.group(
EventParticleEffect.CODEC.optionalFieldOf("particle_effect", null).forGetter { it.particleEffect },
EventSoundEffect.CODEC.optionalFieldOf("sound_effect", null).forGetter { it.soundEffect },
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
).apply(instance) { particleEffect, soundEffect, expression ->
ParticleEvent(
particleEffect,
soundEffect,
expression?.asExpressionLike()
)
}
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeNullable(particleEffect) { pb, effect ->
pb.writeIdentifier(effect.effect)
pb.writeEnumConstant(effect.type)
pb.writeNullable(effect.expression) { pb, expr -> pb.writeString(expr.toString()) }
}
buffer.writeNullable(soundEffect) { pb, effect -> pb.writeIdentifier(effect.sound) }
buffer.writeNullable(expression) { pb, expr -> pb.writeString(expr.toString()) }
}
override fun decode(buffer: PacketByteBuf) {
particleEffect = buffer.readNullable { pb -> EventParticleEffect(
pb.readIdentifier(),
pb.readEnumConstant(EventParticleEffect.EventParticleType::class.java),
pb.readNullable { pb.readString().asExpressionLike() }
) }
soundEffect = buffer.readNullable { pb -> EventSoundEffect(pb.readIdentifier()) }
expression = buffer.readNullable { pb -> pb.readString().asExpressionLike() }
}
fun run(storm: ParticleStorm, particle: SnowstormParticle?) {
particleEffect?.let { effect ->
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
val rootMatrix = when (effect.type) {
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
EventParticleEffect.EventParticleType.PARTICLE,
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
}
val sourceVelocity = when (effect.type) {
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
}
val newStorm = ParticleStorm(
effect = bedrockParticleEffect,
matrixWrapper = rootMatrix,
world = storm.world,
sourceVelocity = sourceVelocity,
sourceAlive = storm.sourceAlive,
sourceVisible = storm.sourceVisible,
onDespawn = {},
runtime = MoLangRuntime().setup().also { it.environment.structs["query"] = storm.runtime.environment.getQueryStruct() },
entity = storm.entity
)
effect.expression?.resolve(newStorm.runtime)
newStorm.spawn()
}
soundEffect?.let { effect ->
val position = particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())
val world = storm.world
val soundEvent = SoundEvent.of(effect.sound)
world.playSound(position.x, position.y, position.z, soundEvent, SoundCategory.NEUTRAL, 1F, 1F, true)
}
expression?.resolve(storm.runtime)
}
}
/**
* A particle component of a [ParticleEvent]. It contains the effect to play, the spawning type, and a pre-run
* expression to run in the new storm's runtime.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class EventParticleEffect(
val effect: Identifier,
val type: EventParticleType,
val expression: ExpressionLike? = null
) {
companion object {
val CODEC = RecordCodecBuilder.create<EventParticleEffect> { instance ->
instance.group(
Identifier.CODEC.fieldOf("effect").forGetter { it.effect },
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
).apply(instance) { effect, type, expression ->
EventParticleEffect(
effect,
EventParticleType.valueOf(type),
expression?.asExpressionLike()
)
}
}
}
enum class EventParticleType {
EMITTER,
EMITTER_BOUND,
PARTICLE,
PARTICLE_WITH_VELOCITY
}
}
/**
* A simple sound effect component of a [ParticleEvent]. Plays a sound at the particle location, or if run from an
* emitter event, at the emitter's location.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class EventSoundEffect(
val sound: Identifier,
) {
companion object {
val CODEC = RecordCodecBuilder.create<EventSoundEffect> { instance ->
instance.group(
Identifier.CODEC.fieldOf("sound").forGetter { it.sound }
).apply(instance, ::EventSoundEffect)
}
}
}
@@ -1,118 +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.snowstorm
import com.cobblemon.mod.common.api.net.Decodable
import com.cobblemon.mod.common.api.net.Encodable
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import com.mojang.serialization.codecs.UnboundedMapCodec
import net.minecraft.network.PacketByteBuf
/*
* The different references to events that can be triggered by an effect.
*/
/**
* It really is simple.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class SimpleEventTrigger(var event: String): Encodable, Decodable {
companion object {
val CODEC = RecordCodecBuilder.create<SimpleEventTrigger> { instance ->
instance.group(
PrimitiveCodec.STRING.fieldOf("event").forGetter { it.event }
).apply(instance, ::SimpleEventTrigger)
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeString(event)
}
override fun decode(buffer: PacketByteBuf) {
event = buffer.readString()
}
fun trigger(storm: ParticleStorm, particle: SnowstormParticle?) {
val event = storm.effect.events[event] ?: return
event.run(storm, particle)
}
}
/**
* An event trigger that outlines specific times at which point groups of effects will play. This can be used
* on the basis of time but is also used in the case of travel distance.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class EventTriggerTimeline(var map: MutableMap<Double, MutableList<String>>): Encodable, Decodable {
companion object {
val CODEC = RecordCodecBuilder.create<EventTriggerTimeline> { instance ->
instance.group(
UnboundedMapCodec(PrimitiveCodec.DOUBLE, PrimitiveCodec.STRING.listOf()).fieldOf("map").forGetter { it.map }
).apply(instance, ::EventTriggerTimeline)
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeMap(map, { pb, k -> pb.writeDouble(k) }, { pb, v -> pb.writeCollection(v) { _, s -> pb.writeString(s) } })
}
override fun decode(buffer: PacketByteBuf) {
map = buffer.readMap({ pb -> pb.readDouble() }, { pb -> pb.readList { pb.readString() } })
}
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousTime: Double, newTime: Double) {
val events = map.entries.filter { it.key in previousTime..newTime }.flatMap { it.value }
events.forEach { event ->
val event = storm.effect.events[event] ?: return
event.run(storm, particle)
}
}
}
/**
* An event trigger that takes the total distance travelled by the emitter and modulos it across [distance] to know
* if we need to play it again.
*
* @author Hiroku
* @since March 2nd, 2024
*/
class LoopingTravelDistanceEventTrigger(var distance: Double, var events: MutableList<String>): Encodable, Decodable {
companion object {
val CODEC = RecordCodecBuilder.create<LoopingTravelDistanceEventTrigger> { instance ->
instance.group(
PrimitiveCodec.DOUBLE.fieldOf("distance").forGetter { it.distance },
PrimitiveCodec.STRING.listOf().fieldOf("events").forGetter { it.events }
).apply(instance, ::LoopingTravelDistanceEventTrigger)
}
}
override fun encode(buffer: PacketByteBuf) {
buffer.writeDouble(distance)
buffer.writeCollection(events) { _, s -> buffer.writeString(s) }
}
override fun decode(buffer: PacketByteBuf) {
distance = buffer.readDouble()
events = buffer.readList { buffer.readString() }
}
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousDistance: Double, currentDistance: Double) {
if (previousDistance < distance && currentDistance >= distance) {
events.mapNotNull { storm.effect.events[it] }.forEach { it.run(storm, particle) }
}
}
}
@@ -140,7 +140,7 @@ class InwardsMotionDirection : ParticleMotionDirection {
return if (particlePos == emitterPos) {
Vec3d(storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5)
} else {
emitterPos.subtract(particlePos)
particlePos.subtract(emitterPos)
}.normalize()
}
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
@@ -12,8 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import java.util.UUID
import net.minecraft.server.network.ServerPlayerEntity
@@ -36,7 +34,7 @@ object CobblemonWorldSpawnerManager : SpawnerManager() {
fun onPlayerLogin(player: ServerPlayerEntity) {
// Disables spawning
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
if (!Cobblemon.config.enableSpawning) {
return;
}
@@ -12,8 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.TickingSpawner
import com.cobblemon.mod.common.util.server
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules.DO_POKEMON_SPAWNING
/**
* A manager of various spawners. This is a class in which you should register
@@ -51,7 +49,7 @@ open class SpawnerManager {
open fun onServerTick() {
// Disables spawning
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
if (!Cobblemon.config.enableSpawning) {
return
}
influences.removeIf { it.isExpired() }
@@ -30,16 +30,9 @@ abstract class SingleEntitySpawnAction<T : Entity>(
override fun run(): EntitySpawnResult? {
val e = createEntity() ?: return null
e.setPosition(ctx.position.toVec3d().add(0.5, 1.0, 0.5))
var shouldSpawn = false
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = {
ctx.world.spawnEntity(e)
shouldSpawn = true
})
return if (shouldSpawn) {
this.entity.emit(e)
EntitySpawnResult(listOf(e))
} else null
entity.emit(e)
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = { ctx.world.spawnEntity(e) })
return EntitySpawnResult(listOf(e))
}
@@ -63,6 +63,9 @@ abstract class AreaSpawner(
override fun run(cause: SpawnCause): Pair<SpawningContext, SpawnDetail>? {
val area = getArea(cause)
if (area?.world?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
return null
}
val constrainedArea = if (area != null) constrainArea(area) else null
if (constrainedArea != null) {
@@ -8,12 +8,12 @@
package com.cobblemon.mod.common.api.starter
import com.cobblemon.mod.common.config.starter.StarterCategory
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.Identifier
interface StarterHandler {
fun getStarters(player: ServerPlayerEntity): Map<Identifier, StarterCategory>
fun getStarterList(player: ServerPlayerEntity): List<StarterCategory>
fun handleJoin(player: ServerPlayerEntity)
fun requestStarterChoice(player: ServerPlayerEntity)
fun chooseStarter(player: ServerPlayerEntity, categoryId: Identifier, index: Int)
fun chooseStarter(player: ServerPlayerEntity, categoryName: String, index: Int)
}
@@ -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.api.starter
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
import com.cobblemon.mod.common.util.adapters.PlainJsonTextAdapter
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resource.ResourceType
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.Text
import net.minecraft.util.Identifier
/**
* The registry for starter Pokémon.
*
* The data here is used by the [CobblemonStarterHandler].
*
* 3rd party is not enforced to respect this registry.
*/
object StarterRegistry : JsonDataRegistry<StarterCategory> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.registerTypeAdapter(Text::class.java, PlainJsonTextAdapter)
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
.create()
override val typeToken: TypeToken<StarterCategory> = TypeToken.get(StarterCategory::class.java)
override val id: Identifier = cobblemonResource("starter")
override val resourcePath: String = id.path
override val type: ResourceType = ResourceType.SERVER_DATA
override val observable: SimpleObservable<out DataRegistry> = SimpleObservable()
private val categories = hashMapOf<Identifier, StarterCategory>()
// We let the default starter handler sync the client
// This is to prevent unnecessary packets depending on impl
override fun sync(player: ServerPlayerEntity) {}
override fun reload(data: Map<Identifier, StarterCategory>) {
this.categories.clear()
this.categories += data
Cobblemon.LOGGER.info("Loaded {} starters ({} categories)", this.categories.values.sumOf { it.pokemon.size }, this.categories.size)
}
fun all(): Map<Identifier, StarterCategory> = this.categories
fun keys(): Set<Identifier> = this.categories.keys
fun categories(): Collection<StarterCategory> = this.categories.values
fun categoryOf(key: Identifier): StarterCategory? = this.categories[key]
fun categoryOf(key: String): StarterCategory? = this.categories[key.asIdentifierDefaultingNamespace()]
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.storage.adapter.conversions
import com.cobblemon.mod.common.api.abilities.Abilities
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.pokeball.PokeBalls
import com.cobblemon.mod.common.api.pokemon.Natures
@@ -99,9 +98,8 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<NbtCompound> {
result.level = nbt.getInt("Level")
result.addExperience(SidemodExperienceSource("Reforged"), nbt.getInt("EXP"))
result.setFriendship(nbt.getInt("Friendship"))
Abilities.get(nbt.getString("Ability"))?.let { template ->
result.updateAbility(template.create(forced = result.form.abilities.none { it.template == template }))
}
result.ability = (result.form.abilities.find { it.template.name == nbt.getString("Ability") } ?: result.form.abilities.first())
.template.create()
result.nature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("Nature")].name.lowercase())) ?: Natures.getRandomNature()
result.mintedNature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("MintNature")].name.lowercase()))
result.currentHealth = nbt.getInt("Health")
@@ -37,7 +37,7 @@ data class PlayerData(
fun defaultData(forPlayer: UUID) = PlayerData(
uuid = forPlayer,
starterPrompted = false,
starterLocked = !Cobblemon.config.allowStarterOnJoin,
starterLocked = !Cobblemon.starterConfig.allowStarterOnJoin,
starterSelected = false,
starterUUID = null,
keyItems = mutableSetOf(),
@@ -22,15 +22,107 @@ import net.minecraft.registry.tag.TagKey
object CobblemonBiomeTags {
@JvmField
val IS_AUTUMN = create("has_season/autumn")
val IS_DEEP_DARK = create("is_deep_dark")
@JvmField
val IS_SPRING = create("has_season/spring")
val IS_ARID = create("is_arid")
@JvmField
val IS_SUMMER = create("has_season/summer")
val IS_AUTUMN = create("is_autumn")
@JvmField
val IS_BADLANDS = create("is_badlands")
@JvmField
val IS_BAMBOO = create("is_bamboo")
@JvmField
val IS_CAVE = create("is_cave")
@JvmField
val IS_COAST = create("is_coast")
@JvmField
val IS_COLD = create("is_cold")
@JvmField
val IS_DEEP_OCEAN = create("is_deep_ocean")
@JvmField
val IS_DESERT = create("is_desert")
@JvmField
val IS_DRIPSTONE = create("is_dripstone")
@JvmField
val IS_FLORAL = create("is_floral")
@JvmField
val IS_FOREST = create("is_forest")
@JvmField
val IS_FREEZING = create("is_freezing")
@JvmField
val IS_FRESHWATER = create("is_freshwater")
@JvmField
val IS_COLD_OCEAN = create("is_cold_ocean")
@JvmField
val IS_FROZEN_OCEAN = create("is_frozen_ocean")
@JvmField
val IS_GLACIAL = create("is_glacial")
@JvmField
val IS_GRASSLAND = create("is_grassland")
@JvmField
val IS_HIGHLANDS = create("is_highlands")
@JvmField
val IS_HILLS = create("is_hills")
@JvmField
val IS_ISLAND = create("is_island")
@JvmField
val IS_JUNGLE = create("is_jungle")
@JvmField
val IS_LUKEWARM_OCEAN = create("is_lukewarm_ocean")
@JvmField
val IS_LUSH = create("is_lush")
@JvmField
val IS_MAGICAL = create("is_magical")
@JvmField
val IS_MOUNTAIN = create("is_mountain")
@JvmField
val IS_MUSHROOM = create("is_mushroom")
@JvmField
val IS_OVERWORLD = create("is_overworld")
@JvmField
val IS_PEAK = create("is_peak")
@JvmField
val IS_PLAINS = create("is_plains")
@JvmField
val IS_PLATEAU = create("is_plateau")
@JvmField
val IS_WARM_OCEAN = create("is_warm_ocean")
@JvmField
val IS_RIVER = create("is_river")
@JvmField
val IS_SANDY = create("is_sandy")
@JvmField
val IS_SAVANNA = create("is_savanna")
@JvmField
val IS_SKY = create("is_sky")
@JvmField
val IS_SNOWY_FOREST = create("is_snowy_forest")
@JvmField
val IS_SPOOKY = create("is_spooky")
@JvmField
val IS_SPRING = create("is_spring")
@JvmField
val IS_SUMMER = create("is_summer")
@JvmField
val IS_SWAMP = create("is_swamp")
@JvmField
val IS_TAIGA = create("is_taiga")
@JvmField
val IS_TEMPERATE = create("is_temperate")
@JvmField
val IS_WINTER = create("has_season/winter")
val IS_THERMAL = create("is_thermal")
@JvmField
val IS_TUNDRA = create("is_tundra")
@JvmField
val IS_VOID = create("is_void")
@JvmField
val IS_VOlCANIC = create("is_volcanic")
@JvmField
val IS_WINTER = create("is_winter")
@JvmField
val IS_SPARSE = create("is_sparse")
@JvmField
val IS_DENSE = create("is_dense")
// Has Feature tags
@JvmField
@@ -88,5 +180,16 @@ object CobblemonBiomeTags {
@JvmField
val HAS_WATER_STONE_ORE_RARE = create("has_ore/ore_water_stone_rare")
// ToDo remove in 1.3
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
@JvmField
val IS_CRAG = create("is_crag")
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
@JvmField
val IS_ICY = create("is_icy")
@Deprecated(message = "This tag no longer exists", replaceWith = ReplaceWith("com.cobblemon.mod.common.api.tags.CobblemonBiomeTags.IS_CAVE"), level = DeprecationLevel.ERROR)
@JvmField
val IS_UNDERGROUND = create("is_underground")
private fun create(path: String) = TagKey.of(RegistryKeys.BIOME, cobblemonResource(path))
}
@@ -144,12 +144,6 @@ object CobblemonItemTags {
@JvmField
val POTTERY_SHERDS = create("decorated_pot_sherds")
@JvmField
val ABILITY_CHANGERS = create("ability_changers")
@JvmField
val IS_FRIENDSHIP_BOOSTER = create("is_friendship_booster")
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
}
@@ -1,38 +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.types.tera
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
import net.minecraft.text.Text
import net.minecraft.util.Identifier
/**
* The representation of the Pokémons Tera type.
*
* @see [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Terastal_phenomenon)
*
*/
interface TeraType : ShowdownIdentifiable {
/**
* The [Identifier] associated to this type.
*/
val id: Identifier
/**
* If this tera type can be selected naturally.
*/
val legalAsStatic: Boolean
/**
* The display name of this type.
*/
val displayName: Text
}
@@ -1,128 +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.types.tera
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.api.types.tera.elemental.ElementalTypeTeraType
import com.cobblemon.mod.common.api.types.tera.gimmick.StellarTeraType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.util.Identifier
/**
* The registry of all [TeraType]s.
*/
@Suppress("unused")
object TeraTypes {
private val types = hashMapOf<Identifier, TeraType>()
@JvmStatic
val NORMAL = this.create(cobblemonResource("normal"), ElementalTypeTeraType(ElementalTypes.NORMAL))
@JvmStatic
val FIRE = this.create(cobblemonResource("fire"), ElementalTypeTeraType(ElementalTypes.FIRE))
@JvmStatic
val WATER = this.create(cobblemonResource("water"), ElementalTypeTeraType(ElementalTypes.WATER))
@JvmStatic
val GRASS = this.create(cobblemonResource("grass"), ElementalTypeTeraType(ElementalTypes.GRASS))
@JvmStatic
val ELECTRIC = this.create(cobblemonResource("electric"), ElementalTypeTeraType(ElementalTypes.ELECTRIC))
@JvmStatic
val ICE = this.create(cobblemonResource("ice"), ElementalTypeTeraType(ElementalTypes.ICE))
@JvmStatic
val FIGHTING = this.create(cobblemonResource("fighting"), ElementalTypeTeraType(ElementalTypes.FIGHTING))
@JvmStatic
val POISON = this.create(cobblemonResource("poison"), ElementalTypeTeraType(ElementalTypes.POISON))
@JvmStatic
val GROUND = this.create(cobblemonResource("ground"), ElementalTypeTeraType(ElementalTypes.GROUND))
@JvmStatic
val FLYING = this.create(cobblemonResource("flying"), ElementalTypeTeraType(ElementalTypes.FLYING))
@JvmStatic
val PSYCHIC = this.create(cobblemonResource("psychic"), ElementalTypeTeraType(ElementalTypes.PSYCHIC))
@JvmStatic
val BUG = this.create(cobblemonResource("bug"), ElementalTypeTeraType(ElementalTypes.BUG))
@JvmStatic
val ROCK = this.create(cobblemonResource("rock"), ElementalTypeTeraType(ElementalTypes.ROCK))
@JvmStatic
val GHOST = this.create(cobblemonResource("ghost"), ElementalTypeTeraType(ElementalTypes.GHOST))
@JvmStatic
val DRAGON = this.create(cobblemonResource("dragon"), ElementalTypeTeraType(ElementalTypes.DRAGON))
@JvmStatic
val DARK = this.create(cobblemonResource("dark"), ElementalTypeTeraType(ElementalTypes.DARK))
@JvmStatic
val STEEL = this.create(cobblemonResource("steel"), ElementalTypeTeraType(ElementalTypes.STEEL))
@JvmStatic
val FAIRY = this.create(cobblemonResource("fairy"), ElementalTypeTeraType(ElementalTypes.FAIRY))
@JvmStatic
val STELLAR = this.create(StellarTeraType.ID, StellarTeraType())
/**
* Pick a random [TeraType].
*
* @param legalOnly If [TeraType.legalAsStatic] should be respected.
* @return The selected [TeraType].
*/
@JvmStatic
fun random(legalOnly: Boolean): TeraType {
val possible = this.types.values
if (legalOnly) {
return possible.filter(TeraType::legalAsStatic).random()
}
return possible.random()
}
/**
* Gets a [TeraType] by its [id].
*
* @param id The [Identifier] expected to match against a [TeraType.id].
* @return The found [TeraType] or null.
*/
@JvmStatic
fun get(id: Identifier): TeraType? = this.types[id]
/**
* Gets a [TeraType] by its [id].
*
* @param id The string representation of a [Identifier] if no namespace is present assumes Cobblemon' instead of Minecraft'.
* @return The found [TeraType] or null.
*/
@JvmStatic
fun get(id: String): TeraType? = this.get(cobblemonResource(id))
/**
* Gets the corresponding tera type for a [ElementalType].
*
* @param type The [ElementalType] being checked.
* @return The associated [TeraType].
*/
@JvmStatic
fun forElementalType(type: ElementalType): TeraType = this.get(cobblemonResource(type.name))!! // it's safe to do
private fun create(id: Identifier, type: TeraType): TeraType {
this.types[id] = type
return type
}
}
@@ -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.types.tera.elemental
import com.cobblemon.mod.common.api.types.ElementalType
import com.cobblemon.mod.common.api.types.tera.TeraType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class ElementalTypeTeraType(val type: ElementalType) : TeraType {
override val legalAsStatic: Boolean = true
override val id: Identifier = cobblemonResource(this.type.name)
override val displayName: Text = this.type.displayName
override fun showdownId(): String = this.type.name
}
@@ -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.api.types.tera.gimmick
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.types.tera.TeraType
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class StellarTeraType : TeraType {
override val id: Identifier = ID
override val legalAsStatic: Boolean = false
override val displayName: Text = LANG
override fun showdownId(): String = ID.path
companion object {
val ID = cobblemonResource("stellar")
private val LANG = Text.translatable("${Cobblemon.MODID}.terra_type.stellar")
}
}
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleChallengeExpire
import com.cobblemon.mod.common.util.getPlayer
import com.google.gson.GsonBuilder
import java.time.Instant
import java.util.Optional
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import net.minecraft.server.network.ServerPlayerEntity
@@ -138,7 +139,7 @@ object BattleRegistry {
// 0 - 9, empty == 10
packedTeamBuilder.append("${if (pk.dmaxLevel < 10) pk.dmaxLevel else ""},")
// Teratype
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.showdownId()},")
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.name},")
team.add(packedTeamBuilder.toString())
}
@@ -1,111 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.item.PokeBallItem
import net.minecraft.block.*
import net.minecraft.block.HorizontalFacingBlock.*
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.item.BlockItem
import net.minecraft.item.ItemPlacementContext
import net.minecraft.state.StateManager
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.ItemScatterer
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
@Suppress("OVERRIDE_DEPRECATION")
class DisplayCaseBlock(settings: Settings) : BlockWithEntity(settings) {
init {
this.defaultState = this.stateManager.defaultState
.with(FACING, Direction.NORTH)
}
override fun getPlacementState(ctx: ItemPlacementContext): BlockState? {
var blockState = defaultState
val worldView = ctx.world
val blockPos = ctx.blockPos
ctx.placementDirections.forEach { direction ->
if (direction.axis.isHorizontal) {
blockState = blockState.with(FACING, direction) as BlockState
if (blockState.canPlaceAt(worldView, blockPos)) {
return blockState
}
}
}
return null
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
builder.add(FACING)
}
override fun createBlockEntity(pos: BlockPos, state: BlockState): DisplayCaseBlockEntity {
return DisplayCaseBlockEntity(pos, state)
}
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
return if (direction == state.get(FACING) && !state.canPlaceAt(world, pos)) Blocks.AIR.defaultState
else super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun onUse(
state: BlockState,
world: World,
pos: BlockPos,
player: PlayerEntity,
hand: Hand,
hit: BlockHitResult
): ActionResult {
val entity = world.getBlockEntity(pos) as DisplayCaseBlockEntity
val result = entity.updateItem(player, hand)
if ((hit.side != Direction.UP && hit.side != Direction.DOWN) && result == ActionResult.SUCCESS) {
world.setBlockState(pos, state.with(FACING, hit.side.opposite))
}
return result
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
val entity = world.getBlockEntity(pos) as DisplayCaseBlockEntity
if (!entity.getStack().isEmpty && !player.isCreative) {
ItemScatterer.spawn(world, pos, entity.inv)
}
super.onBreak(world, pos, state, player)
}
override fun getRenderType(state: BlockState?) = BlockRenderType.MODEL
override fun getComparatorOutput(state: BlockState, world: World, pos: BlockPos): Int {
val stack = (world.getBlockEntity(pos) as DisplayCaseBlockEntity).getStack()
if (stack.isEmpty) return 0
if (stack.item is PokeBallItem) return 3
if (stack.item is BlockItem) return 2
return 1
}
override fun hasComparatorOutput(state: BlockState?) = true
override fun canPathfindThrough(state: BlockState, world: BlockView, pos: BlockPos, type: NavigationType) = false
}
@@ -62,8 +62,8 @@ class MonitorBlock(properties: Settings) : MultiblockBlock(properties) {
if(world == null || pos == null) {
return 0
}
val monitorEntity = world.getBlockEntity(pos) as? MultiblockEntity
val multiBlockEntity = monitorEntity?.multiblockStructure
val monitorEntity = world.getBlockEntity(pos) as MultiblockEntity
val multiBlockEntity = monitorEntity.multiblockStructure
if(multiBlockEntity != null) {
return multiBlockEntity.getComparatorOutput(state, world, pos)
}
@@ -149,8 +149,8 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
if(world == null || pos == null) {
return 0
}
val tankEntity = world.getBlockEntity(pos) as? MultiblockEntity
val multiBlockEntity = tankEntity?.multiblockStructure
val tankEntity = world.getBlockEntity(pos) as MultiblockEntity
val multiBlockEntity = tankEntity.multiblockStructure
if(multiBlockEntity != null) {
return multiBlockEntity.getComparatorOutput(state, world, pos)
}
@@ -180,7 +180,7 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
return
}
val tankEntity = world.getBlockEntity(pos) as? MultiblockEntity
tankEntity?.multiblockStructure?.onTriggerEvent(state, world, pos, random)
tankEntity?.multiblockStructure!!.onTriggerEvent(state, world, pos, random)
}
override fun getOutlineShape(
@@ -9,23 +9,15 @@
package com.cobblemon.mod.common.block
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import net.minecraft.block.*
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.FluidState
import net.minecraft.fluid.Fluids
import net.minecraft.item.ItemPlacementContext
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.server.world.ServerWorld
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.Properties
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.util.math.random.Random
import net.minecraft.util.shape.VoxelShape
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
import net.minecraft.world.WorldView
@@ -36,18 +28,7 @@ class TumblestoneBlock(
height: Int,
xzOffset: Int,
nextStage: Block?
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage), Waterloggable {
init {
this.defaultState = this.stateManager.defaultState
.with(FACING, Direction.DOWN)
.with(WATERLOGGED, false)
}
companion object {
val WATERLOGGED = BooleanProperty.of("waterlogged")
}
) : GrowableStoneBlock(settings, stage, height, xzOffset, nextStage) {
override fun canGrow(pos: BlockPos, world: BlockView): Boolean {
if (stage == MAX_STAGE) return false
val iterator: Iterator<BlockPos> =
@@ -62,31 +43,4 @@ class TumblestoneBlock(
return true
}
override fun getFluidState(state: BlockState): FluidState {
return if (state.get(GildedChestBlock.WATERLOGGED)) {
Fluids.WATER.getStill(false)
} else super.getFluidState(state)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
super.appendProperties(builder)
builder.add(GildedChestBlock.WATERLOGGED)
}
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
return super.getPlacementState(blockPlaceContext)?.with(GildedChestBlock.WATERLOGGED, blockPlaceContext.world.getFluidState(blockPlaceContext.blockPos).fluid == Fluids.WATER)
}
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState? {
if (state.get(GildedChestBlock.WATERLOGGED)) world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world))
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
}
@@ -16,24 +16,29 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.party
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.block.*
import net.minecraft.entity.LivingEntity
import net.minecraft.block.Block
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.block.Blocks
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.block.ShapeContext
import net.minecraft.entity.ai.pathing.NavigationType
import net.minecraft.entity.mob.PiglinBrain
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.fluid.FluidState
import net.minecraft.fluid.Fluids
import net.minecraft.item.ItemPlacementContext
import net.minecraft.item.ItemStack
import net.minecraft.screen.ScreenHandler
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.sound.SoundCategory
import net.minecraft.state.StateManager
import net.minecraft.state.property.BooleanProperty
import net.minecraft.state.property.Properties
import net.minecraft.text.MutableText
import net.minecraft.text.Text
import net.minecraft.util.*
import net.minecraft.util.ActionResult
import net.minecraft.util.BlockMirror
import net.minecraft.util.BlockRotation
import net.minecraft.util.Hand
import net.minecraft.util.Identifier
import net.minecraft.util.ItemScatterer
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
@@ -41,21 +46,17 @@ import net.minecraft.util.shape.VoxelShape
import net.minecraft.util.shape.VoxelShapes
import net.minecraft.world.BlockView
import net.minecraft.world.World
import net.minecraft.world.WorldAccess
@Suppress("OVERRIDE_DEPRECATION")
class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWithEntity(settings), Waterloggable {
class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWithEntity(settings) {
init {
defaultState = defaultState
.with(Properties.HORIZONTAL_FACING, Direction.SOUTH)
.with(WATERLOGGED, false)
defaultState = defaultState.with(Properties.HORIZONTAL_FACING, Direction.SOUTH)
}
companion object {
val POKEMON_ARGS = "gimmighoul"
val LEVEL_RANGE = 5..30
val WATERLOGGED = BooleanProperty.of("waterlogged")
val SOUTH_OUTLINE = VoxelShapes.union(
VoxelShapes.cuboid(0.0, 0.0, 0.25, 1.0, 1.0, 0.9375)
@@ -87,28 +88,9 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
}
}
override fun getStateForNeighborUpdate(
state: BlockState,
direction: Direction,
neighborState: BlockState,
world: WorldAccess,
pos: BlockPos,
neighborPos: BlockPos
): BlockState {
if (state.get(WATERLOGGED)) world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world))
return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos)
}
override fun getFluidState(state: BlockState): FluidState {
return if (state.get(WATERLOGGED)) {
Fluids.WATER.getStill(false)
} else super.getFluidState(state)
}
override fun appendProperties(builder: StateManager.Builder<Block, BlockState>) {
super.appendProperties(builder)
builder.add(Properties.HORIZONTAL_FACING)
builder.add(WATERLOGGED)
}
private val facingToYaw: HashMap<Direction, Float> = hashMapOf(
@@ -129,7 +111,7 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
if (player is ServerPlayerEntity) {
spawnPokemon(world, pos, state, player)
}
world.setBlockState(pos, if (state.fluidState.isOf(Fluids.WATER)) Blocks.WATER.defaultState else Blocks.AIR.defaultState)
world.setBlockState(pos, Blocks.AIR.defaultState)
} else super.onBreak(world, pos, state, player)
}
@@ -206,9 +188,12 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
override fun getRenderType(state: BlockState?) = BlockRenderType.ENTITYBLOCK_ANIMATED
override fun getPlacementState(blockPlaceContext: ItemPlacementContext): BlockState? {
return defaultState
.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing.opposite)
.with(WATERLOGGED, blockPlaceContext.world.getFluidState(blockPlaceContext.blockPos).fluid == Fluids.WATER)
// val abovePosition = blockPlaceContext.blockPos.up()
// val world = blockPlaceContext.world
// if (world.getBlockState(abovePosition).canReplace(blockPlaceContext) && !world.isOutOfHeightLimit(abovePosition)) {
return defaultState.with(HorizontalFacingBlock.FACING, blockPlaceContext.horizontalPlayerFacing.opposite)
// }
// return null
}
@Deprecated("Deprecated in Java")
@@ -220,14 +205,6 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
) as BlockState
}
override fun hasComparatorOutput(state: BlockState?): Boolean {
return true
}
override fun getComparatorOutput(state: BlockState?, world: World, pos: BlockPos?): Int {
return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos))
}
override fun mirror(state: BlockState, mirror: BlockMirror): BlockState {
return state.rotate(mirror.getRotation(state.get(Properties.HORIZONTAL_FACING) as Direction))
}
@@ -248,17 +225,4 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
return false
}
override fun onPlaced(
world: World,
pos: BlockPos,
state: BlockState,
placer: LivingEntity?,
itemStack: ItemStack
) {
val blockEntity = world.getBlockEntity(pos)
if (itemStack.hasCustomName() && blockEntity is GildedChestBlockEntity) {
blockEntity.customName = itemStack.name
}
}
}
@@ -1,180 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.block.entity
import com.cobblemon.mod.common.CobblemonBlockEntities
import com.cobblemon.mod.common.CobblemonSounds
import net.minecraft.block.Block
import net.minecraft.block.BlockState
import net.minecraft.block.entity.BlockEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
import net.minecraft.sound.SoundCategory
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
class DisplayCaseBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.DISPLAY_CASE, pos, state), SidedInventory {
val inv: DefaultedList<ItemStack> = DefaultedList.ofSize(1, ItemStack.EMPTY)
/**
* Updates the [ItemStack] stored in this entity
*
* @param player The [PlayerEntity] that performed this interaction
* @param hand The [Hand] the player used to perform this interaction
* @author whatsy
*/
fun updateItem(player: PlayerEntity, hand: Hand): ActionResult {
val playerStack = player.getStackInHand(hand)
// Player and case item are the same - do nothing
if (playerStack.item == getStack().item) {
return if (playerStack.item != Items.AIR) ActionResult.SUCCESS else ActionResult.FAIL
}
// Player's hand is empty, case is not empty - give player the item in the case
if (playerStack.isEmpty && !getStack().isEmpty) {
if (!player.isCreative) player.setStackInHand(hand, getStack())
setCaseStack(ItemStack.EMPTY)
return ActionResult.success(true)
}
// Case is empty, player's hand is not - put playerStack in the case
if (getStack().isEmpty && !playerStack.isEmpty) {
setCaseStack(playerStack.copy())
if (!player.isCreative) playerStack.decrement(1)
return ActionResult.success(true)
}
// Player has item, case has item - swap items
if (!getStack().isEmpty && !playerStack.isEmpty) {
val oldCaseStack = getStack()
setCaseStack(playerStack.copy())
if (!player.isCreative) {
playerStack.decrement(1)
player.giveItemStack(oldCaseStack)
}
return ActionResult.SUCCESS
}
return ActionResult.FAIL
}
fun getStack(): ItemStack {
return inv[0]
}
private fun setCaseStack(newStack: ItemStack) {
if (world == null) return
val oldState = world!!.getBlockState(pos)
newStack.count = 1
inv[0] = newStack
if (newStack.isEmpty) {
world!!.playSound(null, pos, CobblemonSounds.DISPLAY_CASE_REMOVE_ITEM, SoundCategory.BLOCKS)
} else {
world!!.playSound(null, pos, CobblemonSounds.DISPLAY_CASE_ADD_ITEM, SoundCategory.BLOCKS)
}
world!!.updateListeners(pos, oldState, world!!.getBlockState(pos), Block.NOTIFY_LISTENERS)
world!!.updateComparators(pos, world!!.getBlockState(pos).block)
}
override fun writeNbt(nbt: NbtCompound) {
super.writeNbt(nbt)
Inventories.writeNbt(nbt, inv, true)
}
override fun readNbt(nbt: NbtCompound) {
super.readNbt(nbt)
inv.clear()
Inventories.readNbt(nbt, inv)
}
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
return BlockEntityUpdateS2CPacket.create(this)
}
override fun toInitialChunkDataNbt(): NbtCompound {
return this.createNbt()
}
private fun onItemUpdated(world: World, oldState: BlockState, newState: BlockState) {
markDirty()
world.updateListeners(pos, oldState, newState, Block.NOTIFY_LISTENERS)
world.updateComparators(pos, world.getBlockState(pos).block)
}
override fun clear() {
inv.clear()
}
override fun size(): Int {
return inv.size
}
override fun isEmpty(): Boolean {
return getStack().isEmpty
}
override fun getStack(slot: Int): ItemStack {
return getStack()
}
override fun removeStack(slot: Int, amount: Int): ItemStack {
val oldState = cachedState
val result = Inventories.splitStack(inv, slot, amount)
if (world != null) onItemUpdated(world!!, oldState, world!!.getBlockState(pos))
return result
}
override fun removeStack(slot: Int): ItemStack {
val oldState = cachedState
val result = Inventories.removeStack(inv, slot)
if (world != null) onItemUpdated(world!!, oldState, world!!.getBlockState(pos))
return result
}
override fun setStack(slot: Int, stack: ItemStack) {
val oldState = cachedState
inv[slot] = stack
if (stack.count > stack.maxCount) {
stack.count = stack.maxCount
}
if (world != null) onItemUpdated(world!!, oldState, world!!.getBlockState(pos))
}
override fun canPlayerUse(player: PlayerEntity?) = false
override fun getAvailableSlots(side: Direction?): IntArray {
val result = IntArray(inv.size)
for (i in result.indices) {
result[i] = i
}
return result
}
override fun getMaxCountPerStack() = 1
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
if(dir == Direction.DOWN) return false
return getStack().isEmpty
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean = (dir == Direction.DOWN)
}
@@ -19,7 +19,6 @@ import net.minecraft.block.entity.BlockEntityType
import net.minecraft.nbt.NbtCompound
import net.minecraft.nbt.NbtHelper
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.ChunkPos
open class FossilMultiblockEntity(
pos: BlockPos,
@@ -40,12 +39,8 @@ open class FossilMultiblockEntity(
get() {
return if (field != null) {
field
} else if (masterBlockPos != null && masterBlockPos != pos) {
val chunkPos = ChunkPos(masterBlockPos)
if (world?.chunkManager?.isChunkLoaded(chunkPos.x, chunkPos.z) == true) {
val entity: FossilMultiblockEntity? = world?.getBlockEntity(masterBlockPos) as FossilMultiblockEntity?
field = entity?.multiblockStructure
}
} else if (masterBlockPos != null && masterBlockPos != pos && world?.getBlockEntity(masterBlockPos) != null) {
field = (world?.getBlockEntity(masterBlockPos) as FossilMultiblockEntity).multiblockStructure
field
} else {
null
@@ -20,7 +20,6 @@ import net.minecraft.entity.player.PlayerEntity
import net.minecraft.entity.player.PlayerInventory
import net.minecraft.inventory.DoubleInventory
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.SidedInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.screen.GenericContainerScreenHandler
@@ -29,10 +28,9 @@ import net.minecraft.state.property.Properties
import net.minecraft.text.Text
import net.minecraft.util.collection.DefaultedList
import net.minecraft.util.math.BlockPos
import net.minecraft.util.math.Direction
import net.minecraft.world.World
class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type = Type.RED) : LootableContainerBlockEntity(CobblemonBlockEntities.GILDED_CHEST, pos, state), SidedInventory {
class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type = Type.RED) : LootableContainerBlockEntity(CobblemonBlockEntities.GILDED_CHEST, pos, state) {
var inventoryContents: DefaultedList<ItemStack> = DefaultedList.ofSize(NUM_SLOTS, ItemStack.EMPTY)
val poseableState: GildedState = GildedState()
@@ -71,7 +69,7 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
override fun getContainerName() = Text.translatable("block.cobblemon.gilded_chest")
override fun createScreenHandler(syncId: Int, playerInventory: PlayerInventory?) =
GenericContainerScreenHandler.createGeneric9x3(syncId, playerInventory, this)
GenericContainerScreenHandler.createGeneric9x3(syncId, playerInventory, this);
override fun onOpen(player: PlayerEntity) {
if (!this.removed && !player.isSpectator && type != Type.FAKE) {
@@ -85,22 +83,6 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
}
}
override fun getAvailableSlots(side: Direction): IntArray {
return if (type == Type.FAKE) IntArray(0) else IntArray(NUM_SLOTS)
}
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
if (type == Type.FAKE) return false
return dir != Direction.DOWN
}
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
if (type == Type.FAKE) return false
return dir == Direction.DOWN
}
override fun canPlayerUse(player: PlayerEntity) = !player.isSpectator
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
override fun setInvStackList(list: DefaultedList<ItemStack>) {
@@ -140,7 +140,7 @@ class PokemonPastureBlockEntity(pos: BlockPos, val state: BlockState) : BlockEnt
if (fixedPosition != null) {
entity.setPosition(fixedPosition.toCenterPos().subtract(0.0, 0.5, 0.0))
val pc = Cobblemon.storage.getPC(player.uuid)
entity.beamMode = 2
entity.beamMode = 1
afterOnServer(seconds = SendOutPokemonHandler.SEND_OUT_DURATION) {
entity.beamMode = 0
}
@@ -117,10 +117,10 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
val monitorPos = monitorPositions[fossilTankIndex]
val fossilAnalyzerPos = fossilAnalyzerPositions[fossilTankIndex]!!
val restorationTankPos = restorationTankPositions[fossilTankIndex]!!
val monitorEntity = world.getBlockEntity(monitorPos) as? MultiblockEntity
val analyzerEntity = world.getBlockEntity(fossilAnalyzerPos) as? MultiblockEntity
val tankBaseEntity = world.getBlockEntity(restorationTankPos) as? MultiblockEntity
val tankTopEntity = world.getBlockEntity(restorationTankPos.up()) as? MultiblockEntity
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
val analyzerEntity = world.getBlockEntity(fossilAnalyzerPos) as MultiblockEntity
val tankBaseEntity = world.getBlockEntity(restorationTankPos) as MultiblockEntity
val tankTopEntity = world.getBlockEntity(restorationTankPos.up()) as MultiblockEntity
val structure = FossilMultiblockStructure(monitorPos, fossilAnalyzerPos, restorationTankPos)
structure.tankConnectorDirection = dirsToCheck.filter {
@@ -128,20 +128,20 @@ class FossilMultiblockBuilder(val centerPos: BlockPos) : MultiblockStructureBuil
return@filter adjPos == fossilAnalyzerPos
}.first()
analyzerEntity?.multiblockStructure = structure
tankBaseEntity?.multiblockStructure = structure
tankTopEntity?.multiblockStructure = structure
monitorEntity?.multiblockStructure = structure
analyzerEntity.multiblockStructure = structure
tankBaseEntity.multiblockStructure = structure
tankTopEntity.multiblockStructure = structure
monitorEntity.multiblockStructure = structure
structure.syncToClient(world)
structure.markDirty(world)
world.playSound(null, centerPos, CobblemonSounds.FOSSIL_MACHINE_ASSEMBLE, SoundCategory.BLOCKS)
//Set these to null so the builders can be freed
analyzerEntity?.multiblockBuilder = null
tankBaseEntity?.multiblockBuilder = null
tankTopEntity?.multiblockBuilder = null
monitorEntity?.multiblockBuilder = null
analyzerEntity.multiblockBuilder = null
tankBaseEntity.multiblockBuilder = null
tankTopEntity.multiblockBuilder = null
monitorEntity.multiblockBuilder = null
}
companion object {
@@ -98,97 +98,101 @@ class FossilMultiblockStructure (
): ActionResult {
val stack = player.getStackInHand(interactionHand)
if(stack.isIn(CobblemonItemTags.POKE_BALLS) || stack.item is PokeBallItem) {
if (this.createdPokemon != null) {
if (!stack.isIn(CobblemonItemTags.POKE_BALLS) || stack.item !is PokeBallItem) {
return ActionResult.PASS
}
if (player !is ServerPlayerEntity) {
return ActionResult.SUCCESS
return ActionResult.CONSUME
}
if (this.createdPokemon != null) {
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
ownerName = it
}
player.sendMessage(lang("fossilmachine.protected", ownerName), true)
return ActionResult.FAIL
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
ownerName = it
}
val ballType = (stack.item as PokeBallItem).pokeBall
if (!player.isCreative) {
stack?.decrement(1)
}
this.createdPokemon!!.caughtBall = ballType
player.party().add(this.createdPokemon!!)
this.fossilState.growthState = "Taken"
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
// Turn the monitor off
val monitorState = world.getBlockState(monitorPos)
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
}
this.createdPokemon = null
this.fossilOwnerUUID = null
this.protectionTime = -1
this.updateFossilType(world)
this.syncToClient(world)
this.markDirty(world)
return ActionResult.SUCCESS
player.sendMessage(lang("fossilmachine.protected", ownerName), true)
return ActionResult.FAIL
}
val ballType = (stack.item as PokeBallItem).pokeBall
if (!player.isCreative) {
stack?.decrement(1)
}
this.createdPokemon!!.caughtBall = ballType
player.party().add(this.createdPokemon!!)
this.fossilState.growthState = "Taken"
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
// Turn the monitor off
val monitorState = world.getBlockState(monitorPos)
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
}
this.createdPokemon = null
this.fossilOwnerUUID = null
this.protectionTime = -1
this.updateFossilType(world)
this.syncToClient(world)
this.markDirty(world)
return ActionResult.SUCCESS
}
if (this.isRunning()) {
return ActionResult.PASS
}
// Reclaim the last fossil from the machine if their hand is empty
if (player.getStackInHand(interactionHand).isEmpty) {
if(!this.isRunning() && this.createdPokemon == null) {
if (fossilInventory.isEmpty()) {
return ActionResult.CONSUME
}
player.setStackInHand(interactionHand, fossilInventory.last())
if (fossilInventory.isEmpty()) {
return ActionResult.CONSUME
}
// remove last fossil in the fossil machine stack when grabbed out of the machine
this.fossilInventory.removeAt(fossilInventory.size - 1)
if(!world.isClient) {
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
this.updateFossilType(world)
this.syncToClient(world)
this.markDirty(world)
}
player.setStackInHand(interactionHand, fossilInventory.last())
// remove last fossil in the fossil machine stack when grabbed out of the machine
this.fossilInventory.removeAt(fossilInventory.size - 1)
if(!world.isClient) {
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
this.updateFossilType(world)
this.syncToClient(world)
this.markDirty(world)
}
return ActionResult.CONSUME
}
// Check if the player is holding a fossil and if so insert it into the machine.
if (Fossils.isFossilIngredient(stack)) {
if(!this.isRunning() && this.createdPokemon == null) {
if (fossilInventory.size > Cobblemon.config.maxInsertedFossilItems) {
return ActionResult.FAIL
}
if (fossilInventory.size > Cobblemon.config.maxInsertedFossilItems) {
return ActionResult.FAIL
}
val copyFossilStack = stack.copyWithCount(1)
if (!player.isCreative) {
stack?.decrement(1)
}
val copyFossilStack = stack.copyWithCount(1)
if (!player.isCreative) {
stack?.decrement(1)
}
fossilOwnerUUID = player.uuid
fossilInventory.add(copyFossilStack)
if(!world.isClient) {
this.updateFossilType(world)
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
this.syncToClient(world)
this.markDirty(world)
}
fossilOwnerUUID = player.uuid
fossilInventory.add(copyFossilStack)
if(!world.isClient) {
this.updateFossilType(world)
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
this.syncToClient(world)
this.markDirty(world)
}
return ActionResult.SUCCESS
}
// Check if the player is holding a natural material and if so, feed it to the machine.
if (NaturalMaterials.isNaturalMaterial(stack)) {
if (!this.isRunning() && this.createdPokemon == null && this.organicMaterialInside < MATERIAL_TO_START && insertOrganicMaterial(stack, world)) {
if (NaturalMaterials.isNaturalMaterial(stack) && this.organicMaterialInside < MATERIAL_TO_START) {
if (insertOrganicMaterial(stack, world)) {
this.lastInteraction = world.time
if (!player.isCreative) {
val returnItem = NaturalMaterials.getReturnItem(stack)
@@ -196,6 +200,7 @@ class FossilMultiblockStructure (
player.giveOrDropItemStack(ItemStack(Registries.ITEM.get(returnItem)), false)
}
}
return ActionResult.success(world.isClient)
}
@@ -306,22 +311,22 @@ class FossilMultiblockStructure (
}
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
val monitorEntity = world.getBlockEntity(monitorPos) as? MultiblockEntity
val analyzerEntity = world.getBlockEntity(analyzerPos) as? MultiblockEntity
val tankBaseEntity = world.getBlockEntity(tankBasePos) as? MultiblockEntity
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as? MultiblockEntity
val state = world.getBlockState(tankBaseEntity?.pos)
val monitorEntity = world.getBlockEntity(monitorPos) as MultiblockEntity
val analyzerEntity = world.getBlockEntity(analyzerPos) as MultiblockEntity
val tankBaseEntity = world.getBlockEntity(tankBasePos) as MultiblockEntity
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as MultiblockEntity
val state = world.getBlockState(tankBaseEntity.pos)
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
val wildPokemon: Pokemon? = this.createdPokemon
monitorEntity?.multiblockStructure = null
analyzerEntity?.multiblockStructure = null
tankBaseEntity?.multiblockStructure = null
tankTopEntity?.multiblockStructure = null
monitorEntity?.masterBlockPos = null
analyzerEntity?.masterBlockPos = null
tankBaseEntity?.masterBlockPos = null
tankTopEntity?.masterBlockPos = null
monitorEntity.multiblockStructure = null
analyzerEntity.multiblockStructure = null
tankBaseEntity.multiblockStructure = null
tankTopEntity.multiblockStructure = null
monitorEntity.masterBlockPos = null
analyzerEntity.masterBlockPos = null
tankBaseEntity.masterBlockPos = null
tankTopEntity.masterBlockPos = null
// Drop fossils from machine as long as the machine is not started or near completion
if (this.timeRemaining == -1 || this.timeRemaining >= 20) {
@@ -539,7 +544,7 @@ class FossilMultiblockStructure (
}
if (natureValue < 0 && organicMaterialInside == 0) return false
val oldFillStage = organicMaterialInside * 8 / MATERIAL_TO_START
val oldFillStage = organicMaterialInside / 8
// to prevent over/under filling the tank causing a crash
if ((organicMaterialInside + natureValue) > MATERIAL_TO_START) {
@@ -557,7 +562,7 @@ class FossilMultiblockStructure (
world.playSound(null, this.tankBasePos, CobblemonSounds.FOSSIL_MACHINE_INSERT_DNA, SoundCategory.BLOCKS, 1.0F, 1.0F)
}
this.markDirty(world)
if (oldFillStage != (organicMaterialInside * 8 / MATERIAL_TO_START)) {
if (oldFillStage != (organicMaterialInside / 8)) {
this.syncToClient(world)
}
return true
@@ -619,10 +624,10 @@ class FossilMultiblockStructure (
}
const val TICKS_PER_MINUTE = 1200
const val MATERIAL_TO_START = 128
const val TIME_TO_TAKE = TICKS_PER_MINUTE * 12
const val MATERIAL_TO_START = 64
const val TIME_TO_TAKE = TICKS_PER_MINUTE * 1
const val TIME_PER_STAGE = TIME_TO_TAKE / 8
const val PROTECTION_TIME = TICKS_PER_MINUTE * 5
const val PROTECTION_TIME = 6000
fun fromNbt(nbt: NbtCompound, animAge: Int = -1, partialTicks: Float = 0f): FossilMultiblockStructure {
val monitorPos = NbtHelper.toBlockPos(nbt.getCompound(DataKeys.MONITOR_POS))
@@ -657,7 +662,7 @@ class FossilMultiblockStructure (
if (nbt.contains(DataKeys.CREATED_POKEMON)) {
result.createdPokemon = Pokemon.loadFromNBT(nbt.getCompound(DataKeys.CREATED_POKEMON))
}
result.fillLevel = result.organicMaterialInside * 8 / MATERIAL_TO_START
result.fillLevel = result.organicMaterialInside / 8
return result
}
@@ -27,9 +27,7 @@ import com.cobblemon.mod.common.client.render.block.FossilAnalyzerRenderer
import com.cobblemon.mod.common.client.render.block.RestorationTankRenderer
import com.cobblemon.mod.common.client.render.block.GildedChestBlockRenderer
import com.cobblemon.mod.common.client.render.block.HealingMachineRenderer
import com.cobblemon.mod.common.client.render.block.*
import com.cobblemon.mod.common.client.render.boat.CobblemonBoatRenderer
import com.cobblemon.mod.common.client.render.generic.GenericBedrockRenderer
import com.cobblemon.mod.common.client.render.item.CobblemonBuiltinItemRendererRegistry
import com.cobblemon.mod.common.client.render.item.PokemonItemRenderer
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer
@@ -48,7 +46,6 @@ import com.cobblemon.mod.common.data.CobblemonDataProvider
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.client.render.models.blockbench.repository.FossilModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.GenericBedrockEntityModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.MiscModelRepository
import com.cobblemon.mod.common.platform.events.PlatformEvents
import com.cobblemon.mod.common.util.DataKeys
@@ -120,6 +117,7 @@ object CobblemonClient {
PlatformEvents.CLIENT_ITEM_TOOLTIP.subscribe { event ->
val stack = event.stack
val lines = event.lines
val size = lines.size
@Suppress("DEPRECATION")
if (stack.item.registryEntry.key.isPresent && stack.item.registryEntry.key.get().value.namespace == Cobblemon.MODID) {
if (stack.nbt?.getBoolean(DataKeys.HIDE_TOOLTIP) == true) {
@@ -127,14 +125,14 @@ object CobblemonClient {
}
val language = Language.getInstance()
val key = this.baseLangKeyForItem(stack)
val offset = if (lines.size > 1) 1 else 0
val offset = if (size > 1) 1 else 0
if (language.hasTranslation(key)) {
lines.add(lines.size - offset, key.asTranslated().gray())
lines.add(size - offset, key.asTranslated().gray())
}
var i = 1
var listKey = "${key}_$i"
while(language.hasTranslation(listKey)) {
lines.add(lines.size - offset, listKey.asTranslated().gray())
lines.add(size - offset, listKey.asTranslated().gray())
listKey = "${key}_${++i}"
}
}
@@ -220,8 +218,7 @@ object CobblemonClient {
CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE,
CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER,
CobblemonBlocks.GIMMIGHOUL_CHEST,
CobblemonBlocks.DISPLAY_CASE
CobblemonBlocks.GIMMIGHOUL_CHEST
)
this.createBoatModelLayers()
@@ -252,7 +249,6 @@ object CobblemonClient {
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.FOSSIL_ANALYZER, ::FossilAnalyzerRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.RESTORATION_TANK, ::RestorationTankRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.GILDED_CHEST, ::GildedChestBlockRenderer)
this.implementation.registerBlockEntityRenderer(CobblemonBlockEntities.DISPLAY_CASE, ::DisplayCaseRenderer)
}
private fun registerEntityRenderers() {
@@ -264,8 +260,6 @@ object CobblemonClient {
this.implementation.registerEntityRenderer(CobblemonEntities.BOAT) { ctx -> CobblemonBoatRenderer(ctx, false) }
LOGGER.info("Registering Boat with Chest renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.CHEST_BOAT) { ctx -> CobblemonBoatRenderer(ctx, true) }
LOGGER.info("Registering Generic Bedrock Entity renderer")
this.implementation.registerEntityRenderer(CobblemonEntities.GENERIC_BEDROCK_ENTITY, ::GenericBedrockRenderer)
}
fun reloadCodedAssets(resourceManager: ResourceManager) {
@@ -273,14 +267,13 @@ object CobblemonClient {
BedrockParticleEffectRepository.loadEffects(resourceManager)
BedrockAnimationRepository.loadAnimations(
resourceManager = resourceManager,
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories + GenericBedrockEntityModelRepository.animationDirectories
directories = PokemonModelRepository.animationDirectories + PokeBallModelRepository.animationDirectories + FossilModelRepository.animationDirectories + BlockEntityModelRepository.animationDirectories
)
PokemonModelRepository.reload(resourceManager)
PokeBallModelRepository.reload(resourceManager)
BerryModelRepository.reload(resourceManager)
FossilModelRepository.reload(resourceManager)
BlockEntityModelRepository.reload(resourceManager)
GenericBedrockEntityModelRepository.reload(resourceManager)
MiscModelRepository.reload(resourceManager)
LOGGER.info("Loaded assets")
}
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.entity
import com.bedrockk.molang.runtime.value.DoubleValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
@@ -21,6 +22,7 @@ import com.cobblemon.mod.common.api.scheduling.lerpOnClient
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
import com.cobblemon.mod.common.client.particle.ParticleStorm
import com.cobblemon.mod.common.client.render.MatrixWrapper
import com.cobblemon.mod.common.client.render.SnowstormParticle
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.PrimaryAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.animation.StatefulAnimation
@@ -32,8 +34,11 @@ import com.cobblemon.mod.common.util.MovingSoundInstance
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.MinecraftClient
import net.minecraft.client.util.math.MatrixStack
import java.lang.Float.min
import kotlin.math.abs
import net.minecraft.entity.Entity
import net.minecraft.entity.data.TrackedData
import net.minecraft.particle.ParticleTypes
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent
import net.minecraft.util.Hand
@@ -100,8 +105,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
this.addPrimaryAnimation(primaryAnimation)
}
} else if (data == PokemonEntity.BEAM_MODE) {
// If you make adjustments to this code, make sure to Find Usages for both PokemonEntity.beamMode and PokemonEntity.BEAM_MODE
// TODO: change beamMode to an enum, or a set of booleans (send-out vs recall, delay vs delay)
val beamMode = currentEntity.beamMode
when (beamMode) {
0 -> { /* Do nothing */ }
@@ -138,37 +141,39 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
currentEntity.after(seconds = POKEBALL_AIR_TIME){
beamStartTime = System.currentTimeMillis()
ballDone = true
if (client.soundManager.get(CobblemonSounds.POKE_BALL_SEND_OUT.id) != null && !playedSendOutSound) {
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
playedSendOutSound = true
}
// Display ball-specific particles
sendOutPosition?.let{
val newPos = it.add(sendOutOffset)
val ballType = currentEntity.pokemon.caughtBall.name.path.lowercase().replace("_","")
val mode = if(currentEntity.isBattling) "battle" else "casual"
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
sendflash?.let { effect ->
val wrapper = MatrixWrapper()
val matrix = MatrixStack()
matrix.translate(newPos.x, newPos.y, newPos.z)
wrapper.updateMatrix(matrix.peek().positionMatrix)
val world = MinecraftClient.getInstance().world ?: return@let
ParticleStorm(effect, wrapper, world).spawn()
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
afterOnClient(seconds = 0.01667f) {
ballsparks?.let { effect ->
if (client.soundManager.get(CobblemonSounds.POKE_BALL_OPEN.id) != null && !playedSendOutSound) {
currentEntity.owner?.let {
client.world?.playSound(client.player, soundPos.x, soundPos.y, soundPos.z, SoundEvent.of(CobblemonSounds.POKE_BALL_SEND_OUT.id), SoundCategory.PLAYERS, 0.6f, 1f)
playedSendOutSound = true
/// create end rod particles in a 0.1 radius around the soundPos with a count of 50 and a random velocity of 0.1
sendOutPosition?.let{
val newPos = it.add(sendOutOffset)
val ballType = currentEntity.pokemon.caughtBall.name.path.toLowerCase().replace("_","")
val mode = if(currentEntity.isBattling) "battle" else "casual"
val sendflash = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/sendflash"))
sendflash?.let { effect ->
val wrapper = MatrixWrapper()
val matrix = MatrixStack()
matrix.translate(newPos.x, newPos.y, newPos.z)
wrapper.updateMatrix(matrix.peek().positionMatrix)
val world = MinecraftClient.getInstance().world ?: return@let
ParticleStorm(effect, wrapper, world).spawn()
}
ballsendsparkle?.let { effect ->
ParticleStorm(effect, wrapper, world).spawn()
}
currentEntity.after(seconds = 0.4f) {
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
ballsparkle?.let { effect ->
ParticleStorm(effect, wrapper, world).spawn()
val ballsparks = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsparks"))
val ballsendsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/${mode}/ballsendsparkle"))
// using afterOnClient because it's such a small timeframe that it's unlikely the entity has been removed & we'd like the precision
afterOnClient(seconds = 0.01667f) {
ballsparks?.let { effect ->
ParticleStorm(effect, wrapper, world).spawn()
}
ballsendsparkle?.let { effect ->
ParticleStorm(effect, wrapper, world).spawn()
}
currentEntity.after(seconds = 0.4f) {
val ballsparkle = BedrockParticleEffectRepository.getEffect(cobblemonResource("${ballType}/ballsparkle"))
ballsparkle?.let { effect ->
ParticleStorm(effect, wrapper, world).spawn()
}
}
}
}
}
@@ -185,35 +190,7 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
}
}
}
2 -> {
// Scaling up with no delay and no particles
playedSendOutSound = false
entityScaleModifier = 0F
currentEntity.isInvisible = false
val soundPos = currentEntity.pos
val client = MinecraftClient.getInstance()
if (client.soundManager.get(CobblemonSounds.POKE_BALL_SEND_OUT.id) != null && !playedSendOutSound) {
client.world?.playSound(
client.player,
soundPos.x,
soundPos.y,
soundPos.z,
CobblemonSounds.POKE_BALL_SEND_OUT,
SoundCategory.PLAYERS,
0.6f,
1f
)
playedSendOutSound = true
}
lerpOnClient(BEAM_SHRINK_TIME) { entityScaleModifier = it }
currentEntity.after(seconds = BEAM_SHRINK_TIME * 2) {
ballOffset = 0f
ballRotOffset = 0f
sendOutPosition = null
}
}
3 -> {
else -> {
// Scaling down into pokeball
entityScaleModifier = 1F
beamStartTime = System.currentTimeMillis()
@@ -226,7 +203,6 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
}
}
}
else -> { /* Do nothing */ }
}
} else if (data == PokemonEntity.LABEL_LEVEL) {
currentEntity.dataTracker.get(PokemonEntity.LABEL_LEVEL)
@@ -59,7 +59,7 @@ class PartyOverlay : InGameHud(MinecraftClient.getInstance(), MinecraftClient.ge
BattleGUI::class.java
)
val starterToast = CobblemonToast(
private val starterToast = CobblemonToast(
MathHelper.randomUuid(),
CobblemonItems.POKE_BALL.defaultStack,
lang("ui.starter.choose_starter_title", SummaryBinding.boundKey().localizedText).red(),
@@ -104,12 +104,24 @@ class PartyOverlay : InGameHud(MinecraftClient.getInstance(), MinecraftClient.ge
!CobblemonClient.checkedStarterScreen
) {
if (!this.attachedToast) {
// Adding starter toast on start and connect of client to server.
minecraft.toastManager.add(this.starterToast)
this.attachedToast = true
}
/*
drawScaledText(
context = context,
text = lang("ui.starter.chooseyourstarter", SummaryBinding.boundKey().localizedText),
x = minecraft.window.scaledWidth / 2,
y = 70,
centered = true,
shadow = true
)
*/
}
return // Don't render the stuff below if no Pokémon in party
return
}
if (this.starterToast.nextVisibility != Toast.Visibility.HIDE) {
this.starterToast.nextVisibility = Toast.Visibility.HIDE
}
val totalHeight = party.slots.size * SLOT_HEIGHT
@@ -10,12 +10,11 @@ package com.cobblemon.mod.common.client.gui.battle.subscreen
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.battle.SingleActionRequest
import com.cobblemon.mod.common.client.gui.battle.BattleGUI
import com.cobblemon.mod.common.client.gui.battle.widgets.BattleOptionTile
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
import com.cobblemon.mod.common.util.battleLang
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
@@ -62,9 +61,8 @@ class BattleGeneralActionSelection(
}
addOption(rank++, battleLang("ui.run"), BattleGUI.runResource) {
CobblemonClient.battle?.minimised = true
MinecraftClient.getInstance().player?.sendMessage(battleLang("run_prompt"), false)
playDownSound(MinecraftClient.getInstance().soundManager)
FleeBattlePacket(battle.battleId).sendToServer()
}
}
}
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.api.gui.ColourLibrary
import com.cobblemon.mod.common.api.gui.MultiLineLabelK
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.text.bold
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.CobblemonResources
import com.cobblemon.mod.common.client.gui.startselection.widgets.CategoryList
import com.cobblemon.mod.common.client.gui.startselection.widgets.ExitButton
@@ -27,7 +26,7 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.type.DualTypeWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.type.SingleTypeWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.type.TypeWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.api.starter.RenderableStarterCategory
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.pokemon.RenderablePokemon
import com.cobblemon.mod.common.util.asTranslated
@@ -38,9 +37,8 @@ import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.toast.Toast
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
/**
* Starterselection Screen Thingy
@@ -48,7 +46,7 @@ import net.minecraft.util.Identifier
* @author Qu
* @since 2022-06-18
*/
class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()) {
class StarterSelectionScreen(private val categories: List<RenderableStarterCategory>): Screen("cobblemon.ui.starter.title".asTranslated()) {
companion object {
// Size of UI at scale 1
@@ -65,9 +63,8 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
private val doubleTypeBackground = cobblemonResource("textures/gui/starterselection/starterselection_type_slot2.png")
}
private val categories = categories.toSortedMap { a, b -> a.compareTo(b) }
private var currentSelection = 0
private lateinit var currentCategoryId: Identifier
private lateinit var currentCategory: RenderableStarterCategory
private lateinit var modelWidget: ModelWidget
private lateinit var currentPokemon: RenderablePokemon
private lateinit var typeWidget: TypeWidget
@@ -77,12 +74,6 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
override fun init() {
super.init()
// Hide toast once checkedStarterScreen was set, which happens during the opening of the starter screen.
if (CobblemonClient.checkedStarterScreen) {
if (CobblemonClient.overlay.starterToast.nextVisibility != Toast.Visibility.HIDE) {
CobblemonClient.overlay.starterToast.nextVisibility = Toast.Visibility.HIDE
}
}
val x = (width - BASE_WIDTH) / 2
val y = (height - BASE_HEIGHT) / 2
@@ -97,7 +88,7 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
paneWidth = 71, paneHeight = BASE_HEIGHT - 11,
topOffset = 6, bottomOffset = 5,
entryHeight = 20, entryWidth = 57,
categories = this.categories,
categories = categories,
x = x - 2, y = y + 8,
starterSelectionScreen = this
)
@@ -122,8 +113,8 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
addDrawableChild(rightButton)
addDrawableChild(leftButton)
currentCategoryId = categories.firstKey()
currentPokemon = this.currentCategory().pokemon[currentSelection]
currentCategory = categories.first()
currentPokemon = currentCategory.pokemon[currentSelection]
with(currentPokemon) {
modelWidget = ModelWidget(
@@ -144,11 +135,11 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
) {
CobblemonNetwork.sendPacketToServer(
SelectStarterPacket(
categoryId = currentCategoryId,
categoryName = currentCategory.name,
selected = currentSelection
)
)
this.close()
MinecraftClient.getInstance().setScreen(null)
}
addDrawableChild(selectionButton)
@@ -163,7 +154,7 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
starterRoundaboutLeft = StarterRoundabout(
pX = x + 89, pY = height / 2 + 84,
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
pokemon = this.currentCategory().pokemon[leftOfCurrentSelection()],
pokemon = currentCategory.pokemon[leftOfCurrentSelection()],
clickAction = { _, _ -> this.left() },
rotationVector = this.modelWidget.rotVec
)
@@ -171,7 +162,7 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
starterRoundaboutRight = StarterRoundabout(
pX = x + 149, pY = height / 2 + 84,
pWidth = StarterRoundabout.MODEL_WIDTH, pHeight = StarterRoundabout.MODEL_HEIGHT,
pokemon = this.currentCategory().pokemon[rightOfCurrentSelection()],
pokemon = currentCategory.pokemon[rightOfCurrentSelection()],
clickAction = { _, _ -> this.right() },
rotationVector = this.modelWidget.rotVec
)
@@ -278,8 +269,8 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
super.render(context, mouseX, mouseY, delta)
}
fun changeCategory(id: Identifier) {
currentCategoryId = id
fun changeCategory(category: RenderableStarterCategory) {
currentCategory = category
currentSelection = 0
updateSelection()
}
@@ -290,7 +281,7 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
updateSelection()
}
private fun rightOfCurrentSelection() : Int = if (currentSelection + 1 <= this.currentCategory().pokemon.size - 1) currentSelection + 1 else 0
private fun rightOfCurrentSelection() : Int = if (currentSelection + 1 <= currentCategory.pokemon.size - 1) currentSelection + 1 else 0
private fun left() {
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK, 1.0F))
@@ -298,16 +289,16 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
updateSelection()
}
private fun leftOfCurrentSelection() : Int = if (currentSelection - 1 == -1) this.currentCategory().pokemon.size - 1 else currentSelection - 1
private fun leftOfCurrentSelection() : Int = if (currentSelection - 1 == -1) currentCategory.pokemon.size - 1 else currentSelection - 1
private fun updateSelection() {
currentPokemon = this.currentCategory().pokemon[currentSelection].also {
currentPokemon = currentCategory.pokemon[currentSelection].also {
modelWidget.pokemon = it
typeWidget = typeWidget(it, (width - BASE_WIDTH) / 2, (height - BASE_HEIGHT) / 2)
}
starterRoundaboutLeft.pokemon = this.currentCategory().pokemon[leftOfCurrentSelection()]
starterRoundaboutLeft.pokemon = currentCategory.pokemon[leftOfCurrentSelection()]
starterRoundaboutCenter.pokemon = currentPokemon
starterRoundaboutRight.pokemon = this.currentCategory().pokemon[rightOfCurrentSelection()]
starterRoundaboutRight.pokemon = currentCategory.pokemon[rightOfCurrentSelection()]
}
private fun typeWidget(pokemon: RenderablePokemon, x: Int, y: Int) : TypeWidget {
@@ -326,7 +317,5 @@ class StarterSelectionScreen(categories: Map<Identifier, RenderableStarterCatego
)
}
private fun currentCategory(): RenderableStarterCategory = this.categories[this.currentCategoryId]!!
override fun shouldPause() = true
}
@@ -12,14 +12,14 @@ import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.client.gui.startselection.StarterSelectionScreen
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.api.starter.RenderableStarterCategory
import com.cobblemon.mod.common.config.starter.RenderableStarterCategory
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget
import net.minecraft.client.sound.PositionedSoundInstance
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.text.Text
import net.minecraft.util.Identifier
class CategoryList(
private val paneWidth: Int,
@@ -28,7 +28,7 @@ class CategoryList(
bottomOffset: Int,
private val entryWidth: Int,
entryHeight: Int,
private val categories: Map<Identifier, RenderableStarterCategory>,
private val categories: List<RenderableStarterCategory>,
val x: Int, val y: Int,
private val minecraft: MinecraftClient = MinecraftClient.getInstance(),
private val starterSelectionScreen: StarterSelectionScreen
@@ -44,6 +44,7 @@ class CategoryList(
companion object {
private const val CATEGORY_BUTTON_WIDTH = 51.5f
private const val CATEGORY_BUTTON_HEIGHT = 16f
private const val ENTRY_X_OFFSET = 10f
private val categoryResource = cobblemonResource("textures/gui/starterselection/starterselection_slot.png")
}
@@ -52,12 +53,19 @@ class CategoryList(
this.setRenderHorizontalShadows(false)
this.setRenderBackground(false)
this.setRenderSelection(false)
this.categories.forEach { (id, category) ->
this.addEntry(Category(id, category))
}
}
private var entriesCreated = false
private fun createEntries() = categories.map {
Category(it)
}
override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
if (!entriesCreated) {
createEntries().forEach { addEntry(it) }
entriesCreated = true
}
context.enableScissor(
x,
y,
@@ -72,13 +80,15 @@ class CategoryList(
this.updateSize(this.paneWidth, this.paneHeight, this.y, this.y + this.paneHeight)
this.setLeftPos(this.x)
}
private fun scale(n: Int): Int = (this.client.window.scaleFactor * n).toInt()
override fun getRowWidth() = this.entryWidth
override fun getScrollbarPositionX(): Int {
return this.left + this.width - 5
}
inner class Category(private val id: Identifier, private val category: RenderableStarterCategory) : Entry<Category>() {
inner class Category(private val category: RenderableStarterCategory) : Entry<Category>() {
override fun render(
context: DrawContext,
@@ -111,7 +121,7 @@ class CategoryList(
)
drawScaledText(
context = context,
text = category.displayName.copy(),
text = category.displayNameText,
x = x + 28,
y = y + 4.5F,
scale = 1F,
@@ -122,7 +132,7 @@ class CategoryList(
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
starterSelectionScreen.changeCategory(this.id)
starterSelectionScreen.changeCategory(category = category)
minecraft.soundManager.play(PositionedSoundInstance.master(CobblemonSounds.GUI_CLICK, 1.0F))
return true
}
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.api.gui.blitk
import com.cobblemon.mod.common.api.moves.Move
import com.cobblemon.mod.common.api.moves.MoveSet
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.species
import com.cobblemon.mod.common.api.reactive.Observable.Companion.emitWhile
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.scheduling.Schedulable
@@ -35,7 +34,6 @@ import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MoveSwa
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWidget
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
import com.cobblemon.mod.common.client.render.drawScaledText
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
import com.cobblemon.mod.common.pokemon.Gender
@@ -615,27 +613,6 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
) {
this.focused = null
}
if (Cobblemon.config.enableDebugKeys) {
val model = PokemonModelRepository.getPoser(selectedPokemon.species.resourceIdentifier, selectedPokemon.aspects)
if (keyCode == InputUtil.GLFW_KEY_UP) {
model.profileTranslation = model.profileTranslation.add(0.0, -0.01, 0.0)
}
if (keyCode == InputUtil.GLFW_KEY_DOWN) {
model.profileTranslation = model.profileTranslation.add(0.0, 0.01, 0.0)
}
if (keyCode == InputUtil.GLFW_KEY_LEFT) {
model.profileTranslation = model.profileTranslation.add(-0.01, 0.0, 0.0)
}
if (keyCode == InputUtil.GLFW_KEY_RIGHT) {
model.profileTranslation = model.profileTranslation.add(0.01, 0.0, 0.0)
}
if (keyCode == InputUtil.GLFW_KEY_EQUAL) {
model.profileScale += 0.01F
}
if (keyCode == InputUtil.GLFW_KEY_MINUS) {
model.profileScale -= 0.01F
}
}
return super.keyPressed(keyCode, scanCode, modifiers)
}
@@ -643,14 +620,4 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, 1.0F))
}
override fun close() {
if (Cobblemon.config.enableDebugKeys) {
val model = PokemonModelRepository.getPoser(selectedPokemon.species.resourceIdentifier, selectedPokemon.aspects)
MinecraftClient.getInstance().player?.sendMessage(Text.of("Profile Translation: ${model.profileTranslation}"))
MinecraftClient.getInstance().player?.sendMessage(Text.of("Profile Scale: ${model.profileScale}"))
Cobblemon.LOGGER.info("override var profileTranslation = Vec3d(${model.profileTranslation.x}, ${model.profileTranslation.y}, ${model.profileTranslation.z})")
Cobblemon.LOGGER.info("override var profileScale = ${model.profileScale}F")
}
super.close()
}
}
@@ -8,14 +8,11 @@
package com.cobblemon.mod.common.client.keybind
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.client.keybind.keybinds.DebugKeybindings
import com.cobblemon.mod.common.client.keybind.keybinds.DownShiftPartyBinding
import com.cobblemon.mod.common.client.keybind.keybinds.HidePartyBinding
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
import com.cobblemon.mod.common.client.keybind.keybinds.UpShiftPartyBinding
import com.cobblemon.mod.common.config.CobblemonConfig
import com.cobblemon.mod.common.platform.events.PlatformEvents
import net.minecraft.client.option.KeyBinding
@@ -26,17 +23,13 @@ import net.minecraft.client.option.KeyBinding
* @since 2022-02-17
*/
object CobblemonKeyBinds {
private val keyBinds = arrayListOf<CobblemonKeyBinding>()
init {
PlatformEvents.CLIENT_TICK_POST.subscribe { this.onTick() }
if (Cobblemon.config.enableDebugKeys) {
DebugKeybindings.keybindings.forEach {
this.queue(it)
}
}
}
private val keyBinds = arrayListOf<CobblemonKeyBinding>()
val HIDE_PARTY = this.queue(HidePartyBinding)
// ToDo enable again down the line
//val POKENAV = this.queue(PokeNavigatorBinding)
@@ -9,9 +9,7 @@
package com.cobblemon.mod.common.client.keybind
import com.cobblemon.mod.common.api.text.red
import com.cobblemon.mod.common.api.text.yellow
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.keybind.keybinds.SummaryBinding
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
import com.cobblemon.mod.common.util.lang
import net.minecraft.client.MinecraftClient
@@ -27,20 +25,12 @@ abstract class CobblemonPartyLockedKeyBinding(
category: String
) : CobblemonKeyBinding(name, type, key, category) {
private var skippedStarterSelectionMessageShown = false
override fun onTick() {
if (this.wasPressed() && this.hasPartyMembers()) {
this.onPress()
}
}
/**
* Checks if the player has any party members, and
*
* - Handles the starter selection if the player doesn't have any party members.
* - Shows a message if the player initially skipped the starter selection.
*/
private fun hasPartyMembers(): Boolean {
val havePokemon = CobblemonClient.storage.myParty.slots.any { it != null }
val starterSelected = CobblemonClient.clientPlayerData.starterSelected
@@ -52,18 +42,6 @@ abstract class CobblemonPartyLockedKeyBinding(
RequestStarterScreenPacket().sendToServer()
}
return false
} else if (!startersLocked && !starterSelected && havePokemon) {
if (!skippedStarterSelectionMessageShown) {
MinecraftClient.getInstance().player?.sendMessage(
lang(
"ui.starter.skippedchoosing",
SummaryBinding.boundKey().localizedText
).yellow(), false
)
/** Only show the info message about skipping the selection once per MC instance */
skippedStarterSelectionMessageShown = true
}
return true
}
return true
}
@@ -10,5 +10,4 @@ package com.cobblemon.mod.common.client.keybind
object KeybindCategories {
const val COBBLEMON_CATEGORY = "key.cobblemon.categories.cobblemon"
const val COBBLEMON_DEBUG_CATEGORY = "key.cobblemon.categories.cobblemon.debug"
}
@@ -1,140 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.keybind.keybinds
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.client.keybind.CobblemonKeyBinding
import com.cobblemon.mod.common.client.keybind.KeybindCategories
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import net.minecraft.client.MinecraftClient
import net.minecraft.client.util.InputUtil
import net.minecraft.text.Text
object DebugKeybindings {
val keybindings = listOf(
ScaleUpKeybinding(),
ScaleDownKeybinding(),
TranslateLeftKeybinding(),
TranslateRightKeybinding(),
TranslateUpKeybinding(),
TranslateDownKeybinding(),
PrintModelSettingsKeybinding()
)
class ScaleUpKeybinding(): CobblemonKeyBinding(
"key.cobblemon.scaleportraitup",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_EQUAL,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitScale += 0.01F
}
}
}
class ScaleDownKeybinding(): CobblemonKeyBinding(
"key.cobblemon.scaleportraitdown",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_MINUS,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitScale -= 0.01F
}
}
}
class TranslateUpKeybinding: CobblemonKeyBinding(
"key.cobblemon.translateportraitup",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_I,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitTranslation = model.portraitTranslation.add(0.0, -0.01, 0.0)
}
}
}
class TranslateDownKeybinding(): CobblemonKeyBinding(
"key.cobblemon.translateportraitdown",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_K,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitTranslation = model.portraitTranslation.add(0.0, 0.01, 0.0)
}
}
}
class TranslateLeftKeybinding(): CobblemonKeyBinding(
"key.cobblemon.translateportraitleft",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_J,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitTranslation = model.portraitTranslation.add(-0.01, 0.0, 0.0)
}
}
}
class TranslateRightKeybinding(): CobblemonKeyBinding(
"key.cobblemon.translateportraitright",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_L,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
model.portraitTranslation = model.portraitTranslation.add(0.01, 0.0, 0.0)
}
}
}
class PrintModelSettingsKeybinding() : CobblemonKeyBinding(
"key.cobblemon.printmodelsettings",
InputUtil.Type.KEYSYM,
InputUtil.GLFW_KEY_PERIOD,
KeybindCategories.COBBLEMON_DEBUG_CATEGORY
) {
override fun onPress() {
val currentlySelectedPokemon = CobblemonClient.storage.myParty.get(CobblemonClient.storage.selectedSlot)
if (currentlySelectedPokemon != null) {
val model = PokemonModelRepository.getPoser(currentlySelectedPokemon.species.resourceIdentifier, currentlySelectedPokemon.aspects)
MinecraftClient.getInstance().player?.sendMessage(Text.of("Portrait Translation: ${model.portraitTranslation}"))
MinecraftClient.getInstance().player?.sendMessage(Text.of("Portrait Scale: ${model.portraitScale}"))
Cobblemon.LOGGER.info("override var portraitTranslation = Vec3d(${model.portraitTranslation.x}, ${model.portraitTranslation.y}, ${model.portraitTranslation.z})")
Cobblemon.LOGGER.info("override var portraitScale = ${model.portraitScale}F")
}
}
}
}
@@ -40,8 +40,7 @@ object SpawnSnowstormEntityParticleHandler : ClientNetworkPacketHandler<SpawnSno
runtime = particleRuntime,
sourceVelocity = { entity.velocity },
sourceAlive = { !entity.isRemoved },
sourceVisible = { !entity.isInvisible },
entity = entity
sourceVisible = { !entity.isInvisible }
)
storm.spawn()
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.client.particle
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleEffect
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterAction
import com.cobblemon.mod.common.client.render.MatrixWrapper
@@ -43,11 +42,6 @@ class ParticleStorm(
): NoRenderParticle(world, matrixWrapper.getOrigin().x, matrixWrapper.getOrigin().y, matrixWrapper.getOrigin().z) {
fun spawn() {
if (entity != null) {
runtime.environment.getQueryStruct()
.addFunction("entity_width") { DoubleValue(entity.boundingBox.xLength) }
.addFunction("entity_height") { DoubleValue(entity.boundingBox.yLength) }
.addFunction("entity_size") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength }) }
.addFunction("entity_radius") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength } / 2) }
// TODO replace with a generified call to if (entity is MoLangEntity) entity.applyVariables(env) or w/e
runtime.environment.setSimpleVariable("entity_width", DoubleValue(entity.boundingBox.xLength))
runtime.environment.setSimpleVariable("entity_height", DoubleValue(entity.boundingBox.yLength))
@@ -73,8 +67,6 @@ class ParticleStorm(
// The idea is that some instantaneous particle effects could teeeechnically be over before they start.
var hasPlayedOnce = false
var distanceTravelled = 0F
companion object {
var contextStorm: ParticleStorm? = null
}
@@ -83,7 +75,6 @@ class ParticleStorm(
init {
runtime.execute(effect.emitter.startExpressions)
effect.emitter.creationEvents.forEach { it.trigger(this, null) }
}
override fun getMaxAge(): Int {
@@ -93,7 +84,6 @@ class ParticleStorm(
override fun markDead() {
super.markDead()
if (!despawned) {
effect.emitter.expirationEvents.forEach { it.trigger(this, null) }
despawned = true
onDespawn()
}
@@ -126,12 +116,6 @@ class ParticleStorm(
y = pos.y
z = pos.z
val oldDistanceTravelled = distanceTravelled
distanceTravelled += Vec3d(x - prevPosX, y - prevPosY, z - prevPosZ).length().toFloat()
effect.emitter.travelDistanceEvents.check(this, null, oldDistanceTravelled.toDouble(), distanceTravelled.toDouble())
effect.emitter.loopingTravelDistanceEvents.forEach { it.check(this, null, oldDistanceTravelled.toDouble(), distanceTravelled.toDouble()) }
effect.emitter.eventTimeline.check(this, null, (age - 1) / 20.0, age / 20.0)
runtime.environment.setSimpleVariable("emitter_random_1", DoubleValue(Random.Default.nextDouble()))
runtime.environment.setSimpleVariable("emitter_random_2", DoubleValue(Random.Default.nextDouble()))
@@ -153,27 +137,18 @@ class ParticleStorm(
}
}
fun getNextParticleSpawnPosition(): Vec3d {
fun spawnParticle() {
runtime.environment.setSimpleVariable("particle_random_1", DoubleValue(Random.Default.nextDouble()))
runtime.environment.setSimpleVariable("particle_random_2", DoubleValue(Random.Default.nextDouble()))
runtime.environment.setSimpleVariable("particle_random_3", DoubleValue(Random.Default.nextDouble()))
runtime.environment.setSimpleVariable("particle_random_4", DoubleValue(Random.Default.nextDouble()))
val newPosition = transformPosition(effect.emitter.shape.getNewParticlePosition(runtime, entity))
return newPosition
}
fun getNextParticleVelocity(nextParticlePosition: Vec3d): Vec3d {
val center = transformPosition(effect.emitter.shape.getCenter(runtime, entity))
val initialVelocity = effect.particle.motion.getInitialVelocity(runtime, storm = this, particlePos = nextParticlePosition, emitterPos = center)
return initialVelocity
val newPosition = transformPosition(effect.emitter.shape.getNewParticlePosition(runtime, entity))
val initialVelocity = effect.particle.motion.getInitialVelocity(runtime, storm = this, particlePos = newPosition, emitterPos = center)
val velocity = initialVelocity
.multiply(1 / 20.0)
.add(if (effect.space.localVelocity) sourceVelocity() else Vec3d.ZERO)
}
fun spawnParticle() {
val newPosition = getNextParticleSpawnPosition()
val velocity = getNextParticleVelocity(newPosition)
contextStorm = this
world.addParticle(particleEffect, newPosition.x, newPosition.y, newPosition.z, velocity.x, velocity.y, velocity.z)
@@ -89,14 +89,6 @@ class SnowstormParticle(
var viewDirection = Vec3d.ZERO
var originPos = Vec3d(storm.getX(), storm.getY(), storm.getZ())
fun getX() = x
fun getY() = y
fun getZ() = z
fun getVelocityX() = velocityX
fun getVelocityY() = velocityY
fun getVelocityZ() = velocityZ
fun getSpriteFromAtlas(): Sprite {
val atlas = MinecraftClient.getInstance().particleManager.particleAtlasTexture
@@ -126,7 +118,6 @@ class SnowstormParticle(
storm.particles.add(this)
gravityStrength = 0F
particleTextureSheet = if (invisible) NO_RENDER else PARTICLE_SHEET_TRANSLUCENT
storm.effect.particle.creationEvents.forEach { it.trigger(storm, this) }
// when (storm.effect.particle.material) {
// ParticleMaterial.ALPHA -> ParticleMaterials.ALPHA
// ParticleMaterial.OPAQUE -> ParticleMaterials.OPAQUE
@@ -189,8 +180,8 @@ class SnowstormParticle(
viewDirection = viewDirection
)
val xSize = storm.runtime.resolveDouble(storm.effect.particle.sizeX).toFloat() / 1.5.toFloat()
val ySize = storm.runtime.resolveDouble(storm.effect.particle.sizeY).toFloat() / 1.5.toFloat()
val xSize = storm.runtime.resolveDouble(storm.effect.particle.sizeX).toFloat()
val ySize = storm.runtime.resolveDouble(storm.effect.particle.sizeY).toFloat()
val particleVertices = arrayOf(
Vector3f(-xSize, -ySize, 0.0f),
@@ -254,7 +245,6 @@ class SnowstormParticle(
angularVelocity += storm.effect.particle.rotation.getAngularAcceleration(storm.runtime, angularVelocity) / 20
if (age > maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
storm.effect.particle.expirationEvents.forEach { it.trigger(storm, this)}
markDead()
return
} else {
@@ -295,8 +285,6 @@ class SnowstormParticle(
age++
this.move(velocityX, velocityY, velocityZ)
storm.effect.particle.timeline.check(storm, this, (age - 1) / 20.0, age / 20.0)
}
override fun move(dx: Double, dy: Double, dz: Double) {
@@ -1,165 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.client.render.block
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.item.PokemonItem
import net.minecraft.block.HorizontalFacingBlock
import net.minecraft.client.MinecraftClient
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.VertexConsumer
import net.minecraft.client.render.VertexConsumerProvider
import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.model.json.ModelTransformationMode
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.item.BannerItem
import net.minecraft.item.BedItem
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.item.Items
import net.minecraft.nbt.NbtInt
import net.minecraft.util.math.Direction
import net.minecraft.util.math.RotationAxis
import net.minecraft.world.World
class DisplayCaseRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEntityRenderer<DisplayCaseBlockEntity> {
val coinPouchStack: ItemStack by lazy { ItemStack(CobblemonItems.RELIC_COIN_POUCH).also { it.setSubNbt("CustomModelData", NbtInt.of(1)) } }
override fun render(
entity: DisplayCaseBlockEntity,
tickDelta: Float,
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
overlay: Int
) {
val stack: ItemStack = if (entity.getStack().isOf(CobblemonItems.RELIC_COIN_POUCH)) {
coinPouchStack
} else {
entity.getStack()
}
val world = entity.world ?: return
val posType = getPositioningType(stack, world)
val blockState = if (entity.world != null) entity.cachedState
else (CobblemonBlocks.DISPLAY_CASE.defaultState.with(HorizontalFacingBlock.FACING, Direction.NORTH))
val yRot = if (posType == PositioningType.ITEM_MODEL) blockState.get(HorizontalFacingBlock.FACING).opposite.asRotation()
else blockState.get(HorizontalFacingBlock.FACING).asRotation()
if (stack.item is PokemonItem) {
renderPokemon(
matrices,
vertexConsumers,
light,
stack,
yRot
)
return
}
matrices.push()
matrices.translate(0.5f, 0.4f, 0.5f)
matrices.scale(posType.scaleX, posType.scaleY, posType.scaleZ)
matrices.translate(posType.transX, posType.transY, posType.transZ)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yRot))
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(posType.rotY))
MinecraftClient.getInstance().itemRenderer.renderItem(
stack,
ModelTransformationMode.GROUND,
light,
overlay,
matrices,
vertexConsumers,
entity.world,
0
)
matrices.pop()
}
private fun renderPokemon(
matrices: MatrixStack,
vertexConsumers: VertexConsumerProvider,
light: Int,
stack: ItemStack,
yRot: Float
) {
val item = stack.item as? PokemonItem ?: return
val pokemon = item.asPokemon(stack) ?: return
val model = PokemonModelRepository.getPoser(pokemon.species.resourceIdentifier, pokemon.aspects)
val renderLayer = model.getLayer(PokemonModelRepository.getTexture(pokemon.species.resourceIdentifier, pokemon.aspects, 0F))
val tint = item.tint(stack)
val vertexConsumer: VertexConsumer = vertexConsumers.getBuffer(renderLayer)
val scale = 0.25f
matrices.push()
matrices.scale(1f, -1f, -1f)
matrices.translate(0.5f, -0.69f, -0.5f)
matrices.scale(scale, scale, scale)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yRot))
model.setupAnimStateless(PoseType.PROFILE)
model.withLayerContext(vertexConsumers, null, PokemonModelRepository.getLayers(pokemon.species.resourceIdentifier, pokemon.aspects)) {
model.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, tint.x, tint.y, tint.z, tint.w)
}
matrices.pop()
}
companion object {
private val mobHeads = listOf<Item>(
Items.SKELETON_SKULL,
Items.WITHER_SKELETON_SKULL,
Items.ZOMBIE_HEAD,
Items.PIGLIN_HEAD,
Items.PLAYER_HEAD,
Items.DRAGON_HEAD,
Items.CREEPER_HEAD
)
private fun getPositioningType(stack: ItemStack, world: World) = when {
mobHeads.contains(stack.item) -> PositioningType.MOB_HEAD
stack.item is BedItem -> PositioningType.BED
stack.item is BannerItem -> PositioningType.BANNER
stack.item is PokeBallItem -> PositioningType.POKE_BALL
stack.item == CobblemonItems.RELIC_COIN_POUCH -> PositioningType.COIN_POUCH
stack.item == CobblemonItems.PASTURE -> PositioningType.PASTURE
stack.item == CobblemonItems.POKEMON_MODEL -> PositioningType.ITEM_MODEL
stack.item == Items.SHIELD -> PositioningType.SHIELD
stack.item == Items.DECORATED_POT -> PositioningType.MOB_HEAD
MinecraftClient.getInstance().itemRenderer.getModel(stack, world, null, 0).hasDepth() -> PositioningType.BLOCK_MODEL
else -> PositioningType.ITEM_MODEL
}
}
private enum class PositioningType(
val scaleX: Float, val scaleY: Float, val scaleZ: Float,
val transX: Float, val transY: Float, val transZ: Float,
val rotY: Float = 0f
) {
POKE_BALL(1f, 1f, 1f, 0f, 0.04f, 0f),
BLOCK_MODEL(1f, 1f, 1f, 0f, -0.15f, 0f),
ITEM_MODEL(1f, 1f, 1f, 0f, 0.04f, 0f),
BED(1f, 1f, 1f, 0f, -0.02f, 0f),
BANNER(1f, 1f, 1f, 0f, -0.02f, 0f, 180f),
MOB_HEAD(1f, 1f, 1f, 0f, -0.025f, 0f, 180f),
SHIELD(1f, 1f, 1f, 0f, -0.045f, 0f, 180f),
PASTURE(1f, 1f, 1f, 0f, 0.0375f, 0f),
COIN_POUCH(1f, 1f, 1f, 0f, 0.415f, 0f)
}
}
@@ -19,10 +19,8 @@ import net.minecraft.client.render.block.entity.BlockEntityRenderer
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory
import net.minecraft.client.render.model.json.ModelTransformationMode
import net.minecraft.client.util.math.MatrixStack
import net.minecraft.state.property.DirectionProperty
import net.minecraft.util.math.Direction
import net.minecraft.util.math.RotationAxis
import net.minecraft.util.math.Vec3d
class FossilAnalyzerRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEntityRenderer<FossilAnalyzerBlockEntity> {
@@ -36,29 +34,21 @@ class FossilAnalyzerRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEnt
) {
val blockState = if (entity.world != null) entity.cachedState
else (CobblemonBlocks.FOSSIL_ANALYZER.defaultState.with(HorizontalFacingBlock.FACING, Direction.SOUTH) as BlockState)
// We shouldn't have to do any complex rendering when the block isn't a multiblock
val yRot = blockState.get(HorizontalFacingBlock.FACING).asRotation()
//We shouldnt have to do any complex rendering when the block isn't a multiblock
if (entity.multiblockStructure == null) {
return
}
val direction = blockState.get(HorizontalFacingBlock.FACING)
val yRot = direction.asRotation() + if(direction == Direction.WEST || direction == Direction.EAST) 180F else 0F
val struct = entity.multiblockStructure as FossilMultiblockStructure
struct.fossilInventory.forEachIndexed { index, fossilStack ->
matrices.push()
val dirOffset = when (direction) {
Direction.NORTH -> Vec3d(0.0, 0.0, 0.05)
Direction.SOUTH -> Vec3d(0.0, 0.0, -0.05)
Direction.EAST -> Vec3d(-0.05, 0.0, 0.0)
Direction.WEST -> Vec3d(0.05, 0.0, 0.0)
else -> Vec3d.ZERO
}
matrices.translate(0.5 + dirOffset.x,0.4 + (index * 0.1) + dirOffset.y, 0.5 + dirOffset.z)
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yRot))
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180F))
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90F))
matrices.translate(0.5, 0.4 + (index * 0.1F), 0.55)
matrices.scale(0.7F, 0.7F, 0.7F)
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(180F))
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-yRot))
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90F))
MinecraftClient.getInstance().itemRenderer.renderItem(fossilStack, ModelTransformationMode.NONE, light, overlay, matrices, vertexConsumers, entity.world, 0)
@@ -72,7 +72,7 @@ class RestorationTankRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEn
val fluidModel = if (struct.isRunning()) FLUID_MODELS[8]
else if (struct.createdPokemon != null) FLUID_MODELS[7]
else FLUID_MODELS[fillLevel.coerceAtMost(FLUID_MODELS.size - 1) - 1]
else FLUID_MODELS[fillLevel-1]
fluidModel.getQuads(entity.cachedState, null, entity.world?.random).forEach { quad ->
transparentBuffer?.quad(matrices.peek(), quad, 0.75f, 0.75f, 0.75f, light, OverlayTexture.DEFAULT_UV)
}
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.scheduling.afterOnClient
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
import com.cobblemon.mod.common.client.render.MatrixWrapper
@@ -45,7 +46,6 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.getDoubleOrNull
import com.cobblemon.mod.common.util.getStringOrNull
import com.cobblemon.mod.common.util.plus
import net.minecraft.client.model.ModelPart
import net.minecraft.client.render.OverlayTexture
import net.minecraft.client.render.RenderLayer
@@ -697,7 +697,6 @@ abstract class PoseableEntityModel<T : Entity>(
val portion = (state.animationSeconds - primaryAnimation.started) / primaryAnimation.duration
state.primaryOverridePortion = 1 - primaryAnimation.curve(portion)
if (!primaryAnimation.run(entity, this, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch, 1 - state.primaryOverridePortion)) {
primaryAnimation.afterAction.accept(Unit)
state.primaryAnimation = null
state.primaryOverridePortion = 1F
}
@@ -716,7 +715,6 @@ abstract class PoseableEntityModel<T : Entity>(
//This is used to set additional entity type specific context
open fun setupEntityTypeContext(entity: T?) {}
//Called by LivingEntityRenderer's render method before calling model.render (which is this.render in this case)
override fun setAngles(
entity: T,
limbSwing: Float,
@@ -747,16 +745,19 @@ abstract class PoseableEntityModel<T : Entity>(
curve = { 1F }
)
state.addPrimaryAnimation(primaryAnimation)
primaryAnimation.afterAction += {
afterOnClient(seconds = primaryAnimation.duration) {
state.setPose(desirablePose.poseName)
if (state.primaryAnimation == primaryAnimation) {
state.primaryAnimation = null
}
}
} else if (transition != null) {
val animation = transition(previousPose, desirablePose)
val primaryAnimation = if (animation is PrimaryAnimation) animation else PrimaryAnimation(animation, curve = { 1F })
primaryAnimation.afterAction += {
state.addPrimaryAnimation(primaryAnimation)
afterOnClient(seconds = primaryAnimation.duration) {
state.setPose(desirablePose.poseName)
}
state.addPrimaryAnimation(primaryAnimation)
} else {
state.setPose(poses.values.first { desirablePoseType in it.poseTypes && (it.condition == null || (entity != null && it.condition.invoke(entity))) }.poseName)
}
@@ -56,8 +56,6 @@ import net.minecraft.util.math.Vec3d
* handling all the state for an entity's model, and needs to be conscious of the fact that the
* model may change without this state changing.
*
* This also handles setting up the molang runtime that animations have access to
*
* @author Hiroku
* @since December 5th, 2021
*/
@@ -166,11 +164,6 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
val previousAge = age
updateAge(age + 1)
runEffects(entity, previousAge, age)
val primaryAnimation = primaryAnimation ?: return
if (primaryAnimation.started + primaryAnimation.duration <= animationSeconds) {
this.primaryAnimation = null
primaryAnimation.afterAction.accept(Unit)
}
}
abstract fun updatePartialTicks(partialTicks: Float)
@@ -275,7 +268,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
val pose = currentPose?.let(model::getPose)
allStatefulAnimations.forEach { it.applyEffects(entity, this, previousSeconds, currentSeconds) }
primaryAnimation?.animation?.applyEffects(entity, this, previousSeconds, currentSeconds)
pose?.idleAnimations?.filter { shouldIdleRun(it, 0.5F) }?.forEach { it.applyEffects(entity, this, previousSeconds, currentSeconds) }
pose?.idleAnimations?.filter { shouldIdleRun(it, 0.5F) }
}
}
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityMo
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.frame.ModelFrame
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
import java.util.function.Consumer
import net.minecraft.entity.Entity
/**
@@ -40,7 +39,6 @@ class PrimaryAnimation<T : Entity>(
): StatefulAnimation<T, ModelFrame> {
var started = -1F
override val duration: Float = animation.duration
var afterAction: Consumer<Unit> = Consumer { }
override fun run(
entity: T?,
@@ -15,7 +15,7 @@ import net.minecraft.entity.Entity
/**
* An animation that can run without an entity associated. These are
* locked to a specific [ModelFrame], and CAN be given an entity along with
* locked to a specific frame, and CAN be given an entity along with
* limb swing and age information, but might not.
*
* @author Hiroku
@@ -32,11 +32,11 @@ class BlockEntityModel(val root: Bone) : PoseableEntityModel<Entity>() {
)
closedPose.transitions[openPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "opening")
bedrockStateful("gilded_chest", "opening").andThen { _, state -> state.setPose(openPose.poseName) }
}
openPose.transitions[closedPose.poseName] = { _, _ ->
bedrockStateful("gilded_chest", "closing")
bedrockStateful("gilded_chest", "closing").andThen { _, state -> state.setPose(closedPose.poseName) }
}
}
@@ -51,8 +51,8 @@ class AncientPokeBallModel(root: ModelPart) : PokeBallModel(root), PokeBallFrame
transformTicks = 0
)
shut.transitions[open.poseName] = { _, _ -> bedrockStateful("ancient_poke_ball", "open") }
open.transitions[shut.poseName] = { _, _ -> bedrockStateful("ancient_poke_ball", "shut") }
shut.transitions[open.poseName] = { _, _ -> bedrockStateful("ancient_poke_ball", "open").andThen { entity, state -> state.setPose(open.poseName) } }
open.transitions[shut.poseName] = { _, _ -> bedrockStateful("ancient_poke_ball", "shut").andThen { entity, state -> state.setPose(shut.poseName) } }
midair.transitions[open.poseName] = shut.transitions[open.poseName]!!
}
}
@@ -91,18 +91,14 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
@SerializedName("profileTranslation")
private val _profileTranslation: Vec3d? = null
//Some weirdness going on here, vars have to be initialized, gson doesn't like multiple fields with the same name
@Transient
override var portraitScale = 1F
override val portraitScale
get() = _portraitScale ?: 1F
@Transient
override var portraitTranslation = Vec3d.ZERO
override val portraitTranslation
get() = _portraitTranslation ?: Vec3d(0.0, 0.0, 0.0)
@Transient
override var profileScale = 1F
override val profileScale
get() = _profileScale ?: 1F
@Transient
override var profileTranslation = Vec3d.ZERO
override val profileTranslation
get() = _profileTranslation ?: Vec3d(0.0, 0.0, 0.0)
@@ -56,14 +56,14 @@ abstract class PokemonPoseableModel : PoseableEntityModel<PokemonEntity>() {
}
@Transient
open var portraitScale: Float = 1F
open val portraitScale: Float = 1F
@Transient
open var portraitTranslation: Vec3d = Vec3d.ZERO
open val portraitTranslation: Vec3d = Vec3d.ZERO
@Transient
open var profileScale: Float = 1F
open val profileScale: Float = 1F
@Transient
open var profileTranslation: Vec3d = Vec3d.ZERO
open val profileTranslation: Vec3d = Vec3d.ZERO
open fun getFaintAnimation(
pokemonEntity: PokemonEntity,
@@ -24,11 +24,11 @@ class AbraModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("abra")
override val head = getPart("head")
override var portraitScale = 1.8F
override var portraitTranslation = Vec3d(0.0, 0.2, 0.0)
override val portraitScale = 1.8F
override val portraitTranslation = Vec3d(0.0, 0.2, 0.0)
override var profileScale = 0.85F
override var profileTranslation = Vec3d(0.0, 0.7, 0.0)
override val profileScale = 0.85F
override val profileTranslation = Vec3d(0.0, 0.7, 0.0)
lateinit var standing: PokemonPose
lateinit var walking: PokemonPose
@@ -20,11 +20,11 @@ class AerodactylModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("aerodactyl")
override val head = getPart("head")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3d(-1.0, -0.65, 0.0)
override val portraitScale = 1.9F
override val portraitTranslation = Vec3d(-1.0, -0.65, 0.0)
override var profileScale = 0.55F
override var profileTranslation = Vec3d(0.0, 0.55, 0.0)
override val profileScale = 0.55F
override val profileTranslation = Vec3d(0.0, 0.55, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
@@ -30,11 +30,11 @@ class AlakazamModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
override val leftLeg = getPart("left_upper_leg")
override val rightLeg = getPart("right_upper_leg")
override var portraitScale = 1.75F
override var portraitTranslation = Vec3d(-0.25, 0.85, 0.0)
override val portraitScale = 1.75F
override val portraitTranslation = Vec3d(-0.25, 0.85, 0.0)
override var profileScale = 0.73F
override var profileTranslation = Vec3d(0.0, 0.65, 0.0)
override val profileScale = 0.73F
override val profileTranslation = Vec3d(0.0, 0.65, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -29,11 +29,11 @@ class ArbokModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("arbok")
override val head = getPart("head_ai")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3d(-0.4, 1.0, 0.0)
override val portraitScale = 1.5F
override val portraitTranslation = Vec3d(-0.4, 1.0, 0.0)
override var profileScale = 0.67F
override var profileTranslation = Vec3d(0.0, 0.7, 0.0)
override val profileScale = 0.67F
override val profileTranslation = Vec3d(0.0, 0.7, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -27,11 +27,11 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3d(-0.4, 0.7, 0.0)
override val portraitScale = 1.5F
override val portraitTranslation = Vec3d(-0.4, 0.7, 0.0)
override var profileScale = 0.76F
override var profileTranslation = Vec3d(0.0, 0.57, 0.0)
override val profileScale = 0.76F
override val profileTranslation = Vec3d(0.0, 0.57, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
@@ -31,11 +31,11 @@ class ArticunoModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
override val leftWing = getPart("leftwing")
override val rightWing = getPart("rightwing")
override var portraitScale = 2.8F
override var portraitTranslation = Vec3d(-0.35, 0.6, 0.0)
override val portraitScale = 2.8F
override val portraitTranslation = Vec3d(-0.35, 0.6, 0.0)
override var profileScale = 0.85F
override var profileTranslation = Vec3d(0.0, 0.5, 0.0)
override val profileScale = 0.85F
override val profileTranslation = Vec3d(0.0, 0.5, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
@@ -28,11 +28,11 @@ class BeedrillModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, BiWi
override val leftWing = getPart("wing_left")
override val rightWing = getPart("wing_right")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3d(0.05, 0.9, 0.0)
override val portraitScale = 1.9F
override val portraitTranslation = Vec3d(0.05, 0.9, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3d(-0.1, 0.9, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(-0.1, 0.9, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -21,11 +21,11 @@ class BellsproutModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("bellsprout")
override val head = getPart("head")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3d(-0.1, 0.41, 0.0)
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.1, 0.41, 0.0)
override var profileScale = 0.75F
override var profileTranslation = Vec3d(0.0, 0.64, 0.0)
override val profileScale = 0.75F
override val profileTranslation = Vec3d(0.0, 0.64, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
@@ -27,10 +27,10 @@ class BulbasaurModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Qua
override val hindLeftLeg = getPart("leg_back_left")
override val hindRightLeg = getPart("leg_back_right")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3d(-0.26, -1.20, 0.0)
override var profileScale = 0.9F
override var profileTranslation = Vec3d(0.0, 0.4, 0.0)
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.26, -1.20, 0.0)
override val profileScale = 0.9F
override val profileTranslation = Vec3d(0.0, 0.4, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -27,11 +27,11 @@ class ButterfreeModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bi
val leftWingBack = getPart("wing_left2")
val rightWingBack = getPart("wing_right2")
override var portraitScale = 2.4F
override var portraitTranslation = Vec3d(-0.1, 0.2, 0.0)
override val portraitScale = 2.4F
override val portraitTranslation = Vec3d(-0.1, 0.2, 0.0)
override var profileScale = 0.7F
override var profileTranslation = Vec3d(0.1, 0.8, 0.0)
override val profileScale = 0.7F
override val profileTranslation = Vec3d(0.1, 0.8, 0.0)
lateinit var sleep: PokemonPose
@@ -25,10 +25,10 @@ class CaterpieModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
override val rootPart = root.registerChildWithAllChildren("caterpie")
override val head = getPart("head")
override var portraitScale = 2.1F
override var portraitTranslation = Vec3d(-0.55, -1.55, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3d(0.0, 0.55, 0.0)
override val portraitScale = 2.1F
override val portraitTranslation = Vec3d(-0.55, -1.55, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.55, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -8,16 +8,13 @@
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.client.model.ModelPart
import net.minecraft.util.math.Vec3d
@@ -26,27 +23,17 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
override val leftLeg = getPart("left_foot")
override val rightLeg = getPart("right_foot")
override var portraitScale = 1.5F
override var portraitTranslation = Vec3d(-0.35, 0.3, 0.0)
override val portraitScale = 1.5F
override val portraitTranslation = Vec3d(-0.35, 0.3, 0.0)
override var profileScale = 0.8F
override var profileTranslation = Vec3d(0.0, 0.55, 0.0)
override val profileScale = 0.8F
override val profileTranslation = Vec3d(0.0, 0.55, 0.0)
lateinit var standing: PokemonPose
lateinit var walk: PokemonPose
lateinit var sleep: PokemonPose
override fun registerPoses() {
val blink = quirk { bedrockStateful("chansey", "blink") }
sleep = registerPose(
poseName = "sleep",
poseType = PoseType.SLEEP,
idleAnimations = arrayOf(
bedrock("chansey", "ground_sleep")
)
)
val blink = quirk { bedrockStateful("chansey", "blink")}
standing = registerPose(
poseName = "standing",
poseTypes = STATIONARY_POSES + UI_POSES,
@@ -62,13 +49,15 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
transformTicks = 10,
quirks = arrayOf(blink),
idleAnimations = arrayOf(
bedrock("chansey", "ground_walk")
bedrock("chansey", "ground_idle"),
BipedWalkAnimation(this),
//bedrock("chansey", "ground_walk")
)
)
}
override fun getFaintAnimation(
pokemonEntity: PokemonEntity,
state: PoseableEntityState<PokemonEntity>
) = bedrockStateful("chansey", "faint")
// override fun getFaintAnimation(
// pokemonEntity: PokemonEntity,
// state: PoseableEntityState<PokemonEntity>
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("chansey", "faint") else null
}
@@ -34,11 +34,11 @@ class CharizardModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bip
override val leftWing = getPart("wing_left")
override val rightWing = getPart("wing_right")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3d(-0.5, 1.4, 0.0)
override val portraitScale = 1.9F
override val portraitTranslation = Vec3d(-0.5, 1.4, 0.0)
override var profileScale = 0.55F
override var profileTranslation = Vec3d(0.05, 0.93, 0.0)
override val profileScale = 0.55F
override val profileTranslation = Vec3d(0.05, 0.93, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -31,11 +31,11 @@ class CharmanderModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bi
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 2.2F
override var portraitTranslation = Vec3d(-0.1, -0.1, 0.0)
override val portraitScale = 2.2F
override val portraitTranslation = Vec3d(-0.1, -0.1, 0.0)
override var profileScale = 0.71F
override var profileTranslation = Vec3d(0.0, 0.72, 0.0)
override val profileScale = 0.71F
override val profileTranslation = Vec3d(0.0, 0.72, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -29,11 +29,11 @@ class CharmeleonModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bi
override val rightLeg = getPart("leg_right")
override val leftLeg = getPart("leg_left")
override var portraitScale = 1.9F
override var portraitTranslation = Vec3d(-0.16, 0.55, 0.0)
override val portraitScale = 1.9F
override val portraitTranslation = Vec3d(-0.16, 0.55, 0.0)
override var profileScale = 0.65F
override var profileTranslation = Vec3d(0.0, 0.79, 0.0)
override val profileScale = 0.65F
override val profileTranslation = Vec3d(0.0, 0.79, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -23,11 +23,11 @@ import net.minecraft.util.math.Vec3d
class ClefableModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("clefable")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3d(-0.1, -0.7, 0.0)
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(-0.1, -0.7, 0.0)
override var profileScale = 1.15F
override var profileTranslation = Vec3d(0.0, 0.02, 0.0)
override val profileScale = 1.15F
override val profileTranslation = Vec3d(0.0, 0.02, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose
@@ -23,11 +23,11 @@ import net.minecraft.util.math.Vec3d
class ClefairyModel(root: ModelPart) : PokemonPoseableModel() {
override val rootPart = root.registerChildWithAllChildren("clefairy")
override var portraitScale = 2.0F
override var portraitTranslation = Vec3d(0.0, -1.0, 0.0)
override val portraitScale = 2.0F
override val portraitTranslation = Vec3d(0.0, -1.0, 0.0)
override var profileScale = 1.1F
override var profileTranslation = Vec3d(0.0, 0.08, 0.0)
override val profileScale = 1.1F
override val profileTranslation = Vec3d(0.0, 0.08, 0.0)
lateinit var sleep: PokemonPose
lateinit var standing: PokemonPose

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