Compare commits

..
Author SHA1 Message Date
apion 263bccca4b idk whats up here but I wanna swap off this branch so 2025-02-07 17:49:10 -05:00
apion 1d94adface Fabric now boots 2025-01-26 03:02:57 -05:00
apion c741ddbc2e Comments 2025-01-25 04:23:40 -05:00
apion 8cad44ffb1 NEOFORGE IS BOOTING INTO A WORLD!!! 2025-01-25 04:05:34 -05:00
apion dec0376d11 More MDG testing 2025-01-18 15:46:50 -05:00
apion 007b2a49f4 More ModDevGradle porting 2025-01-18 01:19:26 -05:00
apion 082683723d Initial moddevgradle port 2025-01-17 21:31:25 -05:00
2863 changed files with 123652 additions and 227261 deletions
+41 -184
View File
@@ -1,163 +1,52 @@
# Changelog
## [1.7.0 (Month xth, 2025)](#1-7-0)
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
- Fixed PCs always opening at box 2 instead of box 1.
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
- Dialogues are correctly removed from memory when they are stopped.
- Dialogues with variably-set initial pages now properly start timeout tracking.
## [1.6.1 (January 26th, 2025)](#1-6-1)
## [1.6.1 (Release TBD)](#1-6-1)
### Additions
- Added crossover paintings from Close Combat: Premonition, Altar, Slumber, and Nomad.
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon. Take a wild guess which.
- Added compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
- Added an evolution method for Karrablast to evolve into Escavalier in singleplayer.
- Pokédexes can now be placed in Chiseled Bookshelves.
- Added optional box argument to the /pc command.
- Pokédex and Dialogue screens now close when the inventory keybind is pressed.
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
- Added the `is_standing_on_blocks(depth, blocks...)` MoLang function, which returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
- Added debug renderer for posable entity locators.
- Added crossover paintings from Close Combat, Premonition, Altar, Slumber, and Nomad.
- Added optional box argument to the /pc command
- Added molang particle queries for getting distance to targeted entities.
- Added debug renderer for poseable entity locators.
- Added `baseScale` property to NPCs.
- Added the player to `PokerodReelEvent`.
- Pokédex and Dialogue API screens now close when the inventory keybind is pressed.
- Added Galarica Nuts, used for crafting Galarica Cuffs and Wreaths. Dropped from certain Pokémon.
- Added specific compatibility with Repurposed Structures. (Thank you, TelepathicGrunt!)
### Changes
- Pokémon will now be dynamically revealed to the Pokédex as they're seen instead of revealing entire parties at the end of battle regardless.
- Unseen wild Pokémon will update their name from '???' to their real name as soon as a battle starts to reflect the battle UI showing the actual species name.
- Pokémon under the illusion effect will reveal their disguise to the Pokédex first and then the base Pokémon once the disguise is broken.
- Added more support for a variety of Fabric/NeoForge Convention tags.
- Reformatted some tags to be more consistent.
- Edited some recipes to utilize tags instead of direct item ids, for greater mod compatibility.
- Berries will drop if broken at age 0
- Improved Fortune drops on Mint Seeds
- New Slowpoke shiny texture.
- Updated drops for many Pokémon.
- Completely resynced Pokémon move and stat data based on later games. Learnsets have changed considerably to maximise available moves.
- Cobblemon save data now saves .old files where applicable as a means to recover from file corruption due to crashes or similar abrupt stops
### Pokémon Added
#### Gen 5
- Ducklett
- Swanna
- Shelmet
- Accelgor
- Karrablast
- Escavalier
- Rufflet
- Braviary
- Foongus
- Amoonguss
#### Gen 6
- Binacle
- Barbaracle
#### Gen 7
- Dewpider
- Araquanid
- Alolan Geodude
- Alolan Graveler
- Alolan Golem
#### Gen 8
- Galarian Slowpoke
- Galarian Slowbro
- Galarian Slowking
#### Gen 9
- Paldean Tauros
### Added cries to the following Pokémon
- All Nidorans
- Shellder, Cloyster
- Pinsir
- Tyrogue, Hitmontop
- Spinda
### Animation updates for the following Pokémon
- Primeape
- Munchlax
- Snorlax
- Poliwrath
- Goldeen
- Seaking
- Dondozo
- Wobbuffet
- Charcadet
- Armarouge
- Ceruledge
- Geodude
- Graveler
- Golem
- Sandile
- Krokorok
- Krookodile
### Model updates for the following Pokémon
- Slowpoke
- Slowbro
- Slowking
- Eiscue
- Tauros
- Goldeen
- Seaking
- Charcadet
- Armarouge
- Ceruledge
- Pinsir
- Geodude
- Graveler
- Golem
### Cry updates for the following Pokémon
- Sceptile
### Changes
- Completely re-synced Pokémon move and stat data based on later games. Learnsets have changed considerably to maximise available moves.
- Pokémon will now be dynamically revealed to the Pokédex as they're seen in battle instead of revealing entire parties at the end of battle.
- Unseen wild Pokémon will update their name from '???' to their real name as soon as a battle starts to match how the battle UI shows the actual species name.
- Pokémon under the illusion effect will reveal their disguise to the Pokédex first and then the base Pokémon once the disguise is broken.
- Berries will now drop from berry trees if broken at age 0 so you aren't punished for mistaken planting.
- Increased Fortune drops on Mint Seeds.
- Updated Slowpoke's shiny texture.
- Updated drops for many Pokémon.
- Adjusted the evolution sound to match the timing of the particle effect.
- Made berry trees shear-able by dispenser blocks. I'm sure nobody will make unholy contraptions with this.
- Edited some recipes to utilize tags instead of direct item IDs, for better mod compatibility.
- Added more support for a variety of Fabric/NeoForge conventional tags.
- Reformatted some tags to be more consistent.
### Fixes
- Fixed Pokédex sometimes crashing when switching forms.
- Fixed Pokédex interface not transitioning out when closed.
- Fixed texture dimensions for the player and Pokémon interact interface.
- Fixed crash related to Tom's Simple Storage mod and the Fossil Machine.
- Fixed texture dimensions for the interact interface.
- Fixed crash related to Tom's Simple Storage mod and Fossil Machine.
- Fixed not being able to retrieve a fossil from the Fossil Machine with an empty hand.
- Fixed Pokémon being collidable (collidible? collissionable? kaleidoscopable?) while being captured by a Poké Ball.
- Fixed Pokémon being collidable while being captured by a Poké Ball.
- Fixed `full_party`, `own_zangoose_seviper`, `use_revive` and `use_candy` Advancement triggers.
- Fixed `healing_machine` Advancement by using the correct 1.21 trigger.
- Fix Display Cases not dropping items if destroyed through explosions.
- Fixed an issue where the first Pokémon in the pastured Pokémon list clipped into the interface.
- Fixed all Pokémon facing South on spawn.
- Fixed bait being consumed even when not reeling in any Pokémon.
- Parametric particle motion now works.
- Event spawned particles now work.
- Particles can now have independent coordinate spaces.
- Fixed bait being consumed when not reeling in any Pokémon.
- Fixed Miltank milk magically disappearing out of your bucket.
- Fixed Pokémon nicknames migrating from 1.5.2 not being displayed properly.
- Fixed capitalization in one of our config options. It was a very important fix. Very important. Old configs are fine.
- Fixed Poké Rods not working if Lure or Luck of the Sea enchantments get removed by other mods.
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item. Very specific.
- Fixed a crash that sometimes occurred when evolving Nincada.
- Fixed Cobblemon plants not being compostable on NeoForge.
- Fixed capitalization in one of our config fields, but allowing typo'd version to still be valid.
- Fixed Poké Rods not working if lure or luck of the sea enchantments get removed by other mods.
- Fixed crashes related to Pokémon when they are ready to evolve while holding an enchanted item.
- Fixed crashes that sometimes occur when evolving Nincada.
- Fixed plants not being compostible on NeoForge.
- Fixed hide UI (F1 key) not hiding the party overlay.
- Fixed NPC MoLang command `player_lose_command` not working.
- Fixed misaligned tooltips with edit boxes in the NPC editor screen.
- Corrected misaligned tooltips with editboxes in the NPC editor screen.
- Fixed Pokémon riding two boats when attempting to deploy a platform on water.
- Fixed the summary screen showing there's experience to reach the next level when they are at the level cap.
- Made berry trees be shearable by dispenser blocks.
- Fixed the summary screen showing there's experience to reach the next level when at level cap.
- Fixed Pokémon forgetting moves when evolving on specific cases.
- Fixed Adorn compatibility, including improvements when using JEI/REI (Apricorn items now show up under the collapsed entries rather than standalone).
- Fixed error message appearing on battle log when using Solar Beam with Sunny Day.
@@ -165,68 +54,35 @@
- Fixed `/pokedex grant all` command not giving male/female/shininess completion for some Pokémon.
- Fixed `/pokedex grant only` and `/pokedex remove only` not respecting the form parameter passed.
- Fixed variant forms appearing incorrectly in the Pokédex when the normal form had not been unlocked.
- Fixed Pokémon occasionally being shot into the sky during battle. No Pokémon were harmed by this bug, probably.
- Fixed Pokémon occasionally being shot into the sky during battle.
- Fixed NPC editing GUI not updating aspects until a game restart.
- Fixed some users being unable to open their PC if a Pokémon in it had a lot of PP raises beyond normal bounds. How did you get those, anyway? Tell me or the Bellossom gets it.
- Fixed some color variants (Dubwool, Conkeldurr and Undyed wooloo) being missing in the Pokédex.
- Fixed invalid species or held items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods).
- Fix some users being unable to open their PC if a Pokémon in said PC had a lot of pp raises beyond normal bounds
- Fix some color variants (dubwool, conkeldurr and undyed wooloo) missing in the Pokédex
- Fix invalid species or held_items causing Players to not be able to load into their world anymore (commonly happening after removing addons/mods)
- Fixed Wooloo variants not being automatically registered in the owner's Pokédex when dyed.
- Fixed Vivichoke Dip and Leek & Potato Stew not returning a bowl upon consumption.
- Fixed Fossil Restoration Tank not accepting Hay Bales as organic material.
- Fixed Potion items applying double their intended healing value.
- Fixed Fast Ball capture bonuses applying to all Pokémon, making it the Best Ball instead of the Mediocre Edge-Case Ball.
- Fixed "learned new move" messages appearing for already-known moves on Pokémon evolutions.
- Fixed Pokémon Item Models breaking shadows nearby when being placed in Display Cases or Item Frames.
- Fixed berries not giving bonus yields when planted in their preferred biomes. I'm sure we've fixed that 5 times now.
- Fixed the NeoForge version not supporting "SodiumDynamicLights".
- Fixed players disconnecting from servers if they made changes to certain config options.
- Fixed players with shouldered Pokémon not being able to rejoin their 1.5.2 worlds using 1.6.
- Fixed `PokemonProperties` utilizing `ability=<some ability>` being treated as a forced ability even when it is a legal ability for the Pokémon.
- Fixed type formatting in Pokédex scanner mode when dual types require two lines.
- Fixed trading sometimes crashing the game or server.
- Fixed Wild shiny sounds not respecting the `shinyNoticeParticlesDistance` config setting.
- Fixed Pokémon being able to evolve mid-battle.
- Fixed NPC held items being able to be stolen by players. Don't be a thief!
- Fixed evolutions that require a held item consuming it as soon as meeting requirements when it should only be consumed upon evolution.
- Fixed Pokémon showing only the default form when selecting them as a target in battle.
- Fixed a possible error coming out of reeling fishing rods in specific situations.
- Fixed incorrect weights being used when Poké Fishing with Luck of the Sea.
- Parametric particle motion now works.
- Event-spawned particles now work.
- Particles can now have independent coordinate spaces.
- Fixed Vivichoke Dip and Leek and Potato Stew not returning a bowl upon consumption.
- Fixed Fossil Restoration Machine not accepting Hay Bales.
- Fixed Potion items so that they no longer apply over double their intended healing value.
### Developer
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
- Updated fields in `SpawnNPCPacket` and `SpawnPokemonPacket` to be visible and mutable.
- Updated `UnvalidatedPlaySoundS2CPacket` to be public instead of internal and made its fields mutable.
- Added `hideNameTag` field and `HideNPCNameTag` nbt tag to `NPCEntity` to allow hiding the name tag of the NPC.
- Added the player to `PokerodReelEvent` so you know who is doing the reeling.
### MoLang & Datapacks
### Molang & Datapacks
- Added flows for:
- `forme_change`: Triggered when a Pokémon changes form in battle.
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third-party mods are required for this feature currently)
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third-party mods are required for this feature currently)
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third-party mods are required for this feature currently)
- `mega_evolution`: Triggered when a Pokémon mega evolves in battle. (Note: Third party mods are required for this feature currently)
- `zpower_used`: Triggered when a Pokémon uses a Z-Power move in battle. (Note: Third party mods are required for this feature currently)
- `terastallization`: Triggered when a Pokémon terastallizes in battle. (Note: Third party mods are required for this feature currently)
- `battle_fainted`: Triggered when a Pokémon faints in battle.
- `battle_fled`: Triggered when a player flees from battle.
- `battle_fled`: Triggered when a Player flees from battle.
- `battle_started_pre`: Triggered when a battle starts. Cancelable!
- `battle_started_post`: Triggered when a battle starts.
- `apricorn_harvested`: Triggered when an Apricorn is harvested.
- `apricorn_harvested`: Triggered when an apricorn is harvested.
- `thrown_pokeball_hit`: Triggered when a thrown Pokéball hits a Pokémon.
- `level_up`: Triggered when a Pokémon levels up.
- `pokemon_fainted`: Triggered when a Pokémon faints.
- `pokemon_gained`: Triggered when a player gains a Pokémon.
- Added MoLang functions:
- `pokemon_gained`: Triggered when a Player gains a Pokémon.
- Added molang functions:
- For Pokémon:
- `pokemon.apply(PokemonProperties)`: Applies the given properties to the Pokémon.
- `pokemon.owner`: Returns the owner of the Pokémon or 0.0 if there is no owner or they are not online.
- For all entities:
- `entity.is_standing_on_blocks(depth, blocks...)`: Returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
- Added NPC field:
- `hideNameTag`: Hides the name tag of the NPC.
- Added `baseScale` property to NPCs.
- Added MoLang particle queries for getting distance to targeted entities.
## [1.6.0 - The Record Catch Update (December 25th, 2024)](#1-6-0)
#### "Now that there's a fishing mechanic, the mod is actually good!"
@@ -2129,4 +1985,5 @@ 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.
+27
View File
@@ -0,0 +1,27 @@
plugins {
id("java-gradle-plugin")
kotlin("jvm") version "2.1.0"
}
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://maven.architectury.dev/")
maven("https://maven.fabricmc.net/")
}
dependencies {
implementation("net.neoforged:moddev-gradle:2.0.75")
implementation("dev.architectury:at:1.0.1")
implementation("net.fabricmc:access-widener:2.1.0")
}
gradlePlugin {
plugins {
create("cobblemongradle") {
id = "com.cobblemon.gradle"
implementationClass = "com.cobblemon.gradle.CobblemonGradle"
version = "1.0.0"
}
}
}
+7
View File
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
@@ -0,0 +1,85 @@
package com.cobblemon.gradle
import com.cobblemon.gradle.extension.CobblemonGradleExtension
import com.cobblemon.gradle.extension.tasks.ConvertAccessWidenersTask
import com.cobblemon.gradle.extension.tasks.UnzipAccessWidenersTask
import net.neoforged.nfrtgradle.CreateMinecraftArtifacts
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.attributes.LibraryElements
import org.gradle.language.jvm.tasks.ProcessResources
class CobblemonGradle : Plugin<Project> {
override fun apply(project: Project) {
val cobblemonExtension = project.extensions.create(
CobblemonGradleExtension.EXTENSION_NAME,
CobblemonGradleExtension::class.java
)
//This exists because all of
// - com.cobblemon:mod
// - com.cobblemon:mod-resources
// - com.cobblemon:accesswidener
//technically point to the same dependency (the :common project). To pick the proper artifact from that project
//we set attributes in that project and check for them here.
val accessWideners = project.configurations.register("accessWidener") { configuration ->
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = true
configuration.isCanBeDeclared = true
configuration.attributes {
it.attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
project.objects.named(LibraryElements::class.java, LibraryElements.OBJECTS)
)
}
}
val includeRootResources = project.configurations.register("includeRootResources") { configuration ->
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = true
configuration.isCanBeDeclared = true
configuration.attributes {
it.attribute(
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
project.objects.named(LibraryElements::class.java, LibraryElements.RESOURCES)
)
}
}
val unzipAwTask = project.tasks.register("unzipAccessWideners", UnzipAccessWidenersTask::class.java) {
it.accessWidenerZips = accessWideners.get()
}
val convertAwTask = project.tasks.register(ConvertAccessWidenersTask.NAME, ConvertAccessWidenersTask::class.java) {
it.enabled = cobblemonExtension.convertAccessWideners
it.dependsOn(unzipAwTask)
it.accessWideners = project.files(unzipAwTask).plus(project.files(cobblemonExtension.additionalAccessWideners))
}
//Add root resources and access wideners to output jar
project.tasks.named("processResources", ProcessResources::class.java) { task ->
task.dependsOn(includeRootResources)
if (cobblemonExtension.convertAccessWideners) {
task.dependsOn(convertAwTask)
task.from(convertAwTask)
}
else {
task.dependsOn(unzipAwTask)
task.from(unzipAwTask)
}
task.doLast {
project.copy {
it.from(project.provider {
includeRootResources.get().resolve().map { project.zipTree(it) }
})
it.into(task.destinationDir)
}
}
}
project.tasks.withType(CreateMinecraftArtifacts::class.java) {
it.dependsOn(convertAwTask)
it.accessTransformers.from(convertAwTask)
}
}
}
@@ -0,0 +1,12 @@
package com.cobblemon.gradle.extension
import org.gradle.api.file.FileCollection
abstract class CobblemonGradleExtension {
var additionalAccessWideners: FileCollection? = null
var convertAccessWideners = true
companion object {
const val EXTENSION_NAME = "cobblemon"
}
}
@@ -0,0 +1,82 @@
package com.cobblemon.gradle.extension.tasks
import dev.architectury.at.AccessChange
import dev.architectury.at.AccessTransform
import dev.architectury.at.AccessTransformSet
import dev.architectury.at.ModifierChange
import dev.architectury.at.io.AccessTransformFormats
import net.fabricmc.accesswidener.AccessWidenerReader
import net.fabricmc.accesswidener.AccessWidenerVisitor
import org.cadixdev.bombe.type.signature.MethodSignature
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFiles
import org.gradle.api.tasks.TaskAction
import java.io.Writer
import java.nio.file.Files
abstract class ConvertAccessWidenersTask : DefaultTask() {
abstract var accessWideners: FileCollection
@InputFiles get
@Internal
val accessTransformerDir = project.layout.buildDirectory.dir("access-transformers")
@OutputFiles
val accessTransformers = project.files ({
accessWideners.files.map {
accessTransformerDir.get().file(it.name.replace("accesswidener", "accesstransformer.cfg"))
}
})
@TaskAction
fun convertAccessWideners() {
accessWideners.files.forEach { file ->
val awFile = Files.newBufferedReader(file.toPath())
val result = AccessTransformSet.create();
AccessWidenerReader(object : AccessWidenerVisitor {
override fun visitClass(name: String, access: AccessWidenerReader.AccessType, transitive: Boolean) {
result.getOrCreateClass(name).merge(toAt(access));
}
override fun visitMethod(owner: String, name: String, descriptor: String, access: AccessWidenerReader.AccessType, transitive: Boolean) {
result.getOrCreateClass(owner).mergeMethod(MethodSignature.of(name, descriptor), toAt(access));
}
override fun visitField(owner: String, name: String, descriptor: String, access: AccessWidenerReader.AccessType, transitive: Boolean) {
result.getOrCreateClass(owner).mergeField(name, toAt(access));
}
}).read(awFile)
val outputFile = accessTransformerDir.get().file(
file.name.replace("accesswidener", "accesstransformer.cfg")
)
var outputWriter: Writer? = null
try {
outputWriter = outputFile.asFile.writer()
AccessTransformFormats.FML.write(outputWriter, result)
}
finally {
outputWriter?.flush()
outputWriter?.close()
}
}
}
private fun toAt(access: AccessWidenerReader.AccessType): AccessTransform {
return when (access) {
AccessWidenerReader.AccessType.ACCESSIBLE -> AccessTransform.of(AccessChange.PUBLIC)
AccessWidenerReader.AccessType.EXTENDABLE, AccessWidenerReader.AccessType.MUTABLE -> AccessTransform.of(
AccessChange.PUBLIC,
ModifierChange.REMOVE
)
}
}
companion object {
const val NAME = "convertAccessWideners"
}
}
@@ -0,0 +1,33 @@
package com.cobblemon.gradle.extension.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.OutputFiles
import org.gradle.api.tasks.TaskAction
abstract class UnzipAccessWidenersTask : DefaultTask() {
abstract var accessWidenerZips: FileCollection
@InputFiles get
@OutputFiles
val outputFiles = project.provider {
project.files(accessWidenerZips.flatMap { zip ->
project.zipTree(zip).files.map { OUTPUT_DIR.get().file(it.name) }
})
}
@Internal
val OUTPUT_DIR = project.layout.buildDirectory.dir("cobblemon-working/access-wideners")
@TaskAction
fun run() {
project.copy {
it.from(accessWidenerZips.map(project::zipTree))
it.into(OUTPUT_DIR)
}
}
}
+4 -2
View File
@@ -1,12 +1,14 @@
plugins {
id("cobblemon.root-conventions")
//id("cobblemon.root-conventions")
id ("net.nemerosa.versioning") version "3.1.0"
}
version = "${project.property("mod_version")}+${project.property("mc_version")}"
val isSnapshot = project.property("snapshot")?.equals("true") == true
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
/*
if (isSnapshot) {
val fixedBranchName = versioning.info.branch.substringAfter("/")
version = "$version-${fixedBranchName}-${versioning.info.build}"
}
*/
+90 -54
View File
@@ -1,68 +1,102 @@
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
* * 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/.
*
*/
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 "3.1.0"
kotlin("jvm") version "2.1.0"
id ("net.neoforged.moddev") version "2.0.75"
id("net.kyori.blossom") version "2.1.0"
id("com.github.johnrengelman.shadow") version "8.1.1"
id("com.cobblemon.gradle")
}
architectury {
common("neoforge", "fabric")
cobblemon {
additionalAccessWideners = files(sourceSets.main.get().resources).filter { it.extension == "accesswidener" }
}
val rootResources = configurations.create("rootResources") {
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.RESOURCES))
}
}
val accessWidenerExport = configurations.create("accessWidenerExport") {
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.OBJECTS))
}
}
tasks.processResources {
exclude("*.accesswidener")
}
tasks.create<Zip>("zipResources") {
dependsOn("processResources")
from(tasks.processResources.get().destinationDir)
this.archiveBaseName = "mod-resources"
}
tasks.create<Zip>("zipAccessWideners") {
from(sourceSets.main.get().resources)
include("*.accesswidener")
this.archiveBaseName = "mod-accesswideners"
}
tasks.jar {
archiveBaseName = "mod"
manifest {
attributes(mapOf("FMLModType" to "GAMELIBRARY"))
}
exclude {
it.file in tasks.processResources.get().outputs.files
}
}
tasks.assemble {
dependsOn(tasks.named("zipResources"))
dependsOn(tasks.named("zipAccessWideners"))
}
artifacts {
add("rootResources", tasks.getByName<Zip>("zipResources"))
add("accessWidenerExport", tasks.getByName("zipAccessWideners"))
}
buildscript {
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://maven.architectury.dev/")
maven("https://maven.fabricmc.net/")
}
}
repositories {
maven(url = "${rootProject.projectDir}/deps")
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
mavenLocal()
mavenCentral()
maven("https://maven.fabricmc.net/")
maven("https://maven.blamejared.com/")
maven("https://api.modrinth.com/maven")
maven(url = "../deps")
}
dependencies {
implementation(libs.bundles.kotlin)
modImplementation(libs.fabric.loader)
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
compileOnly(libs.bundles.mongo)
compileOnly(libs.bundles.kotlin)
compileOnly(libs.molang)
compileOnly(libs.graal)
compileOnly(libs.jei.api)
compileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
// Showdown
modCompileOnly(libs.graal)
// Data Storage
modCompileOnly(libs.bundles.mongo)
// Unit Testing
compileOnly("net.fabricmc:sponge-mixin:0.15.5+mixin.0.8.7")
compileOnly("io.github.llamalad7:mixinextras-fabric:0.4.1")
testImplementation(libs.bundles.unitTesting)
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
setEvents(listOf("failed"))
setExceptionFormat("full")
}
neoForge {
neoFormVersion = "1.21.1-20240808.144430"
interfaceInjectionData.from("src/main/resources/interfaces.json")
validateAccessTransformers = true
}
sourceSets {
@@ -72,7 +106,7 @@ sourceSets {
fun generateLicenseHeader() : String {
val builder = StringBuilder()
builder.append("/*\n")
rootProject.file("HEADER").forEachLine {
project.projectDir.parentFile.resolve("HEADER").forEachLine {
if(it.isEmpty()) {
builder.append(" *").append("\n")
} else {
@@ -85,12 +119,14 @@ sourceSets {
property("license", generateLicenseHeader())
property("modid", "cobblemon")
property("version", project.version())
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
property("version", project.version as String)
property("isSnapshot", "true")
/*
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")
*/
}
}
}
+97
View File
@@ -0,0 +1,97 @@
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
* * 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/.
*
*/
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 "3.1.0"
}
architectury {
common("neoforge", "fabric")
}
repositories {
maven(url = "${rootProject.projectDir}/deps")
maven(url = "https://api.modrinth.com/maven")
maven(url = "https://maven.neoforged.net/releases")
mavenLocal()
}
dependencies {
implementation(libs.bundles.kotlin)
modImplementation(libs.fabric.loader)
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
// modCompileOnly(libs.flywheelFabric)
// Showdown
modCompileOnly(libs.graal)
// Data Storage
modCompileOnly(libs.bundles.mongo)
// Unit Testing
testImplementation(libs.bundles.unitTesting)
}
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
setEvents(listOf("failed"))
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")
}
}
}
}
+95
View File
@@ -0,0 +1,95 @@
[versions]
# Kotlin
kotlin = "2.0.0"
# Plugins
licenser = "0.6.1"
shadow = "8.1.1"
blossom = "2.1.0"
idea-ext = "1.1.7"
# Loom
loom = "1.7-SNAPSHOT"
architectury-plugin = "3.4-SNAPSHOT"
# Common
molang = "1.1.18"
graal = "22.3.0"
icu4j = "71.1"
jei-api = "19.8.2.99"
# Fabric
fabric-loader = "0.16.5"
fabric-api = "0.104.0+1.21.1"
fabric-kotlin = "1.11.0+kotlin.2.0.0"
fabric-permissions-api = "0.2-SNAPSHOT"
lambDynamicLights = "3.0.1+1.21.1"
debugutils-fabric = "1.21-1.0.6-fabric"
# NeoForge
neoforge = "21.1.66"
neo-kotlin-for-forge = "5.5.0"
debugutils-forge = "1.21-1.0.6-neoforge"
# Data Storage
mongo = "4.10.2"
# Testing
junit = "5.9.0"
mockito = "5.2.0"
mockk = "1.12.1"
classgraph = "4.8.153"
[libraries]
# General Buildscript Plugins
kotlin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
loom = { group = "dev.architectury", name = "architectury-loom", version.ref = "loom" }
architectury = { group = "architectury-plugin", name = "architectury-plugin.gradle.plugin", version.ref = "architectury-plugin" }
shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" }
blossom = { group = "net.kyori", name = "blossom", version.ref = "blossom" }
ideaExt = { group = "org.jetbrains.gradle.plugin.idea-ext", name = "org.jetbrains.gradle.plugin.idea-ext.gradle.plugin", version.ref = "idea-ext"}
licenser = { group = "gradle.plugin.org.cadixdev.gradle", name = "licenser", version.ref = "licenser" }
# Kotlin
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
# Common
jei-api = { group = "mezz.jei", name = "jei-1.21-common-api", version.ref = "jei-api"}
molang = { group = "local.com.bedrockk", name = "molang", version.ref = "molang" }
graal = { group = "org.graalvm.js", name = "js", version.ref = "graal" }
icu4j = { group = "com.ibm.icu", name = "icu4j", version.ref = "icu4j" }
# Fabric
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
fabric-kotlin = { group = "net.fabricmc", name = "fabric-language-kotlin", version.ref = "fabric-kotlin" }
fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions-api" }
adorn-fabric = { group = "maven.modrinth", name = "adorn", version = "6.0.0-neoforge"}
lambDynamicLights = { group = "maven.modrinth", name = "lambdynamiclights", version.ref = "lambDynamicLights"}
jei-api-fabric = { group = "mezz.jei", name = "jei-1.21-fabric-api", version.ref = "jei-api" }
jei-fabric = { group = "mezz.jei", name = "jei-1.21-fabric", version.ref = "jei-api"}
fabric-debugutils = { group = "maven.modrinth", name = "debugutils", version.ref = "debugutils-fabric"}
# NeoForge
neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge" }
neo-kotlin-forge = { group = "thedarkcolour", name = "kotlinforforge-neoforge", version.ref = "neo-kotlin-for-forge" }
neoforge-debugutils = { group = "maven.modrinth", name = "debugutils", version.ref = "debugutils-forge"}
# Data Storage
mongo-driver-core = { group = "org.mongodb", name = "mongodb-driver-core", version.ref = "mongo" }
mongo-driver-sync = { group = "org.mongodb", name = "mongodb-driver-sync", version.ref = "mongo" }
# Testing
junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }
mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" }
mock-kotlin = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
classgraph = { group = "io.github.classgraph", name = "classgraph", version.ref = "classgraph" }
[bundles]
kotlin = [ "kotlin-stdlib", "kotlin-reflect" ]
fabric = [ "fabric-kotlin", "fabric-permissions" ]
fabric-integrations-compileOnly = [ "adorn-fabric", "lambDynamicLights", "jei-api-fabric" ]
fabric-integrations-runtimeOnly = [ "jei-fabric" ]
mongo = [ "mongo-driver-core", "mongo-driver-sync" ]
unitTesting = [ "junit", "mockito-core", "mock-kotlin", "classgraph" ]
@@ -1,61 +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.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.world.level.Level;
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(Creeper.class)
public class EntityCreeperMixin extends Mob {
private EntityCreeperMixin(net.minecraft.world.entity.EntityType<? extends Creeper> entityType, Level world) {
super(entityType, world);
}
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
final Creeper creeper = (Creeper) (Object) this;
// Pokemon Entities
this.goalSelector.addGoal(
3,
new AvoidEntityGoal<>(
creeper,
PokemonEntity.class,
6.0f,
1.0,
1.2,
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedByCreeper() && ((PokemonEntity)entity).getBeamMode() != 1
)
);
// Players with shoulder mounted Pokemon
this.goalSelector.addGoal(
3,
new AvoidEntityGoal<>(
creeper,
ServerPlayer.class,
6.0f,
1.0,
1.2,
entity -> EntityBehaviour.Companion.hasCreeperFearedShoulderMount((ServerPlayer)entity)
)
);
}
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import net.minecraft.world.entity.monster.Phantom;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(targets = "net/minecraft/world/entity/monster/Phantom$PhantomSweepAttackGoal")
public class EntityPhantomMixin {
// TODO: Figure out how to access the outer class that wraps SwoopMovementGoal
// Need to find the cat mons that are near the phantom
// @Inject(method = "shouldContinue", at = @At(value = "RETURN"), cancellable = true)
// public void cobblemon$shouldContinue(CallbackInfoReturnable<Boolean> ci) {
//// var goalSelectorField = PhantomEntity.class.getClasses();// PhantomEntity.class.getFields();// .class.getDeclaredField("goalSelector");
//
//// goalSelectorField.setAccessible(true);
//// GoalSelector goalSelector = (GoalSelector) goalSelectorField.get(mobEntity);
//// final SwoopMovementGoal phantom = (SwoopMovementGoal) (Object) this;
//// if(ci.getReturnValue() == false) {
//// var result = this$0.getWorld().getEntitiesByClass(
//// PokemonEntity.class,
//// this$0.getBoundingBox().expand(16.0),
//// entity -> {
//// return ((PokemonEntity) entity).getBehaviour().getEntityInteract().getAvoidedByPhantom();
//// }
//// ).isEmpty();
////
//// ci.setReturnValue(result);
//// }
// }
}
@@ -1,62 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.monster.AbstractSkeleton;
import net.minecraft.world.level.Level;
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(AbstractSkeleton.class)
public class EntitySkeletonMixin extends Mob {
private EntitySkeletonMixin(EntityType<? extends Mob> entityType, Level world) {
super(entityType, world);
}
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
final AbstractSkeleton skeleton = (AbstractSkeleton) (Object) this;
// Pokemon Entities
this.goalSelector.addGoal(
3,
new AvoidEntityGoal<>(
skeleton,
PokemonEntity.class,
6.0f,
1.0,
1.2,
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedBySkeleton() && ((PokemonEntity)entity).getBeamMode() != 1
)
);
// Players with shoulder mounted Pokemon
this.goalSelector.addGoal(
3,
new AvoidEntityGoal<>(
skeleton,
ServerPlayer.class,
6.0f,
1.0,
1.2,
entity -> EntityBehaviour.Companion.hasSkeletonFearedShoulderMount((ServerPlayer)entity)
)
);
}
}
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
@@ -179,10 +178,10 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Override @Nullable
public PokedexEntityData resolvePokemonScan() {
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
if(CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityRight())){
return getDataFromShoulderPokemon(this.getShoulderEntityRight());
}
if (CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
if(CompoundTagUtilities.isShoulderPokemon(this.getShoulderEntityLeft())){
return getDataFromShoulderPokemon(this.getShoulderEntityLeft());
}
return null;
@@ -191,34 +190,30 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
@Nullable @Unique
private PokedexEntityData getDataFromShoulderPokemon(CompoundTag shoulderTag) {
CompoundTag pokemonTag = shoulderTag.getCompound(DataKeys.POKEMON);
if (pokemonTag.isEmpty()) return null;
if(pokemonTag.isEmpty()) return null;
Species species = PokemonSpecies.INSTANCE.getByIdentifier(ResourceLocation.parse(pokemonTag.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)));
if (species == null) return null;
if(species == null) return null;
String formId = pokemonTag.getString(DataKeys.POKEMON_FORM_ID);
FormData form = species.getStandardForm();
List<FormData> formList = species.getForms().stream().filter(it -> it.formOnlyShowdownId().equals(formId)).toList();
if (!formList.isEmpty()) form = formList.getFirst();
if (form == null) return null;
if(!formList.isEmpty()) form = formList.getFirst();
if(form == null) return null;
String genderString = pokemonTag.getString(DataKeys.POKEMON_GENDER);
if (genderString.isEmpty()) return null;
if(genderString.isEmpty()) return null;
Gender gender = Gender.valueOf(genderString);
boolean shiny = pokemonTag.getBoolean(DataKeys.POKEMON_SHINY);
int level = pokemonTag.getInt(DataKeys.POKEMON_LEVEL);
Set<String> aspects = shoulderTag.getList(DataKeys.SHOULDER_ASPECTS, Tag.TAG_STRING).stream().map(Tag::getAsString).collect(Collectors.toSet());
Pokemon pokemon = new Pokemon();
if (level().isClientSide) {
pokemon.setSpecies(species);
pokemon.setForm(form);
pokemon.setGender(gender);
pokemon.setShiny(shiny);
pokemon.setLevel(level);
pokemon.setForcedAspects(aspects);
} else {
PlayerPartyStore party = Cobblemon.INSTANCE.getStorage().getParty(this.getUUID(), this.registryAccess());
pokemon = party.get(shoulderTag.getUUID(DataKeys.SHOULDER_UUID));
}
return new PokedexEntityData(pokemon, null);
return new PokedexEntityData(
species,
form,
gender,
aspects,
shiny,
level,
this.getUUID()
);
}
@Override
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.SeasonResolver
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.EvolutionItemDropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
@@ -201,7 +200,6 @@ object Cobblemon {
DropEntry.register("command", CommandDropEntry::class.java)
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
DropEntry.register("evolution", EvolutionItemDropEntry::class.java)
ExperienceGroups.registerDefaults()
CaptureCalculators.registerDefaults()
@@ -220,7 +218,7 @@ object Cobblemon {
storage.onPlayerDataSync(it)
playerDataManager.syncAllToPlayer(it)
starterHandler.handleJoin(it)
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel, this.config.displayEntityNameLabel, this.config.maxPokemonLevel, this.config.maxPokemonFriendship, this.config.maxDynamaxLevel).sendToPlayer(it)
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel, this.config.displayEntityNameLabel, this.config.maxPokemonLevel).sendToPlayer(it)
}
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe {
PCLinkManager.removeLink(it.player.uuid)
@@ -258,8 +256,6 @@ object Cobblemon {
// 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()
if (increment <= 0) //these affects are only meant to affect positive gains
return@subscribe
// Our Luxury ball spec is diff from official, but we will still assume these stack
if (event.pokemon.heldItemNoCopy().`is`(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
increment += increment * 0.5F
@@ -15,8 +15,6 @@ object CobblemonActivities {
val BATTLING = register(Activity("battling"))
val ACTION_EFFECT = register(Activity("action_effect"))
val NPC_CHATTING = register(Activity("npc_chatting"))
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
fun register(activity: Activity): Activity {
activities.add(activity)
@@ -9,35 +9,27 @@
package com.cobblemon.mod.common
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.ai.BrainPreset
import com.cobblemon.mod.common.api.ai.config.BrainConfig
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
import com.cobblemon.mod.common.api.data.DataRegistry
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.BrainPresetSyncPacket
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
import com.cobblemon.mod.common.util.adapters.BrainConfigAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import com.mojang.datafixers.util.Either
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.entity.schedule.Activity
object CobblemonBrainConfigs : JsonDataRegistry<BrainPreset> {
object CobblemonBrainConfigs : JsonDataRegistry<List<BrainConfig>> {
override val gson: Gson = GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
@@ -45,27 +37,21 @@ object CobblemonBrainConfigs : JsonDataRegistry<BrainPreset> {
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
.registerTypeAdapter(
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
ExpressionOrEntityVariableAdapter
)
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.create()
override val typeToken = TypeToken.get(BrainPreset::class.java)
override val typeToken = TypeToken.getParameterized(List::class.java, BrainConfig::class.java) as TypeToken<List<BrainConfig>>
override val resourcePath = "brain_presets"
override val id: ResourceLocation = cobblemonResource("brain_presets")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<CobblemonBrainConfigs>()
val presets = mutableMapOf<ResourceLocation, BrainPreset>()
val presets = mutableMapOf<ResourceLocation, List<BrainConfig>>()
override fun sync(player: ServerPlayer) {
player.sendPacket(BrainPresetSyncPacket(presets))
// TODO implement probs ay
}
override fun reload(data: Map<ResourceLocation, BrainPreset>) {
override fun reload(data: Map<ResourceLocation, List<BrainConfig>>) {
presets.clear()
presets.putAll(data)
}
@@ -57,7 +57,6 @@ object CobblemonCommands {
FreezePokemonCommand.register(dispatcher)
ApplyPlayerTextureCommand.register(dispatcher)
RunMolangScriptCommand.register(dispatcher)
BrainEditCommand.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
@@ -317,7 +317,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
private val berries = mutableMapOf<ResourceLocation, BerryItem>()
// Plants
@@ -16,31 +16,14 @@ import com.mojang.serialization.codecs.PrimitiveCodec
import net.minecraft.core.UUIDUtil
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import java.util.Optional
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.LivingEntity
object CobblemonMemories {
val memories = mutableMapOf<String, MemoryModuleType<*>>()
/*
* When a memory doesn't have a codec provided, it's because it doesn't
* get serialized during relogs. This makes sense for things like battles which
* do not survive a relog therefore any memory of it should be temporary.
*/
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
val REST_PATH_COOLDOWN = register("rest_path_cooldown", PrimitiveCodec.BOOL)
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
val memoryModule = MemoryModuleType(Optional.of(codec))
@@ -53,4 +36,4 @@ object CobblemonMemories {
memories[id] = memoryModule
return memoryModule
}
}
}
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
import com.cobblemon.mod.common.client.net.animation.PlayPosableAnimationHandler
@@ -52,16 +51,8 @@ import com.cobblemon.mod.common.client.net.storage.pc.OpenPCHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCBoxPokemonHandler
import com.cobblemon.mod.common.client.net.storage.pc.SetPCPokemonHandler
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
import com.cobblemon.mod.common.client.net.trade.*
import com.cobblemon.mod.common.net.PacketRegisterInfo
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
@@ -102,38 +93,14 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
import com.cobblemon.mod.common.net.messages.client.trade.*
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
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.behaviour.SetEntityBehaviourPacket
import com.cobblemon.mod.common.net.messages.server.*
import com.cobblemon.mod.common.net.messages.server.battle.*
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
@@ -163,22 +130,9 @@ import com.cobblemon.mod.common.net.messages.server.storage.pc.MovePartyPokemonT
import com.cobblemon.mod.common.net.messages.server.storage.pc.ReleasePCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.SwapPCPokemonPacket
import com.cobblemon.mod.common.net.messages.server.storage.pc.UnlinkPlayerFromPCPacket
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
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.ChallengeResponseHandler
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
import com.cobblemon.mod.common.net.messages.server.trade.*
import com.cobblemon.mod.common.net.serverhandling.*
import com.cobblemon.mod.common.net.serverhandling.battle.*
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
@@ -212,12 +166,7 @@ import com.cobblemon.mod.common.net.serverhandling.storage.pc.MovePartyPokemonTo
import com.cobblemon.mod.common.net.serverhandling.storage.pc.ReleasePartyPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.SwapPCPokemonHandler
import com.cobblemon.mod.common.net.serverhandling.storage.pc.UnlinkPlayerFromPCHandler
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.net.serverhandling.trade.*
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -355,7 +304,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(BrainPresetSyncPacket.ID, BrainPresetSyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -406,9 +354,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler))
list.add(PacketRegisterInfo(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler))
// Behaviours
list.add(PacketRegisterInfo(OpenBehaviourEditorPacket.ID, OpenBehaviourEditorPacket::decode, OpenBehaviourEditorHandler))
// Pokédex scanning
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
return list
@@ -498,9 +443,6 @@ object CobblemonNetwork {
// NPC packets
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
// Behaviour Packets
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
return list
}
@@ -8,12 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DefendOwnerSensor
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.ItemEntitySensor
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonAdultSensor
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonGrowableCropSensor
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
import java.util.function.Supplier
@@ -26,22 +20,10 @@ object CobblemonSensors {
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
val ITEM_SENSOR = register("item_sensor", ::ItemEntitySensor)
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
val sensor = SensorType(supplier)
sensors[id] = sensor
return sensor
}
}
}
@@ -9,14 +9,11 @@
package com.cobblemon.mod.common.api.ai
import com.cobblemon.mod.common.api.ai.config.BrainConfig
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.schedule.Activity
import net.minecraft.world.entity.schedule.Schedule
class BrainConfigurationContext {
var appliedBrainPresets: MutableSet<ResourceLocation> = mutableSetOf()
var defaultActivity = Activity.IDLE
var coreActivities = setOf(Activity.CORE)
@@ -30,11 +27,6 @@ class BrainConfigurationContext {
fun apply(entity: LivingEntity, brainConfigs: List<BrainConfig>) {
val brain = entity.brain
if (entity is MoLangScriptingEntity) {
entity.registerVariables(brainConfigs.flatMap { it.getVariables(entity) })
entity.initializeScripting()
}
// Setup the brain config
brainConfigs.forEach { it.configure(entity, this) }
@@ -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.ai
import com.cobblemon.mod.common.api.ai.config.BrainConfig
import com.cobblemon.mod.common.util.asTranslated
import com.cobblemon.mod.common.util.entityTypeRegistry
import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
class BrainPreset(
val name: Component = "dummy".asTranslated(),
val description: Component = "".asTranslated(),
val entityType: ResourceLocation? = null,
val configurations: List<BrainConfig> = mutableListOf()
) {
fun canBeApplied(entity: LivingEntity) = entityType?.let { entity.type == entity.level().entityTypeRegistry.get(it) } != false
}
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.mojang.datafixers.util.Either
import kotlin.jvm.optionals.getOrNull
typealias ExpressionOrEntityVariable = Either<Expression, MoLangConfigVariable>
fun List<ExpressionOrEntityVariable>.asVariables() = mapNotNull { it.right().getOrNull() }
@@ -1,24 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai
/**
* The medium that an entity might be in which motivates what type of wandering it should do.
*
* If you've discovered this in main and it's not being used outside of that unused extension function, delete me
*
* @author Hiroku
* @since January 25th, 2025
*/
enum class PathfindingMedium {
LAND,
WATER,
LAVA,
AIR
}
@@ -8,23 +8,27 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.schedule.Activity
class AddTasksToActivity : BrainConfig {
val activity = Activity.IDLE
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val condition = "true".asExpressionLike()
val tasksByPriority = mutableMapOf<Int, List<TaskConfig>>()
override fun getVariables(entity: LivingEntity) = tasksByPriority.values.flatten().flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
if (!checkCondition(entity, condition)) return
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return
val activity = brainConfigurationContext.getOrCreateActivity(activity)
tasksByPriority.forEach { (priority, taskConfigs) ->
@@ -8,42 +8,28 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBrainConfigs
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.LivingEntity
class ApplyPresets : BrainConfig {
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val condition = "true".asExpressionLike()
val presets = mutableListOf<ResourceLocation>()
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return if (checkCondition(entity, condition)) {
presets.flatMap {
CobblemonBrainConfigs.presets[it]?.configurations?.flatMap { it.getVariables(entity) } ?: emptyList()
} + listOf(condition).asVariables()
} else {
listOf(condition).asVariables()
}
}
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
if (!checkCondition(entity, condition)) return
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return
val presetConfigs = presets.flatMap { CobblemonBrainConfigs.presets[it]?.takeIf { it.canBeApplied(entity) }?.configurations ?: return Cobblemon.LOGGER.warn("Preset $it not found") }
// Why not just add the presets to the context directly?
// Nested preset application is a thing, and I only want to track the top level presets.
// i.e. if a preset applies another preset, I don't want to track the inner preset, since it's redundant if we track the top one.
val originalContextPresets = brainConfigurationContext.appliedBrainPresets.toMutableSet()
presetConfigs.forEach {
it.configure(entity, brainConfigurationContext)
}
originalContextPresets.addAll(presets)
brainConfigurationContext.appliedBrainPresets = originalContextPresets
val presetConfigs = presets.flatMap { CobblemonBrainConfigs.presets[it] ?: return Cobblemon.LOGGER.warn("Preset $it not found") }
presetConfigs.forEach { it.configure(entity, brainConfigurationContext) }
}
}
@@ -8,15 +8,7 @@
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
/**
@@ -38,21 +30,12 @@ interface BrainConfig {
"add_tasks_to_activity" to AddTasksToActivity::class.java,
"apply_presets" to ApplyPresets::class.java,
"set_default_activity" to SetDefaultActivity::class.java,
"set_core_activities" to SetCoreActivities::class.java,
"add_variables" to AddVariablesConfig::class.java,
"set_variables" to SetVariablesConfig::class.java,
"set_core_activities" to SetCoreActivities::class.java
)
}
fun checkCondition(entity: LivingEntity, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
return runtime.resolveBoolean(expressionOrEntityVariable.map({ it }, { "q.entity.config.${it.variableName}".asExpression() }))
}
// fun encode(buffer: RegistryFriendlyByteBuf)
// fun decode(buffer: RegistryFriendlyByteBuf)
fun getVariables(entity: LivingEntity): List<MoLangConfigVariable>
fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext)
}
@@ -9,13 +9,8 @@
package com.cobblemon.mod.common.api.ai.config
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import net.minecraft.world.entity.LivingEntity
class AddVariablesConfig : BrainConfig {
override fun getVariables(entity: LivingEntity) = mutableListOf<MoLangConfigVariable>()
// Configuration happens naturally through the override on variables
object DummyBrainConfig : BrainConfig {
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {}
}
@@ -117,49 +117,3 @@ Example brain preset (`uses_healing_machine.json`):
}
]
```
### add_variables
The `add_variables` type adds some number of MoLang variables to the entity that can be configured in-game or left with defaults.
- `variables`: A list of objects, each representing a variable that can be configured.
Each variable has the following properties:
- `variableName`: The name of the variable. This is the name that will be accessible from MoLang scripts.
- `defaultValue`: The default value of the variable. This is a MoLang expression that will be used if the variable is not set.
- `displayName`: The display name of the variable. This is used in the UI to label the variable. This can be a translation key.
- `description`: A description of the variable. This is used in the UI to describe what the variable does. This can be a translation key.
- `type`: The type of the variable. This can be `TEXT`, `NUMBER`, or `BOOLEAN`.
Example:
```json
{
"type": "add_variables",
"variables": [
{
"variableName": "can_heal_using_machine",
"defaultValue": "false",
"displayName": "Can Use Healing Machine",
"description": "Whether or not the entity can use a healing machine.",
"type": "BOOLEAN"
}
]
}
```
### set_variables
The `set_variables` type sets some values for pre-established variables. This is useful in cases where a preset has defined a variable
but it's locked in by a specific entity using that preset. This strongly forces the variable to a specific value. In future this
probably should deregister the variable so that the client cannot edit them once they've been forced, as currently that will
be possible yet the value will get repeatedly overwritten.
The values inside the variables map can be MoLang expressions (with `q.entity` as the entity) or simple JSON primitives.
Example:
```json
{
"type": "set_variables",
"variables": {
"aggressive": true,
"attack_range": "10"
}
}
```
@@ -15,10 +15,8 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.ai.ActivityConfigurationContext
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.molang.ObjectValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.activityRegistry
@@ -35,11 +33,10 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
class ScriptBrainConfig : BrainConfig {
val condition = "true".asExpressionLike()
val script = cobblemonResource("dummy")
override fun getVariables(entity: LivingEntity) = mutableListOf<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, context: BrainConfigurationContext) {
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return
val struct = createBrainStruct(entity, context)
@@ -53,7 +50,7 @@ class ScriptBrainConfig : BrainConfig {
fun createBrainStruct(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): QueryStruct {
return QueryStruct(hashMapOf()).addStandardFunctions()
.addFunction("entity") { entity.asMostSpecificMoLangValue() }
.addFunction("entity") { (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()) }
.addFunction("create_activity") { params ->
val name = params.getString(0).asIdentifierDefaultingNamespace()
val activity = entity.level().activityRegistry.get(name) ?: return@addFunction run {
@@ -9,13 +9,11 @@
package com.cobblemon.mod.common.api.ai.config
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.schedule.Activity
class SetCoreActivities : BrainConfig {
val activities = mutableListOf<Activity>()
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
brainConfigurationContext.coreActivities = activities.toSet()
}
@@ -9,13 +9,11 @@
package com.cobblemon.mod.common.api.ai.config
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.schedule.Activity
class SetDefaultActivity : BrainConfig {
val activity: Activity = Activity.IDLE
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
brainConfigurationContext.defaultActivity = activity
}
@@ -1,36 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.util.resolve
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
class SetVariablesConfig : BrainConfig {
var variableValues = mutableMapOf<String, ExpressionLike>()
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
val runtime = MoLangRuntime().setup()
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (entity is MoLangScriptingEntity) {
variableValues.forEach { (variableName, valueExpression) ->
entity.config.setDirectly(variableName, runtime.resolve(valueExpression))
}
}
}
}
@@ -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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.ai.util.HoverRandomPos
class AirWanderTaskConfig : SingleTaskConfig {
val condition = booleanVariable(WANDER, "air_wanders", true).asExpressible()
val wanderChance = numberVariable(WANDER, "air_wander_chance", 1/(20 * 1F)).asExpressible()
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 20).asExpressible()
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
val minUpwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
val minDownwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return listOf(condition, wanderChance, horizontalRange, verticalRange, speedMultiplier, minUpwardsMovement, minDownwardsMovement).asVariables()
}
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
it.registered(MemoryModuleType.LOOK_TARGET)
).apply(it) { walkTarget, lookTarget ->
Trigger { world, entity, time ->
if (entity !is PathfinderMob || entity.isInWater) {
return@Trigger false
}
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val wanderChance = wanderChance.resolveFloat()
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
val rotVec = entity.getViewVector(0F)
val target = HoverRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), rotVec.x, rotVec.y, 1.5707964f, minUpwardsMovement.resolveInt(), minDownwardsMovement.resolveInt())
?: return@Trigger false
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 3))
lookTarget.set(BlockPosTracker(target))
return@Trigger true
}
}
}
}
}
@@ -8,36 +8,25 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class AllOfTaskConfig : TaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val condition = "true".asExpressionLike()
val tasks: List<TaskConfig> = emptyList()
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return if (checkCondition(entity, condition))
tasks.flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
else
listOf(condition).asVariables()
}
override fun createTasks(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): List<BehaviorControl<in LivingEntity>> {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return emptyList()
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return emptyList()
return tasks.flatMap { it.createTasks(entity, brainConfigurationContext) }
}
}
@@ -8,10 +8,9 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
@@ -20,15 +19,13 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class AttackAngryAtTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "should_attack_angry_at", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
val condition = "true".asExpressionLike()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return AttackAngryAtTask.create()
}
}
@@ -8,28 +8,24 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.VillagerCalmDown
class CalmDownTaskConfig : SingleTaskConfig {
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
var condition = "true".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return VillagerCalmDown.create()
}
}
@@ -8,34 +8,30 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.DoNothing
class DoNothingTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(condition, minDurationTicks, maxDurationTicks).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val minDurationTicks = "40".asExpression()
val maxDurationTicks = "80".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return DoNothing(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return DoNothing(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks))
}
}
@@ -8,14 +8,14 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.battles.BattleRegistry
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.NPCEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -24,21 +24,15 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_when_hurt", true).asExpressible()
var includePassiveDamage = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_from_passive_damage", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
includePassiveDamage
).asVariables()
var condition = "true".asExpression()
var includePassiveDamage = true
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val includePassiveDamage = includePassiveDamage.resolveBoolean()
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
if (entity is NPCEntity) {
fun cancelNPCBattles(npcEntity: NPCEntity): Boolean {
@@ -58,7 +52,7 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelNPCBattles(entity as NPCEntity) } }
}
}
} else if (entity is PokemonEntity) {
} else { return null }/* else if (entity is PokemonEntity) { TODO uncomment when pokemon have brain :)
fun cancelPokemonBattle(pokemonEntity: PokemonEntity): Boolean {
val battle = BattleRegistry.getBattle(pokemonEntity.battleId ?: return false)
battle?.end()
@@ -67,17 +61,15 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
return if (includePassiveDamage) {
BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLE))
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLING))
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
}
} else {
BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLE))
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLING))
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
}
}
} else {
return null
}
}*/
}
}
@@ -1,36 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.FindRestingPlaceTask
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class FindRestingPlaceTaskConfig : SingleTaskConfig {
val horizontalSearchDistance: ExpressionOrEntityVariable = Either.left("16".asExpression())
val verticalSearchDistance: ExpressionOrEntityVariable = Either.left("5".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(horizontalSearchDistance, verticalSearchDistance).asVariables()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return WrapperLivingEntityTask(
FindRestingPlaceTask.create(horizontalSearchDistance.resolveInt(), verticalSearchDistance.resolveInt()),
PokemonEntity::class.java
)
}
}
@@ -8,12 +8,14 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -22,24 +24,18 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FleeAttackerTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_attacker", true).asExpressible()
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
speedMultiplier,
desiredDistance
).asVariables()
var condition = "true".asExpression()
var speedMultiplier = "0.5".asExpression()
var desiredDistance = "9".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
val speedMultiplier = speedMultiplier.resolveFloat()
val desiredDistance = desiredDistance.resolveInt()
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
val desiredDistance = runtime.resolveInt(desiredDistance)
return WrapperLivingEntityTask(
SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false),
PathfinderMob::class.java
@@ -8,13 +8,14 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -23,20 +24,18 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class FleeNearestHostileTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_nearest_hostile", true).asExpressible()
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition, speedMultiplier, desiredDistance).asVariables()
var condition = "true".asExpression()
var speedMultiplier = "0.5".asExpression()
var desiredDistance = "9".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
val speedMultiplier = speedMultiplier.resolveFloat()
val desiredDistance = desiredDistance.resolveInt()
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
val desiredDistance = runtime.resolveInt(desiredDistance)
return WrapperLivingEntityTask(
SetWalkTargetAwayFrom.entity(MemoryModuleType.NEAREST_HOSTILE, speedMultiplier, desiredDistance, false),
PathfinderMob::class.java
@@ -8,31 +8,32 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.ai.FollowWalkTargetTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class FollowWalkTargetTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val minRunTicks: ExpressionOrEntityVariable = Either.left("150".asExpression())
val maxRunTicks: ExpressionOrEntityVariable = Either.left("250".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(minRunTicks, maxRunTicks).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val minRunTicks: Expression = "150".asExpression()
val maxRunTicks: Expression = "250".asExpression()
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return WrapperLivingEntityTask(
FollowWalkTargetTask(minRunTicks.resolveInt(), maxRunTicks.resolveInt()),
FollowWalkTargetTask(runtime.resolveInt(minRunTicks), runtime.resolveInt(maxRunTicks)),
PathfinderMob::class.java
)
}
@@ -8,30 +8,26 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.ATTACKING_CATEGORY
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.ai.GetAngryAtAttackerTask
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class GetAngryAtAttackerTaskConfig : SingleTaskConfig {
companion object {
const val GET_ANGRY_AT_ATTACKER = "get_angry_at_attacker"
}
val condition = booleanVariable(ATTACKING_CATEGORY, GET_ANGRY_AT_ATTACKER, true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return GetAngryAtAttackerTask.create()
}
}
@@ -8,43 +8,38 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.ai.GoToHealingMachineTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class GoToHealingMachineTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
val horizontalSearchRange: ExpressionOrEntityVariable = Either.left("10".asExpression())
val verticalSearchRange: ExpressionOrEntityVariable = Either.left("5".asExpression())
val completionRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition, walkSpeed, horizontalSearchRange, verticalSearchRange, completionRange).asVariables()
companion object {
const val SELF_HEALING = "self_healing"
const val USE_HEALING_MACHINES = "use_healing_machines"
}
class GoToHealingMachineTaskConfig(
val condition: ExpressionLike = "true".asExpressionLike(),
val horizontalSearchRange: Expression = "10".asExpression(),
val verticalSearchRange: Expression = "5".asExpression(),
val speedMultiplier: Expression = "0.35".asExpression(),
val completionRange: Expression = "1".asExpression()
) : SingleTaskConfig {
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return GoToHealingMachineTask.create(
horizontalSearchRange = horizontalSearchRange.asExpression(),
verticalSearchRange = verticalSearchRange.asExpression(),
speedMultiplier = walkSpeed.asExpression(),
completionRange = completionRange.asExpression()
horizontalSearchRange = horizontalSearchRange,
verticalSearchRange = verticalSearchRange,
speedMultiplier = speedMultiplier,
completionRange = completionRange
)
}
@@ -1,27 +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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GoToSleepTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class GoToSleepTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
}
}
@@ -8,33 +8,29 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.SELF_HEALING
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.USE_HEALING_MACHINES
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.ai.HealUsingHealingMachineTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class HealUsingHealingMachineTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
val horizontalUseRange: ExpressionOrEntityVariable = Either.left("2".asExpression())
val verticalUseRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(condition, horizontalUseRange, verticalUseRange).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val horizontalUseRange = "3".asExpression()
val verticalUseRange = "2".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return HealUsingHealingMachineTask(horizontalUseRange.asExpression(), verticalUseRange.asExpression())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return HealUsingHealingMachineTask(horizontalUseRange, verticalUseRange)
}
}
@@ -8,41 +8,29 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.ai.LookAtBattlingPokemonTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class LookAtBattlingPokemonTaskConfig : SingleTaskConfig {
companion object {
const val LOOK_AT_BATTLING_POKEMON = "look_at_battling_pokemon"
}
val condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, LOOK_AT_BATTLING_POKEMON, true).asExpressible()
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(
condition,
minDurationTicks,
maxDurationTicks
).asVariables()
val minDurationTicks = "40".asExpression()
val maxDurationTicks = "80".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!resolveBooleanVariable(LOOK_AT_BATTLING_POKEMON)) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
return LookAtBattlingPokemonTask.create(
minDurationTicks = minDurationTicks.resolveInt(),
maxDurationTicks = maxDurationTicks.resolveInt()
minDurationTicks = runtime.resolveInt(minDurationTicks),
maxDurationTicks = runtime.resolveInt(maxDurationTicks)
)
}
}
@@ -8,35 +8,29 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.SEE_DISTANCE
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
class LookAtEntitiesTaskConfig : SingleTaskConfig {
companion object {
const val LOOK_AT_ENTITIES = "look_at_entities"
}
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
maxDistance
).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val maxDistance = "15".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return SetEntityLookTarget.create(maxDistance.resolveFloat())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return SetEntityLookTarget.create(runtime.resolveFloat(maxDistance))
}
}
@@ -9,12 +9,10 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.LookAtSpeakerTask
import net.minecraft.world.entity.LivingEntity
class LookAtSpeakerTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -8,37 +8,33 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink
class LookAtTargetTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
val minDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("160".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(
condition,
minDurationTicks,
maxDurationTicks
).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val minDurationTicks: Expression = "40".asExpression()
val maxDurationTicks: Expression = "80".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return WrapperLivingEntityTask(LookAtTargetSink(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt()), Mob::class.java)
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return WrapperLivingEntityTask(LookAtTargetSink(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks)), Mob::class.java)
}
}
@@ -1,27 +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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.LookAtTargetedBattlePokemonTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class LookAtTargetedBattlePokemonTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity> {
return WrapperLivingEntityTask(LookAtTargetedBattlePokemonTask.create(), PokemonEntity::class.java)
}
}
@@ -8,29 +8,18 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.LOOKING_CATEGORY
import com.cobblemon.mod.common.entity.ai.LookInDirectionTask
import com.cobblemon.mod.common.util.asExpression
import net.minecraft.world.entity.LivingEntity
class LookInDirectionTaskConfig : SingleTaskConfig {
var condition = booleanVariable(LOOKING_CATEGORY, "locked_rotation", true).asExpressible()
var yaw = numberVariable(LOOKING_CATEGORY, "locked_yaw", 0F).asExpressible()
var pitch = numberVariable(LOOKING_CATEGORY, "locked_pitch", 0F).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
yaw,
pitch
).asVariables()
var yaw: Expression = "0".asExpression()
var pitch: Expression = "0".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
) = LookInDirectionTask(
shouldLock = condition.asExpression(),
yaw = yaw.asExpression(),
pitch = pitch.asExpression()
)
) = LookInDirectionTask(yaw, pitch)
}
@@ -8,36 +8,32 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class MeleeAttackTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacks_melee", true).asExpressible()
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 1.5F).asExpressible()
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 30).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
range,
cooldownTicks
).asVariables()
val condition = "true".asExpressionLike()
val range = "1.5".asExpression()
val cooldownTicks = "30".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return MeleeAttackTask.create(
range = range.asExpression(),
cooldownTicks = cooldownTicks.asExpression()
range = range,
cooldownTicks = cooldownTicks
)
}
}
@@ -9,28 +9,19 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
class MoveToAttackTargetTaskConfig : SingleTaskConfig {
val speedMultiplier = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacking_movement_speed", 0.5).asExpressible()
val closeEnoughDistance: ExpressionOrEntityVariable = Either.left("1".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(
speedMultiplier,
closeEnoughDistance
).asVariables()
val speedMultiplier = "0.5".asExpression()
val closeEnoughDistance = "1".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
) = MoveToAttackTargetTask.create(
speedMultiplier = speedMultiplier.asExpression(),
closeEnoughDistance = closeEnoughDistance.asExpression()
speedMultiplier = speedMultiplier,
closeEnoughDistance = closeEnoughDistance
)
}
@@ -1,29 +0,0 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.ai.FollowWalkTargetTask
import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.MoveToItemAndEatTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class MoveToItemAndEatTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
return WrapperLivingEntityTask(
MoveToItemAndEatTask(),
PokemonEntity::class.java
)
}
}
@@ -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.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.MoveToOwnerTask
import com.cobblemon.mod.common.util.asExpression
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class MoveToOwnerTaskConfig : SingleTaskConfig {
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
var completionRange: ExpressionOrEntityVariable = Either.left("4.0".asExpression())
var speedMultiplier: ExpressionOrEntityVariable = Either.left("0.4".asExpression())
var teleportDistance: ExpressionOrEntityVariable = Either.left("24.0".asExpression())
var maxDistance: ExpressionOrEntityVariable = Either.left("14.0".asExpression())
override fun getVariables(entity: LivingEntity) = listOf(
condition,
completionRange,
speedMultiplier,
teleportDistance,
maxDistance
).asVariables()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return WrapperLivingEntityTask(
MoveToOwnerTask.create(
condition = condition.asExpression(),
completionRange = completionRange.asExpression(),
speedMultiplier = speedMultiplier.asExpression(),
teleportDistance = teleportDistance.asExpression(),
maxDistance = maxDistance.asExpression()
),
PokemonEntity::class.java
)
}
}
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
@@ -36,16 +34,14 @@ import net.minecraft.world.entity.ai.behavior.RunOne
class OneOfTaskConfig : SingleTaskConfig {
class OneOfTaskOption {
val weight: Int = 1
val task: TaskConfig = SingleTaskConfig.nothing()
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
}
val condition: ExpressionLike = "true".asExpressionLike()
val options = mutableListOf<OneOfTaskOption>()
override fun getVariables(entity: LivingEntity) = options.flatMap { it.task.getVariables(entity) }
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return RunOne(options.map { it.task.createTasks(entity, brainConfigurationContext).first() toDF it.weight })
}
@@ -11,8 +11,6 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
@@ -36,19 +34,17 @@ import net.minecraft.world.entity.ai.behavior.DoNothing
class RandomTaskConfig : TaskConfig {
class RandomTaskChoice {
val weight = 1.0
val task: TaskConfig = SingleTaskConfig.nothing()
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
}
val condition: ExpressionLike = "true".asExpressionLike()
val choices = mutableListOf<RandomTaskChoice>()
override fun getVariables(entity: LivingEntity) = choices.flatMap { it.task.getVariables(entity) }
override fun createTasks(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): List<BehaviorControl<in LivingEntity>> {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return emptyList()
val task = choices.weightedSelection { it.weight }?.task ?: throw IllegalStateException("No tasks to choose from in random_task config")
return task.createTasks(entity, brainConfigurationContext)
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -31,13 +31,7 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
* @since December 2nd, 2024
*/
class RunScript : SingleTaskConfig {
companion object {
const val SCRIPT_CATEGORY = "script"
}
val script = stringVariable(SCRIPT_CATEGORY, "script", "cobblemon:dummy_script").asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(script).asVariables()
val script = cobblemonResource("dummy")
override fun createTask(
entity: LivingEntity,
@@ -47,8 +41,8 @@ class RunScript : SingleTaskConfig {
it.registered(MemoryModuleType.LOOK_TARGET) // I think I need to have at least something here?
).apply(it) { _ ->
Trigger { world, entity, _ ->
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
return@Trigger CobblemonScripts.run(script.resolveString().asIdentifierDefaultingNamespace(), runtime) == DoubleValue.ONE
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: entity.asMostSpecificMoLangValue())
return@Trigger CobblemonScripts.run(script, runtime) == DoubleValue.ONE
}
}
}
@@ -1,22 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
object SharedEntityVariables {
const val MOVEMENT_CATEGORY = "movement"
const val FEAR_CATEGORY = "fear"
const val ATTACKING_CATEGORY = "attacking"
const val BATTLING_CATEGORY = "battling"
const val LOOKING_CATEGORY = "looking"
const val WALK_SPEED = "walk_speed"
const val FLEE_SPEED_MULTIPLIER = "flee_speed_multiplier"
const val FLEE_DESIRED_DISTANCE = "flee_desired_distance"
const val SEE_DISTANCE = "see_distance"
}
@@ -9,24 +9,10 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.DoNothing
interface SingleTaskConfig : TaskConfig {
companion object {
fun nothing() = object : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return DoNothing(0, 1)
}
}
}
fun interface SingleTaskConfig : TaskConfig {
override fun createTasks(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -8,31 +8,31 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.entity.ai.StayAfloatTask
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class StayAfloatTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.MOVEMENT_CATEGORY, "can_float", true).asExpressible()
val chance = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, "float_chance", 0.8F).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
chance
).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val chance: Expression = "0.01".asExpression()
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
val chance = runtime.resolveFloat(chance)
return WrapperLivingEntityTask(
StayAfloatTask(chance.resolveFloat()),
StayAfloatTask(chance),
PathfinderMob::class.java
)
}
@@ -8,26 +8,26 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.StopBeingAngryIfTargetDead
class StopBeingAngryIfAttackerDeadTaskConfig : SingleTaskConfig {
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "stop_being_angry_if_attacker_dead", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return StopBeingAngryIfTargetDead.create()
}
}
@@ -10,13 +10,11 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchFromActionEffectTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -10,13 +10,11 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchFromChattingTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -9,14 +9,12 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchFromFightTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -10,14 +10,12 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchFromNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchFromPokemonBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return BehaviorBuilder.create {
it.group(it.absent(CobblemonMemories.POKEMON_BATTLE)).apply(it) { _ ->
Trigger { level, entity, _ ->
entity.brain.updateActivityFromSchedule(level.dayTime, level.gameTime)
true
}
}
}
}
}
@@ -11,14 +11,12 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
class SwitchToActionEffectTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -11,14 +11,12 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.CobblemonActivities
import com.cobblemon.mod.common.CobblemonMemories
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
class SwitchToChattingTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -8,9 +8,11 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.Difficulty
import net.minecraft.world.entity.LivingEntity
@@ -20,10 +22,9 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.schedule.Activity
class SwitchToFightTaskConfig : SingleTaskConfig {
val condition = "true".asExpressionLike()
val activity = Activity.FIGHT
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -32,7 +33,8 @@ class SwitchToFightTaskConfig : SingleTaskConfig {
it.present(MemoryModuleType.ATTACK_TARGET)
).apply(it) { _ ->
Trigger { world, entity, _ ->
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return@Trigger false
if (entity.commandSenderWorld.getCurrentDifficultyAt(entity.blockPosition()).difficulty == Difficulty.PEACEFUL) return@Trigger false
entity.brain.setActiveActivityIfPossible(activity)
@@ -9,13 +9,11 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class SwitchToNPCBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
@@ -9,39 +9,27 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.Behavior
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.schedule.Activity
class SwitchToPanicWhenHostilesNearbyTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "panic_when_hostiles_nearby", true).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
var condition = "true".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.NEAREST_HOSTILE))
.apply(it) { nearestHostile ->
Trigger { world, entity, _ ->
(entity as? PathfinderMob)?.navigation?.stop()
entity.brain.setActiveActivityIfPossible(Activity.PANIC)
return@Trigger true
}
) = BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.NEAREST_HOSTILE))
.apply(it) { nearestHostile ->
Trigger { world, entity, _ ->
(entity as? PathfinderMob)?.navigation?.stop()
entity.brain.setActiveActivityIfPossible(Activity.PANIC)
return@Trigger true
}
}
}
}
}
@@ -8,10 +8,11 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
@@ -22,21 +23,16 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.schedule.Activity
class SwitchToPanicWhenHurtTaskConfig : SingleTaskConfig {
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "panic_when_hurt", true).asExpressible()
var includePassiveDamage = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "panic_on_passive_damage", false).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
includePassiveDamage
).asVariables()
var condition = "true".asExpression()
var includePassiveDamage = false
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return if (includePassiveDamage.resolveBoolean()) {
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return if (includePassiveDamage) {
BehaviorBuilder.create {
it.group(it.present(MemoryModuleType.HURT_BY))
.apply(it) { _ ->
@@ -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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.npc.ai.SwitchToBattleTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class SwitchToPokemonBattleTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity> {
return SwitchToBattleTask.createForPokemon()
}
}
@@ -10,18 +10,7 @@ package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.runtime.MoLangRuntime
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.resolveString
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
@@ -34,13 +23,11 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
* @author Hiroku
* @since October 14th, 2024
*/
interface TaskConfig {
fun interface TaskConfig {
companion object {
val types = mutableMapOf<String, Class<out TaskConfig>>(
"one_of" to OneOfTaskConfig::class.java,
"wander" to WanderTaskConfig::class.java,
"water_wander" to WaterWanderTaskConfig::class.java,
"air_wander" to AirWanderTaskConfig::class.java,
"look_at_target" to LookAtTargetTaskConfig::class.java,
"follow_walk_target" to FollowWalkTargetTaskConfig::class.java,
"random" to RandomTaskConfig::class.java,
@@ -52,9 +39,6 @@ interface TaskConfig {
"switch_npc_to_battle" to SwitchToNPCBattleTaskConfig::class.java,
"look_at_battling_pokemon" to LookAtBattlingPokemonTaskConfig::class.java,
"switch_npc_from_battle" to SwitchFromNPCBattleTaskConfig::class.java,
"switch_pokemon_to_battle" to SwitchToPokemonBattleTaskConfig::class.java,
"look_at_targeted_battle_pokemon" to LookAtTargetedBattlePokemonTaskConfig::class.java,
"switch_pokemon_from_battle" to SwitchFromPokemonBattleTaskConfig::class.java,
"go_to_healing_machine" to GoToHealingMachineTaskConfig::class.java,
"heal_using_healing_machine" to HealUsingHealingMachineTaskConfig::class.java,
"all_of" to AllOfTaskConfig::class.java,
@@ -76,11 +60,6 @@ interface TaskConfig {
"flee_nearest_hostile" to FleeNearestHostileTaskConfig::class.java,
"run_script" to RunScript::class.java,
"look_in_direction" to LookInDirectionTaskConfig::class.java,
"wake_up" to WakeUpTaskConfig::class.java,
"go_to_sleep" to GoToSleepTaskConfig::class.java,
"find_resting_place" to FindRestingPlaceTaskConfig::class.java,
"move_to_owner" to MoveToOwnerTaskConfig::class.java,
"move_to_item_and_eat" to MoveToItemAndEatTaskConfig::class.java,
)
val runtime = MoLangRuntime().setup()
@@ -89,38 +68,6 @@ interface TaskConfig {
val runtime: MoLangRuntime
get() = Companion.runtime
fun checkCondition(entity: LivingEntity, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
return expressionOrEntityVariable.resolveBoolean()
}
fun ExpressionOrEntityVariable.asExpression() = map({ it }, { "q.entity.config.${it.variableName}".asExpression() })
fun ExpressionOrEntityVariable.resolveString() = runtime.resolveString(asExpression())
fun ExpressionOrEntityVariable.resolveBoolean() = runtime.resolveBoolean(asExpression())
fun ExpressionOrEntityVariable.resolveInt() = runtime.resolveInt(asExpression())
fun ExpressionOrEntityVariable.resolveDouble() = runtime.resolveDouble(asExpression())
fun ExpressionOrEntityVariable.resolveFloat() = runtime.resolveFloat(asExpression())
private fun variable(category: String, name: String, type: MoLangConfigVariable.MoLangVariableType, default: String) = MoLangConfigVariable(
variableName = name,
category = lang("entity.variable.category.$category"),
displayName = lang("entity.variable.$name.name"),
description = lang("entity.variable.$name.desc"),
type = type,
defaultValue = default
)
fun stringVariable(category: String, name: String, default: String) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.TEXT, default = default)
fun numberVariable(category: String, name: String, default: Number) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.NUMBER, default = default.toString())
fun booleanVariable(category: String, name: String, default: Boolean) = variable(category = category, name = name, type = MoLangConfigVariable.MoLangVariableType.BOOLEAN, default = default.toString())
fun getVariableExpression(name: String) = "q.entity.config.$name".asExpression()
fun resolveStringVariable(name: String) = runtime.resolveString(getVariableExpression(name))
fun resolveBooleanVariable(name: String) = runtime.resolveBoolean(getVariableExpression(name))
fun resolveNumberVariable(name: String) = runtime.resolveDouble(getVariableExpression(name))
/** The variables that this task config uses. These are used to declare variables on the entity cleanly. */
fun getVariables(entity: LivingEntity): List<MoLangConfigVariable>
/** Given the entity in construction, returns a list of tasks. */
fun createTasks(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): List<BehaviorControl<in LivingEntity>>
}
@@ -1,27 +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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.WakeUpTask
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.behavior.BehaviorControl
class WakeUpTaskConfig : SingleTaskConfig {
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
return WrapperLivingEntityTask(WakeUpTask.create(), PokemonEntity::class.java)
}
}
@@ -8,16 +8,23 @@
package com.cobblemon.mod.common.api.ai.config.task
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.entity.PosableEntity
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.asExpressionLike
import com.cobblemon.mod.common.util.resolveBoolean
import com.cobblemon.mod.common.util.resolveDouble
import com.cobblemon.mod.common.util.resolveFloat
import com.cobblemon.mod.common.util.resolveInt
import com.cobblemon.mod.common.util.withQueryValue
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.RandomStroll
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
@@ -25,31 +32,20 @@ import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.ai.util.LandRandomPos
class WanderTaskConfig : SingleTaskConfig {
companion object {
const val WANDER = "wander" // Category
}
val condition = booleanVariable(WANDER, "wanders", true).asExpressible()
val wanderChance = numberVariable(WANDER, "wander_chance", 1/(20 * 6F)).asExpressible()
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 10).asExpressible()
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
override fun getVariables(entity: LivingEntity) = listOf(
condition,
wanderChance,
horizontalRange,
verticalRange,
speedMultiplier
).asVariables()
val condition: ExpressionLike = "true".asExpressionLike()
val shouldWander: ExpressionLike = "math.random(0, 20 * 8) <= 1".asExpressionLike()
val horizontalRange: Expression = "10".asExpression()
val verticalRange: Expression = "5".asExpression()
val speedMultiplier: Expression = "0.35".asExpression()
val completionRange: Expression = "1".asExpression()
val lookTargetYOffset: Expression = "1.5".asExpression()
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(condition)) return null
return BehaviorBuilder.create {
it.group(
@@ -61,13 +57,12 @@ class WanderTaskConfig : SingleTaskConfig {
return@Trigger false
}
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val wanderChance = wanderChance.resolveFloat()
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
if (!runtime.resolveBoolean(shouldWander)) return@Trigger false
val targetVec = LandRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), { 0.0 }) ?: return@Trigger false
walkTarget.set(WalkTarget(targetVec, speedMultiplier.resolveFloat(), 1))
lookTarget.set(BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
val targetVec = LandRandomPos.getPos(entity, runtime.resolveInt(horizontalRange), runtime.resolveInt(verticalRange)) ?: return@Trigger false
walkTarget.set(WalkTarget(targetVec, runtime.resolveFloat(speedMultiplier), runtime.resolveInt(completionRange)))
lookTarget.set(BlockPosTracker(targetVec.add(0.0, runtime.resolveDouble(lookTargetYOffset), 0.0)))
return@Trigger true
}
}
@@ -1,70 +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.ai.config.task
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
import com.cobblemon.mod.common.api.ai.asVariables
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.util.asExpression
import com.cobblemon.mod.common.util.withQueryValue
import com.mojang.datafixers.util.Either
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.ai.behavior.BehaviorControl
import net.minecraft.world.entity.ai.behavior.BehaviorUtils
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.WalkTarget
class WaterWanderTaskConfig : SingleTaskConfig {
val condition = booleanVariable(WANDER, "water_wanders", true).asExpressible()
val wanderChance = numberVariable(WANDER, "water_wander_chance", 1/(20 * 3F)).asExpressible()
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
val horizontalRange: ExpressionOrEntityVariable = Either.left("10.0".asExpression())
val verticalRange: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
return listOf(condition, wanderChance, speedMultiplier).asVariables()
}
override fun createTask(
entity: LivingEntity,
brainConfigurationContext: BrainConfigurationContext
): BehaviorControl<in LivingEntity>? {
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
if (!condition.resolveBoolean()) return null
return BehaviorBuilder.create {
it.group(
it.absent(MemoryModuleType.WALK_TARGET),
it.registered(MemoryModuleType.LOOK_TARGET)
).apply(it) { walkTarget, lookTarget ->
Trigger { world, entity, time ->
if (entity !is PathfinderMob || !entity.isInWater) {
return@Trigger false
}
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
val wanderChance = wanderChance.resolveFloat()
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
val target = BehaviorUtils.getRandomSwimmablePos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt()) ?: return@Trigger false
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 1))
lookTarget.set(BlockPosTracker(target))
return@Trigger true
}
}
}
}
}
@@ -55,7 +55,6 @@ class ActiveDialogue(var playerEntity: ServerPlayer, var dialogueReference: Dial
)
dialogueReference.initializationAction.invoke(this)
setPage(currentPage)
if (!completion.isDone) {
val packet = DialogueOpenedPacket(this, true)
@@ -52,6 +52,6 @@ object DialogueManager {
fun stopDialogue(playerEntity: ServerPlayer) {
val activeDialogue = playerEntity.activeDialogue ?: return
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
activeDialogues.remove(playerEntity.uuid)
activeDialogues.remove(activeDialogue.dialogueId)
}
}
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
@@ -41,23 +40,17 @@ interface DropEntry {
* to be dropped.
*/
val percentage: Float
/**
* The drop's quantity when doing selection from the [DropTable]. See the drop table documentation for more on how
* this works.
*/
val quantity: Int
/**
* The maximum number of times the item can be selected drop the [DropTable]. In most cases this will just be 1,
* meaning that the item, once picked, cannot be picked again. A larger value will allow the same [DropEntry] from
* appearing multiple times in a drop action.
*/
val maxSelectableTimes: Int
/** Whether this is considered a possible drop at the moment or not */
fun canDrop(pokemon: Pokemon?): Boolean = true
/** The logic to use to actually drop the thing. */
fun drop(entity: LivingEntity?, world: ServerLevel, pos: Vec3, player: ServerPlayer?)
}
@@ -11,13 +11,11 @@ package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import kotlin.random.Random
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.ItemStack
import net.minecraft.world.phys.Vec3
/**
@@ -47,11 +45,9 @@ class DropTable {
* Gets a drop list from this table as a list of [DropEntry]. You can specify the range of drop quantity totals
* that will be possible, or if you leave it blank it will use [DropTable.amount].
*/
fun getDrops(amount: IntRange = this.amount, pokemon: Pokemon? = null): List<DropEntry> {
fun getDrops(amount: IntRange = this.amount): List<DropEntry> {
val chosenAmount = amount.random()
val possibleDrops = entries.filter {
it.quantity <= chosenAmount && it.canDrop(pokemon)
}.toMutableList()
val possibleDrops = entries.filter { it.quantity <= chosenAmount }.toMutableList()
if (possibleDrops.isEmpty()) {
return emptyList()
@@ -91,10 +87,11 @@ class DropTable {
world: ServerLevel,
pos: Vec3,
player: ServerPlayer?,
amount: IntRange = this.amount,
pokemon: Pokemon? = null,
amount: IntRange = this.amount
) {
val drops = getDrops(amount, pokemon).toMutableList()
val drops = getDrops(amount).toMutableList()
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
if (!heldItem.isEmpty) entity.spawnAtLocation(heldItem.item)
LOOT_DROPPED.postThen(
event = LootDroppedEvent(this, player, entity, drops),
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
@@ -1,18 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.drop
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.pokemon.Pokemon
class EvolutionItemDropEntry : ItemDropEntry() {
val requirements: MutableSet<EvolutionRequirement> = mutableSetOf()
override fun canDrop(pokemon: Pokemon?): Boolean = pokemon != null && requirements.all { it.check(pokemon) }
}
@@ -13,13 +13,9 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
import com.cobblemon.mod.common.util.asArrayValue
import net.minecraft.world.entity.LivingEntity
/**
* Event fired when a battle is won by some number of [BattleActor]s.
@@ -44,8 +40,6 @@ data class BattleVictoryEvent (
"npc_losers" to losers.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon_winners" to winners.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
"wild_pokemon_losers" to losers.filter { it.type == ActorType.WILD }.asArrayValue { it.struct },
"scriptable_winners" to winners.filterIsInstance<EntityBackedBattleActor<*>>().mapNotNull { it.entity as? MoLangScriptingEntity }.asArrayValue { (it as LivingEntity).asMostSpecificMoLangValue() },
"scriptable_losers" to losers.filterIsInstance<EntityBackedBattleActor<*>>().mapNotNull { it.entity as? MoLangScriptingEntity }.asArrayValue { (it as LivingEntity).asMostSpecificMoLangValue() },
"players" to battle.actors.filter { it.type == ActorType.PLAYER }.asArrayValue { it.struct },
"npcs" to battle.actors.filter { it.type == ActorType.NPC }.asArrayValue { it.struct },
"wild_pokemon" to battle.actors.filter { it.type == ActorType.WILD }.asArrayValue { it.struct }
@@ -18,17 +18,19 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.LivingEntity
data class PokemonScannedEvent(val player: ServerPlayer, val scannedPokemonEntityData: PokedexEntityData, val scannedEntity: ScannableEntity) {
val pokedexEntityData: PokedexEntityData
get() = scannedPokemonEntityData
val isOwned: Boolean
get() = scannedPokemonEntityData.pokemon.getOwnerUUID() == player.uuid
get() = scannedPokemonEntityData.ownerUUID == player.uuid
val context = mutableMapOf(
"player" to player.asMoLangValue(),
"pokemon" to scannedPokemonEntityData.pokemon.struct,
"disguise" to (scannedPokemonEntityData.disguise?.struct ?: DoubleValue.ZERO),
"pokemon" to scannedPokemonEntityData.struct,
"entity" to {
when (scannedEntity) {
is LivingEntity -> scannedEntity.asMostSpecificMoLangValue()
else -> DoubleValue.ZERO
else -> DoubleValue(0.0)
}
},
)
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common.api.events.pokemon
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.pokemon.Pokemon
/**
@@ -19,11 +18,5 @@ import com.cobblemon.mod.common.pokemon.Pokemon
*/
data class FriendshipUpdatedEvent(
val pokemon: Pokemon,
val newFriendshipInitial: Int
)
{
var newFriendship: Int = newFriendshipInitial
set(value) {
field = value.coerceIn(0, Cobblemon.config.maxPokemonFriendship)
}
}
var newFriendship: Int
)
@@ -17,14 +17,16 @@ import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
import com.cobblemon.mod.common.api.pokedex.FormDexRecord
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.getPlayer
import com.mojang.datafixers.util.Either
import java.util.UUID
/**
* Event that fires when a Pokémon's information is gained or updated in the Pokédex.
*/
sealed interface PokedexDataChangedEvent {
val dataSource: PokedexEntityData
val dataSource: Either<PokedexEntityData, Pokemon>
val knowledge: PokedexEntryProgress
val playerUUID: UUID
val record: FormDexRecord
@@ -35,22 +37,22 @@ sealed interface PokedexDataChangedEvent {
fun getContext(): MutableMap<String, MoValue> {
return mutableMapOf(
"player" to (playerUUID.getPlayer()?.asMoLangValue() ?: DoubleValue.ZERO),
"pokemon" to dataSource.pokemon.struct,
"disguise" to (dataSource.disguise?.struct ?: DoubleValue.ZERO),
"pokemon" to dataSource.map({ DoubleValue.ZERO }, { it.struct }),
"data" to dataSource.map({ it.struct }, { DoubleValue.ZERO }),
"knowledge" to StringValue(knowledge.name.lowercase()),
"pokedex" to pokedexManager.struct
)
}
class Pre(
override val dataSource: PokedexEntityData,
override val dataSource: Either<PokedexEntityData, Pokemon>,
override val knowledge: PokedexEntryProgress,
override val playerUUID: UUID,
override val record: FormDexRecord
) : PokedexDataChangedEvent, Cancelable()
class Post(
override val dataSource: PokedexEntityData,
override val dataSource: Either<PokedexEntityData, Pokemon>,
override val knowledge: PokedexEntryProgress,
override val playerUUID: UUID,
override val record: FormDexRecord
@@ -0,0 +1,29 @@
/*
* 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.interaction
import com.google.gson.JsonDeserializer
import com.google.gson.JsonSerializer
import kotlin.reflect.KClass
import net.minecraft.resources.ResourceLocation
/**
* A type adapter for [EntityInteraction]s.
* For the default implementation with Pokémon entities see [CobblemonPokemonEntityInteractionTypeAdapter].
*
* @param T The type of [EntityInteraction].
*
* @author Licious
* @since November 30th, 2022
*/
interface EntityInteractionTypeAdapter<T : EntityInteraction<*>> : JsonDeserializer<T>, JsonSerializer<T> {
fun registerInteraction(identifier: ResourceLocation, type: KClass<out T>)
}
@@ -90,13 +90,11 @@ import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.LightningBolt
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.PathfinderMob
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
import net.minecraft.world.entity.ai.memory.MemoryModuleType
import net.minecraft.world.entity.ai.memory.MemoryStatus
import net.minecraft.world.entity.ai.memory.WalkTarget
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.ClipContext
import net.minecraft.world.level.Level
import net.minecraft.world.level.Level.ExplosionInteraction
import net.minecraft.world.level.biome.Biome
@@ -421,38 +419,6 @@ object MoLangFunctions {
val source = DamageSource(entity.level().registryAccess().registryOrThrow(Registries.DAMAGE_TYPE).getHolder(DamageTypes.GENERIC).get())
entity.hurt(source, amount.toFloat())
}
map.put("distance_to_owner") {
if (entity !is TamableAnimal) {
return@put DoubleValue.ZERO
}
val owner = entity.owner ?: return@put DoubleValue.ZERO
return@put DoubleValue(entity.distanceTo(owner))
}
map.put("owner") {
if (entity !is TamableAnimal) {
return@put DoubleValue.ZERO
}
val owner = entity.owner
return@put owner?.asMostSpecificMoLangValue() ?: DoubleValue.ZERO
}
map.put("can_see") { params ->
val target = params.get<MoValue>(0)
val range = params.getDoubleOrNull(1) ?: 32.0
if (target is ObjectValue<*>) {
val targetEntity = target.obj as? LivingEntity ?: return@put DoubleValue.ZERO
val vector = targetEntity.eyePosition.subtract(entity.eyePosition).normalize()
val trace = entity.traceEntityCollision(
maxDistance = range.toFloat(),
stepDistance = 0.1F,
direction = vector,
entityClass = targetEntity.javaClass,
collideBlock = ClipContext.Fluid.NONE
)
return@put DoubleValue(targetEntity in (trace?.entities ?: emptyList()))
} else {
return@put DoubleValue.ZERO
}
}
map.put("walk_to") { params ->
val x = params.getDouble(0)
val y = params.getDouble(1)
@@ -732,8 +698,6 @@ object MoLangFunctions {
map.put("max_hp") { DoubleValue(pokemon.maxHealth.toDouble()) }
map.put("current_hp") { DoubleValue(pokemon.currentHealth.toDouble()) }
map.put("friendship") { DoubleValue(pokemon.friendship.toDouble()) }
map.put("behaviour") { pokemon.form.behaviour.struct }
map.put("behavior") { pokemon.form.behaviour.struct } // Inferior
map.put("evs") {
val struct = QueryStruct(hashMapOf())
for (stat in Stats.PERMANENT) {
@@ -750,7 +714,6 @@ object MoLangFunctions {
}
map.put("is_wild") { DoubleValue(pokemon.entity?.let { it.ownerUUID == null } == true) }
map.put("is_shiny") { DoubleValue(pokemon.shiny) }
map.put("is_in_party") { DoubleValue(pokemon.storeCoordinates.get()?.store is PartyStore) }
map.put("species") { pokemon.species.struct }
map.put("form") { StringValue(pokemon.form.name) }
map.put("weight") { DoubleValue(pokemon.species.weight.toDouble()) }
@@ -1034,6 +997,7 @@ object MoLangFunctions {
map.put("hitbox_height") { DoubleValue(species.hitbox.height) }
map.put("hitbox_fixed") { DoubleValue(species.hitbox.fixed) }
map.put("catch_rate") { DoubleValue(species.catchRate) }
map
}
)
@@ -1129,7 +1093,7 @@ object MoLangFunctions {
}
/**
* Different functions exist depending on the entity type, this tries to make the struct that's most specific to the type.
* Different functions exist depending on
*/
fun LivingEntity.asMostSpecificMoLangValue(): ObjectValue<out LivingEntity> {
return when (this) {
@@ -1198,7 +1162,6 @@ object MoLangFunctions {
.flatMap { it.invoke(pokemonEntity).entries }
.associate { it.key to it.value }
functions.putAll(addedFunctions)
pokemonEntity.registerFunctionsForScripting(this)
return this
}
@@ -54,15 +54,7 @@ class BenchedMoves : Iterable<BenchedMove> {
}
}
fun add(benchedMove: BenchedMove): Boolean {
if (any { it.moveTemplate == benchedMove.moveTemplate }) {
return false
}
doThenEmit { benchedMoves.add(benchedMove) }
return true
}
fun add(benchedMove: BenchedMove) = doThenEmit { benchedMoves.add(benchedMove) }
fun addAll(benchedMoves: Iterable<BenchedMove>) = doThenEmit { this.benchedMoves.addAll(benchedMoves) }
fun clear() = doThenEmit { benchedMoves.clear() }
fun remove(benchedMove: BenchedMove) = doThenEmit { benchedMoves.remove(benchedMove) }
@@ -134,21 +134,18 @@ class MoveSet : Iterable<Move> {
return json
}
fun add(move: Move): Boolean {
fun add(move: Move) {
if (any { it.template == move.template }) {
return false
return
}
for (i in 0 until MOVE_COUNT) {
if (moves[i] == null) {
moves[i] = move
move.observable.subscribe { this.update() }
update()
return true
return
}
}
return false
}
fun update() {
@@ -13,7 +13,7 @@ import com.bedrockk.molang.runtime.value.MoValue
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.api.ai.config.BrainConfig
import com.cobblemon.mod.common.api.npc.configuration.NPCBattleConfiguration
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
import com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider
import com.cobblemon.mod.common.api.npc.variation.RandomNPCVariationProvider
@@ -45,7 +45,7 @@ class NPCClass {
var interaction: NPCInteractConfiguration? = null
var canDespawn = true
var variations: MutableMap<String, NPCVariationProvider> = mutableMapOf()
var config: MutableList<MoLangConfigVariable> = mutableListOf()
var config: MutableList<NPCConfigVariable> = mutableListOf()
var variables = mutableMapOf<String, MoValue>() // Questionable whether this should be here.
var party: NPCPartyProvider? = null
var skill: Int = 0
@@ -57,7 +57,6 @@ class NPCClass {
var isInvulnerable = false
var isLeashable = true
var allowProjectileHits = true
var hideNameTag = false
// If you're adding stuff here, add it to NPCPreset and NPCClassAdapter too
@@ -81,7 +80,6 @@ class NPCClass {
}
buffer.writeCollection(config) { _, v ->
buffer.writeString(v.variableName)
buffer.writeText(v.category)
buffer.writeText(v.displayName)
buffer.writeText(v.description)
buffer.writeEnumConstant(v.type)
@@ -99,7 +97,6 @@ class NPCClass {
buffer.writeBoolean(isInvulnerable)
buffer.writeBoolean(isLeashable)
buffer.writeBoolean(allowProjectileHits)
buffer.writeBoolean(hideNameTag)
}
fun decode(buffer: RegistryFriendlyByteBuf) {
@@ -128,12 +125,11 @@ class NPCClass {
}
config = buffer.readList {
val variableName = buffer.readString()
val category = buffer.readText()
val displayName = buffer.readText()
val description = buffer.readText()
val type = buffer.readEnumConstant(MoLangConfigVariable.MoLangVariableType::class.java)
val type = buffer.readEnumConstant(NPCConfigVariable.NPCVariableType::class.java)
val defaultValue = buffer.readString()
MoLangConfigVariable(variableName, category, displayName, description, type, defaultValue)
NPCConfigVariable(variableName, displayName, description, type, defaultValue)
}.toMutableList()
skill = buffer.readInt()
autoHealParty = buffer.readBoolean()
@@ -152,6 +148,5 @@ class NPCClass {
isInvulnerable = buffer.readBoolean()
isLeashable = buffer.readBoolean()
allowProjectileHits = buffer.readBoolean()
hideNameTag = buffer.readBoolean()
}
}
@@ -20,8 +20,6 @@ import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropMethod
import com.cobblemon.mod.common.api.entity.EntityDimensionsAdapter
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.NPCClasses.getByIdentifier
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
import com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider
import com.cobblemon.mod.common.api.npc.variation.WeightedAspect
@@ -76,10 +74,6 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
.registerTypeAdapter(WeightedAspect::class.java, WeightedAspectAdapter)
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
.registerTypeAdapter(
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
ExpressionOrEntityVariableAdapter
)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
@@ -96,6 +90,14 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
val classes: Collection<NPCClass>
get() = this.npcClassesByIdentifier.values
init {
// NPC additions would be useful
// SpeciesAdditions.observable.subscribe {
// this.species.forEach(Species::initialize)
// this.species.forEach(Species::resolveEvolutionMoves)
// }
}
/**
* Finds an NPC class by the pathname of their [ResourceLocation].
* This method exists for the convenience of finding Cobble default NPC classes.
@@ -9,7 +9,7 @@
package com.cobblemon.mod.common.api.npc
import com.cobblemon.mod.common.api.ai.config.BrainConfig
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
import com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider
import net.minecraft.network.chat.Component
@@ -21,7 +21,7 @@ class NPCPreset {
var resourceIdentifier: ResourceLocation? = null
var aspects: Set<String>? = null
var variations: Map<String, NPCVariationProvider>? = null
var config: List<MoLangConfigVariable>? = null
var config: List<NPCConfigVariable>? = null
var party: NPCPartyProvider? = null
var canDespawn: Boolean? = null
var interaction: NPCInteractConfiguration? = null
@@ -37,7 +37,6 @@ class NPCPreset {
var isInvulnerable: Boolean? = null
var isLeashable: Boolean? = null
var allowProjectileHits: Boolean? = null
var hideNameTag: Boolean? = null
fun applyTo(npcClass: NPCClass) {
resourceIdentifier?.let { npcClass.resourceIdentifier = it }
@@ -64,6 +63,5 @@ class NPCPreset {
isInvulnerable?.let { npcClass.isInvulnerable = it }
isLeashable?.let { npcClass.isLeashable = it }
allowProjectileHits?.let { npcClass.allowProjectileHits = it }
hideNameTag?.let { npcClass.hideNameTag = it }
}
}
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropMethod
import com.cobblemon.mod.common.api.entity.EntityDimensionsAdapter
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
import com.cobblemon.mod.common.api.npc.configuration.NPCInteractConfiguration
import com.cobblemon.mod.common.api.npc.variation.NPCVariationProvider
import com.cobblemon.mod.common.api.npc.variation.WeightedAspect
@@ -71,10 +70,6 @@ object NPCPresets : JsonDataRegistry<NPCPreset> {
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
.registerTypeAdapter(
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
ExpressionOrEntityVariableAdapter
)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)

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