mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
157
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d4e752769 | ||
|
|
d245ae12c7 | ||
|
|
36c4ea3b1a | ||
|
|
804ad75ede | ||
|
|
be11568041 | ||
|
|
8ad54287e4 | ||
|
|
179d90d482 | ||
|
|
c3fb661f49 | ||
|
|
dccffe311f | ||
|
|
d7d8d766d1 | ||
|
|
54b2cc0a59 | ||
|
|
62696931df | ||
|
|
bfc7f83e07 | ||
|
|
db573455ea | ||
|
|
3af002a39c | ||
|
|
a15c44325d | ||
|
|
33fc67ed58 | ||
|
|
b9f2bcc3a3 | ||
|
|
8a5a88b4f1 | ||
|
|
af6b1190c1 | ||
|
|
7f0a6d4d48 | ||
|
|
d7e4298a91 | ||
|
|
923b4e4266 | ||
|
|
b6966c0e1f | ||
|
|
c40b8ae7b1 | ||
|
|
07bba37c03 | ||
|
|
5896a74d1f | ||
|
|
74d2f4f700 | ||
|
|
6ed4504273 | ||
|
|
8ee6799653 | ||
|
|
96cbc4eca6 | ||
|
|
ad24e529f5 | ||
|
|
2f4bdb336b | ||
|
|
da7dbeaaec | ||
|
|
dea2ad4b12 | ||
|
|
7dd38bf043 | ||
|
|
4caba2fbeb | ||
|
|
e6b1529f27 | ||
|
|
a42ba8de43 | ||
|
|
078c961090 | ||
|
|
676342348a | ||
|
|
97442cb880 | ||
|
|
478804f652 | ||
|
|
55dc5c6760 | ||
|
|
0d3b89828a | ||
|
|
fab1bc6f80 | ||
|
|
6b4ff0ac84 | ||
|
|
193daed8ff | ||
|
|
628c8f6093 | ||
|
|
eac0f209ce | ||
|
|
9ac0fc1b36 | ||
|
|
2e05b25061 | ||
|
|
60fc0c1959 | ||
|
|
1cd112ac74 | ||
|
|
4fe54d3dba | ||
|
|
cb11c2b964 | ||
|
|
8aeb7a43c8 | ||
|
|
cd575e6b7d | ||
|
|
39dbf78ed2 | ||
|
|
7806503ea7 | ||
|
|
7e4054ad8f | ||
|
|
af49e14cfb | ||
|
|
9d38ad78bf | ||
|
|
b59483e52f | ||
|
|
2058184da2 | ||
|
|
9c861392f8 | ||
|
|
d3717fb222 | ||
|
|
54c7e05c8f | ||
|
|
7148f9d954 | ||
|
|
3b9a8c8492 | ||
|
|
b7446fa029 | ||
|
|
9123cc3a2c | ||
|
|
f0dc9be471 | ||
|
|
819635f457 | ||
|
|
d3a2a5827e | ||
|
|
a9ed3750ad | ||
|
|
24fdae725e | ||
|
|
71fc844905 | ||
|
|
24910778d4 | ||
|
|
363c3e5f0a | ||
|
|
8d336fca3e | ||
|
|
ff27676187 | ||
|
|
1fd5d0ff4b | ||
|
|
46752a3911 | ||
|
|
76ad22b53d | ||
|
|
a2ddcaebf8 | ||
|
|
6fc725b6ff | ||
|
|
01efc8d9e0 | ||
|
|
3a05bd5e2e | ||
|
|
439c9647ca | ||
|
|
eb952319e0 | ||
|
|
4787c1d35b | ||
|
|
98394333da | ||
|
|
653b9be4a3 | ||
|
|
a3460a4b8f | ||
|
|
71024481f4 | ||
|
|
7c191981bd | ||
|
|
0be9ac9f59 | ||
|
|
c69f1e6adc | ||
|
|
a26a07337a | ||
|
|
fd74f157a8 | ||
|
|
885cde045a | ||
|
|
bfcaa4bda4 | ||
|
|
7370841e62 | ||
|
|
3c347214a8 | ||
|
|
91f9af1bed | ||
|
|
b32c2e1274 | ||
|
|
400f764054 | ||
|
|
5b6900b74a | ||
|
|
05d0adc947 | ||
|
|
24c2ac116a | ||
|
|
4f558d36e6 | ||
|
|
38218e4001 | ||
|
|
bd8e533bbd | ||
|
|
52b756c33d | ||
|
|
91ce0d9eab | ||
|
|
17ea2bb80f | ||
|
|
e76b047ed3 | ||
|
|
33be35f27b | ||
|
|
ea73382ea3 | ||
|
|
592b4276c8 | ||
|
|
a73cdfbb4f | ||
|
|
770a2e52f6 | ||
|
|
6629b27f33 | ||
|
|
73b06d2f99 | ||
|
|
a07a9a75c0 | ||
|
|
d6fdb4c6da | ||
|
|
c5e036934a | ||
|
|
d9938a5cfd | ||
|
|
fc5d9615fc | ||
|
|
e160a42b83 | ||
|
|
fa68aa44c5 | ||
|
|
f3de9840b5 | ||
|
|
64e3909cea | ||
|
|
735c4b910e | ||
|
|
26a9a1f9e1 | ||
|
|
832ab8db95 | ||
|
|
1d9029ef51 | ||
|
|
a875ba7536 | ||
|
|
93de4785b4 | ||
|
|
765f0e5494 | ||
|
|
4fc232ff31 | ||
|
|
a4d75e9f32 | ||
|
|
a86ae09dc9 | ||
|
|
a5fbafe64d | ||
|
|
1de93b4933 | ||
|
|
f8dfc7c6cc | ||
|
|
accbed9c2b | ||
|
|
8b0e615777 | ||
|
|
746f12c724 | ||
|
|
a11d306a1b | ||
|
|
40d140e84d | ||
|
|
ffdb4842ac | ||
|
|
6baf60d07c | ||
|
|
cb3b7784b0 | ||
|
|
ee4f3b1629 | ||
|
|
518a7daa0e |
@@ -0,0 +1,15 @@
|
||||
### Additions
|
||||
- Rebuilt Pokémon AI to use Minecraft's Brain system, allowing for more complex behaviours and interactions.
|
||||
- As an early pass of this, pastured Pokémon will now sleep when appropriate, and may come up to you when they see you.
|
||||
- Probably also added a whole bunch of bugs.
|
||||
- Growlithe and Arcanine intimidate Skeletons.
|
||||
- Meowth intimidate Creepers and Phantoms.
|
||||
- Added a Behaviour Editor to the NPC editing screen.
|
||||
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
|
||||
- Editing variables for Pokémon is not yet supported.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
|
||||
- Added many default behaviours.
|
||||
- Removed many NPC presets that now exist as behaviours. This is a breaking change if you are using NPCs with these presets.
|
||||
- NPCs with these presets should be modified to instead list under `"behaviours"` all the equivalent behaviours.
|
||||
@@ -134,6 +134,8 @@
|
||||
- Improved parity with vanilla mobs' drop behavior; loot and XP drop on death instead of after the entire death sequence finishes.
|
||||
- Quirk animations no longer play in the battle GUI since they were pretty distracting.
|
||||
- A number of Pokemon that float above the ground visually (Gastly, Klingklang, etc.) are no longer considered to be touching the ground
|
||||
- Renamed `pokemonId` and `type` to `species` in relevant Advancement triggers for conformity, this is a breaking change.
|
||||
- Added a separate `species` argument to the `pick_starter`, `pasture_use` and `resurrect_pokemon` Advancement triggers.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -165,6 +167,8 @@
|
||||
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
|
||||
- Fixed issue with Pokédex Scanner that caused the open/close overlay to have the wrong opacity values
|
||||
- Fixed dragon's breath not being usable on the restoration tank when it should be
|
||||
- Fixed Moon Stones not interacting properly with dripstone blocks.
|
||||
- Fixed some effects like particles from fishing rods appearing for players in the same coordinates in another world.
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
|
||||
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
|
||||
|
||||
- Why is magikarp trying to path through ice
|
||||
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
|
||||
|
||||
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
|
||||
NPC wandering will be jank too.
|
||||
+1
-1
@@ -5,7 +5,7 @@ plugins {
|
||||
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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);
|
||||
//// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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"))
|
||||
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)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class EntityVillagerMixin {
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final Villager villager = (Villager) (Object) this;
|
||||
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "isBarterCurrency", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
if (!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
if (stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import org.spongepowered.asm.mixin.injection.Slice;
|
||||
public abstract class PointedDripstoneBlockMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "canTipGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/Block;"))
|
||||
method = "canGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/block/Block;"))
|
||||
)
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
|
||||
return instance.is(CobblemonBlockTags.DRIPSTONE_GROWABLE);
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.BlockEntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.EntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.client.sound.SoundTracker;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
@@ -51,11 +52,10 @@ public abstract class CameraMixin {
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
@Unique boolean disableRollableCameraDebug = false;
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || disableRollableCameraDebug) return;
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || Cobblemon.config.getDisableRoll()) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
@@ -128,9 +128,9 @@ public abstract class CameraMixin {
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
this.forwards.set(controller.getForwardVector());
|
||||
this.up.set(controller.getUpVector());
|
||||
this.left.set(controller.getLeftVector());
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.TextClipping;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* This mixin facilitates the gradual reveal of text with NPC dialogue. If there is a better way
|
||||
* to do this, I'd love to hear it.
|
||||
*
|
||||
* The idea is that somewhere static in the mod we have a control for how many characters can be drawn
|
||||
* and how many have been drawn so far, and this mixin will add to the latter and stop drawing characters
|
||||
* once it reaches the former.
|
||||
*
|
||||
* This relies STRONGLY on the code that sets the character cap to reset it to -1 after the text is rendered,
|
||||
* otherwise all text in Minecraft will stop drawing.
|
||||
*
|
||||
* Sites that take advantage of this mixin will do the following:
|
||||
* 1: Set the character cap, which resets the drawn counter to zero.
|
||||
* 2: Call whatever Minecraft function draws your text.
|
||||
* 3: Reset the character cap to -1, which will allow regular text to draw again.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since April 18th, 2025
|
||||
*/
|
||||
@Mixin(Font.StringRenderOutput.class)
|
||||
public class StringRenderOutputMixin {
|
||||
@Inject(method = "accept", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void onAccept(int i, Style style, int j, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!TextClipping.canDrawAnotherCharacter()) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ 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"))
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry.Companion.JSON_EXTENSION
|
||||
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.BehaviourSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BehaviourConfigAdapter
|
||||
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.cobblemon.mod.common.util.endsWith
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.io.File
|
||||
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.server.packs.resources.ResourceManager
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BehaviourConfig::class.java, BehaviourConfigAdapter)
|
||||
.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(CobblemonBehaviour::class.java)
|
||||
override val resourcePath = "behaviours"
|
||||
override val id: ResourceLocation = cobblemonResource("behaviours")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonBehaviours>()
|
||||
|
||||
/**
|
||||
* Any behaviours that are put into /pokemon/auto will be automatically
|
||||
* applied to all Pokémon species/forms that don't define a baseAI list of
|
||||
* behaviour configurations. This is an addon-friendly way of defining the general
|
||||
* rules of Pokémon AI without it being unavoidable for specific
|
||||
* species.
|
||||
*/
|
||||
val autoPokemonBehaviours = mutableListOf<CobblemonBehaviour>()
|
||||
|
||||
val behaviours = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(BehaviourSyncPacket(behaviours.filter { it.value.visible }))
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
autoPokemonBehaviours.clear()
|
||||
val data = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
manager.listResources(resourcePath) { path -> path.endsWith(JSON_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
val behaviour = parse(reader, resolvedIdentifier)
|
||||
if ("pokemon/auto/" in identifier.path) {
|
||||
autoPokemonBehaviours.add(behaviour)
|
||||
}
|
||||
data[resolvedIdentifier] = behaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reload(data)
|
||||
Cobblemon.LOGGER.info("Loaded ${behaviours.size} entity behaviours")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, CobblemonBehaviour>) {
|
||||
behaviours.clear()
|
||||
behaviours.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.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.reactive.SimpleObservable
|
||||
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.TaskConfigAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonBrainConfigs : JsonDataRegistry<List<BrainConfig>> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.create()
|
||||
|
||||
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, List<BrainConfig>>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// TODO implement probs ay
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, List<BrainConfig>>) {
|
||||
presets.clear()
|
||||
presets.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ object CobblemonCommands {
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
BehaviourEditCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
MarkGiveCommand.register(dispatcher)
|
||||
MarkTakeCommand.register(dispatcher)
|
||||
|
||||
@@ -16,14 +16,32 @@ 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 PATH_COOLDOWN = register<Boolean>("path_cooldown")
|
||||
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")
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
@@ -36,4 +54,4 @@ object CobblemonMemories {
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
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.CalculateSeatPositionsHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
@@ -60,6 +61,7 @@ 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.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
@@ -138,6 +140,7 @@ import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPack
|
||||
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.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
@@ -184,6 +187,7 @@ 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.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
|
||||
@@ -382,6 +386,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SeasoningRegistrySyncPacket.ID, SeasoningRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
@@ -436,6 +441,9 @@ 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))
|
||||
|
||||
@@ -551,6 +559,9 @@ object CobblemonNetwork {
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
// Behaviour Packets
|
||||
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
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.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
|
||||
@@ -20,10 +25,20 @@ 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)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,18 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val PC_WALLPAPER_UNLOCK = this.create("pc.wallpaper.unlock")
|
||||
|
||||
@JvmField
|
||||
val NPC_GIBBER_GENERIC = this.create("entity.npc.gibber.generic")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_1 = this.create("entity.npc.gibber.speech_type_1_1")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_2 = this.create("entity.npc.gibber.speech_type_1_2")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_3 = this.create("entity.npc.gibber.speech_type_1_3")
|
||||
|
||||
@JvmField
|
||||
val VILLAGER_WORK_NURSE = this.create("entity.villager.work_nurse")
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE_ACTIVE = this.create("block.healing_machine.active")
|
||||
|
||||
@@ -460,4 +470,4 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-32
@@ -18,7 +18,7 @@ import java.util.Optional
|
||||
|
||||
class AspectCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val pokemon: ResourceLocation,
|
||||
val species: ResourceLocation,
|
||||
val aspects: List<String>
|
||||
): SimpleCriterionCondition<MutableMap<ResourceLocation, MutableSet<String>>>(playerCtx) {
|
||||
|
||||
@@ -26,42 +26,13 @@ class AspectCriterion(
|
||||
val CODEC: Codec<AspectCriterion> = RecordCodecBuilder.create { it.group(
|
||||
//All three of these codecs used to use Codecs.createStrictOptionalFieldCodec, that no longer exists
|
||||
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(AspectCriterion::playerCtx),
|
||||
ResourceLocation.CODEC.optionalFieldOf("pokemon", cobblemonResource("pikachu")).forGetter(AspectCriterion::pokemon),
|
||||
ResourceLocation.CODEC.optionalFieldOf("species", cobblemonResource("pikachu")).forGetter(AspectCriterion::species),
|
||||
Codec.STRING.listOf().optionalFieldOf("aspects", listOf()).forGetter(AspectCriterion::aspects)
|
||||
) .apply(it, ::AspectCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: MutableMap<ResourceLocation, MutableSet<String>>): Boolean {
|
||||
val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
val caughtAspects = context.getOrDefault(species, mutableSetOf())
|
||||
return this.aspects.all { it in caughtAspects }
|
||||
}
|
||||
}
|
||||
|
||||
//open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
|
||||
// var pokemon = Identifier.of("cobblemon:pikachu")
|
||||
// var aspects = mutableListOf<String>()
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// json.add("aspects", JsonArray(aspects.size).also {
|
||||
// aspects.forEach { aspect -> it.add(aspect) }
|
||||
// })
|
||||
// json.addProperty("pokemon", pokemon.toString())
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// aspects.clear()
|
||||
// json.getAsJsonArray("aspects").forEach { element ->
|
||||
// aspects.add(element.asString)
|
||||
// }
|
||||
// pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayer, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
|
||||
// val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
// return this.aspects.all { it in caughtAspects }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
+4
-21
@@ -21,40 +21,23 @@ import java.util.Optional
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
open class CountablePokemonTypeContext(times: Int, var type: String) : CountableContext(times)
|
||||
open class CountablePokemonTypeContext(times: Int, var species: String) : CountableContext(times)
|
||||
|
||||
class CaughtPokemonCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val type: String,
|
||||
val species: String,
|
||||
count: Int
|
||||
): CountableCriterion<CountablePokemonTypeContext>(playerCtx, count) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<CaughtPokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(CaughtPokemonCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("type", "any").forGetter(CaughtPokemonCriterion::type),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(CaughtPokemonCriterion::species),
|
||||
Codec.INT.optionalFieldOf("count", 0).forGetter(CaughtPokemonCriterion::count)
|
||||
).apply(it, ::CaughtPokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
|
||||
return super.matches(player, context) && (context.type == type || type == "any")
|
||||
return super.matches(player, context) && (context.species == species || species == "any")
|
||||
}
|
||||
}
|
||||
|
||||
//class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
|
||||
// var type = "any"
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// super.toJson(json)
|
||||
// json.addProperty("type", type)
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// super.fromJson(json)
|
||||
// type = json.get("type")?.asString ?: "any"
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
|
||||
// return super.matches(player, context) && (context.type == type || type == "any")
|
||||
// }
|
||||
//}
|
||||
+4
-2
@@ -19,17 +19,19 @@ import java.util.Optional
|
||||
|
||||
class PokemonCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val properties: PokemonProperties
|
||||
): SimpleCriterionCondition<Pokemon>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(PokemonCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(PokemonCriterion::species),
|
||||
PokemonProperties.CODEC.optionalFieldOf("properties", PokemonProperties()).forGetter(PokemonCriterion::properties)
|
||||
).apply(it, ::PokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: Pokemon): Boolean {
|
||||
return properties.matches(context)
|
||||
return (species.equals(context.species.resourceIdentifier.path) || species.equals(context.species.resourceIdentifier)) && properties.matches(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -17,22 +17,22 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.util.Optional
|
||||
|
||||
class PokemonInteractContext(val type: ResourceLocation, val item: ResourceLocation)
|
||||
class PokemonInteractContext(val species: ResourceLocation, val item: ResourceLocation)
|
||||
|
||||
class PokemonInteractCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val type: String,
|
||||
val species: String,
|
||||
val item: String
|
||||
): SimpleCriterionCondition<PokemonInteractContext>(playerCtx) {
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonInteractCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(PokemonInteractCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("type", "any").forGetter(PokemonInteractCriterion::type),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(PokemonInteractCriterion::species),
|
||||
Codec.STRING.optionalFieldOf("item", "any").forGetter(PokemonInteractCriterion::item)
|
||||
).apply(it, ::PokemonInteractCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: PokemonInteractContext): Boolean {
|
||||
return (context.type == this.type.asIdentifierDefaultingNamespace() || this.type == "any") && (context.item == this.item.asIdentifierDefaultingNamespace() || this.item == "any")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.item == this.item.asIdentifierDefaultingNamespace() || this.item == "any")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -17,23 +17,23 @@ import net.minecraft.advancements.critereon.EntityPredicate
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class ReelInPokemonContext(val pokemonId : ResourceLocation, val baitId: ResourceLocation)
|
||||
class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceLocation)
|
||||
|
||||
class ReelInPokemonCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val pokemonId: String,
|
||||
val species: String,
|
||||
val baitId: String
|
||||
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("pokemonId", "any").forGetter { it.pokemonId },
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
|
||||
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
|
||||
return (context.pokemonId == this.pokemonId.asIdentifierDefaultingNamespace() || this.pokemonId == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -8,12 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.config.BrainConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
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 {
|
||||
class BehaviourConfigurationContext {
|
||||
var appliedBehaviours: Set<ResourceLocation> = setOf()
|
||||
|
||||
var defaultActivity = Activity.IDLE
|
||||
var coreActivities = setOf(Activity.CORE)
|
||||
@@ -24,11 +27,16 @@ class BrainConfigurationContext {
|
||||
return activities.firstOrNull { it.activity == activity } ?: ActivityConfigurationContext(activity).also(activities::add)
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity, brainConfigs: List<BrainConfig>) {
|
||||
fun apply(entity: LivingEntity, behaviourConfigs: List<BehaviourConfig>) {
|
||||
val brain = entity.brain
|
||||
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
entity.registerVariables(behaviourConfigs.flatMap { it.getVariables(entity) })
|
||||
entity.initializeScripting()
|
||||
}
|
||||
|
||||
// Setup the brain config
|
||||
brainConfigs.forEach { it.configure(entity, this) }
|
||||
behaviourConfigs.forEach { it.configure(entity, this) }
|
||||
|
||||
// Apply the brain config
|
||||
activities.forEach { it.apply(entity) }
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
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.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CobblemonBehaviour(
|
||||
val name: Component = "".asTranslated(),
|
||||
val description: Component = "".asTranslated(),
|
||||
/** Some behaviours aren't really worth showing on the client, namely ones that are simply conditional bundles of other behaviours. */
|
||||
val visible: Boolean = true,
|
||||
val entityType: ResourceLocation? = null,
|
||||
val configurations: List<BehaviourConfig> = mutableListOf(),
|
||||
val undo: ExpressionLike? = null,
|
||||
val undoScript: ResourceLocation? = null,
|
||||
) {
|
||||
fun canBeApplied(entity: LivingEntity) = entityType?.let { entityType == entity.type.builtInRegistryHolder().unwrapKey().get().location() } != false
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
configurations.forEach { it.configure(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
|
||||
/** Undoes anything that needs undoing once this configuration is being removed from an entity that had it before. */
|
||||
fun undo(entity: LivingEntity) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (undoScript != null) {
|
||||
CobblemonScripts.run(undoScript, runtime)
|
||||
}
|
||||
if (undo != null) {
|
||||
runtime.resolve(undo)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.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() }
|
||||
|
||||
|
||||
+20
-18
@@ -8,32 +8,34 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
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.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 com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class AddTasksToActivity : BrainConfig {
|
||||
val activity = Activity.IDLE
|
||||
val condition = "true".asExpressionLike()
|
||||
class AddTasksToActivity : BehaviourConfig {
|
||||
val activity: Activity? = null
|
||||
// Can be useful to add to multiple activities at once
|
||||
val activities = mutableListOf<Activity>()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
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) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val activities = if (activity != null) (activities + activity) else activities
|
||||
|
||||
val activity = brainConfigurationContext.getOrCreateActivity(activity)
|
||||
tasksByPriority.forEach { (priority, taskConfigs) ->
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
activity.addTasks(priority, *tasks.toTypedArray())
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
for (activity in activities) {
|
||||
val activityContext = behaviourConfigurationContext.getOrCreateActivity(activity)
|
||||
activityContext.addTasks(priority, *tasks.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class AddVariablesConfig(val variables: List<MoLangConfigVariable> = emptyList()) : BehaviourConfig {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
// Configuration happens naturally through the override on variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.google.gson.annotations.SerializedName
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class ApplyBehaviours : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
@SerializedName("behaviours", alternate = ["behaviors"])
|
||||
val behaviours = mutableListOf<ResourceLocation>()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return if (checkCondition(entity, condition)) {
|
||||
behaviours.flatMap {
|
||||
CobblemonBehaviours.behaviours[it]?.configurations?.flatMap { it.getVariables(entity) } ?: emptyList()
|
||||
} + listOf(condition).asVariables()
|
||||
} else {
|
||||
listOf(condition).asVariables()
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $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 originalContextBehaviours = behaviourConfigurationContext.appliedBehaviours.toMutableSet()
|
||||
configurations.forEach {
|
||||
it.configure(entity, behaviourConfigurationContext)
|
||||
}
|
||||
originalContextBehaviours.addAll(behaviours)
|
||||
behaviourConfigurationContext.appliedBehaviours = originalContextBehaviours
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.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.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 {
|
||||
val condition = "true".asExpressionLike()
|
||||
val presets = mutableListOf<ResourceLocation>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
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] ?: return Cobblemon.LOGGER.warn("Preset $it not found") }
|
||||
presetConfigs.forEach { it.configure(entity, brainConfigurationContext) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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.cobblemonResource
|
||||
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
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BehaviourConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BehaviourConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BehaviourConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<ResourceLocation, Class<out BehaviourConfig>>(
|
||||
cobblemonResource("script") to ScriptBehaviourConfig::class.java,
|
||||
cobblemonResource("custom_script") to CustomScriptBehaviourConfig::class.java,
|
||||
cobblemonResource("add_tasks_to_activity") to AddTasksToActivity::class.java,
|
||||
cobblemonResource("apply_behaviours") to ApplyBehaviours::class.java,
|
||||
cobblemonResource("set_default_activity") to SetDefaultActivity::class.java,
|
||||
cobblemonResource("set_core_activities") to SetCoreActivities::class.java,
|
||||
cobblemonResource("add_variables") to AddVariablesConfig::class.java,
|
||||
cobblemonResource("set_variables") to SetVariablesConfig::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 getVariables(entity: LivingEntity): List<MoLangConfigVariable>
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BrainConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BrainConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BrainConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out BrainConfig>>(
|
||||
"script" to ScriptBrainConfig::class.java,
|
||||
"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
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// fun encode(buffer: RegistryFriendlyByteBuf)
|
||||
// fun decode(buffer: RegistryFriendlyByteBuf)
|
||||
fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
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.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CustomScriptBehaviourConfig : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val variables: List<MoLangConfigVariable> = emptyList()
|
||||
val script: ExpressionLike = "0".asExpressionLike()
|
||||
|
||||
companion object {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
}
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
runtime.resolve(script)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +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.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object DummyBrainConfig : BrainConfig {
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
# Brain Configuration
|
||||
# Behaviour Configuration
|
||||
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside of 'activities',
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside 'activities',
|
||||
and in some cases a schedule which determines which activities will occur during different times of the day. There is
|
||||
also a set of core activities, and a default activity. In Minecraft, the most complex usage of the Brain AI system
|
||||
is on villagers which have schedules that control their behaviour during the day and night as well as child villager play behaviours.
|
||||
|
||||
Cobblemon's NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Brain Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way.
|
||||
Cobblemon's Pokémon and NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Behaviour Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way, as well as to support the configuration of
|
||||
other logical properties of entities that are configured at the same initialization step.
|
||||
|
||||
By default, without any brain configuration, the default activity will be `minecraft:idle` and the core activities will be `[minecraft:core]`.
|
||||
The activities would not have any tasks though.
|
||||
@@ -48,18 +49,18 @@ The activities that were added by Cobblemon are:
|
||||
- `cobblemon:action_effect`: For when the entity is performing an action effect. Usually registered as an almost empty activity that simply prevents the entity from doing other things.
|
||||
- `cobblemon:npc_chatting`: Intended for NPC entities using dialogue so that they look at their chat partner and do nothing else.
|
||||
|
||||
## Brain Configuration Format
|
||||
A brain is configured using a series of "Brain Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring a brain. Many different types are available.
|
||||
## Behaviour Configuration Format
|
||||
A Behaviour is configured using a series of "Behaviour Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring an entity. Many different types are available.
|
||||
|
||||
### script
|
||||
The `script` type executes a MoLang script which will apply some changes to the brain.
|
||||
The `script` type executes a MoLang script which will apply some changes to the entity or brain.
|
||||
- `script`: The MoLang script to execute. This will be a resource location for the `molang` datapack folder. Something like `cobblemon:some_script`.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the script should be executed. Defaults to `"true"`.
|
||||
|
||||
### add_tasks_to_activity
|
||||
The 'add_tasks_to_activity' type adds a list of tasks to an activity.
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a brain configuration cannot
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a behaviour configuration cannot
|
||||
create new activities.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the tasks should be added. If this
|
||||
is not present, the tasks will always be added.
|
||||
@@ -96,24 +97,107 @@ The `set_core_activities` type sets the core activities of the brain. It has onl
|
||||
### set_default_activity
|
||||
The `set_default_activity` type sets the default activity of the brain. It has only one property, `activity`, which is the activity to set as the default.
|
||||
|
||||
### apply_preset
|
||||
The `apply_preset` type applies a preset to the brain. Brain presets are JSON arrays under the `brain_presets` datapack folder.
|
||||
This is a way to apply a set of configurations to the brain.
|
||||
- `preset`: The name of the preset to apply. This is the name of the file in the `brain_presets` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the preset should be applied. Defaults to `"true"`.
|
||||
### apply_behaviours
|
||||
The `apply_behaviours` type applies some number of other Behaviours to the entity. These behaviours are JSONs under the `behaviours` datapack folder.
|
||||
This is a way to apply a set of configurations to the entity.
|
||||
- `behaviours`: A list of behaviour resource locations to apply. This is the name of the file in the `behaviours` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the behaviour should be applied. Defaults to `"true"`.
|
||||
- `visible`: Whether the behaviour should be visible in the UI. Defaults to `true`. If it is not visible, name and description can be left out.
|
||||
- `name`: The name of the behaviour. This is used in the UI to label the behaviour. This can be a translation key.
|
||||
- `description`: A description of the behaviour. This is used in the UI to describe what the behaviour does. This can be a translation key.
|
||||
- `entityType`: The entity type that the behaviour applies to. Defaults to null. This is used to determine if the behaviour should be applied to the entity type..
|
||||
|
||||
Example brain preset (`uses_healing_machine.json`):
|
||||
Example behaviour (`uses_healing_machine.json`):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
{
|
||||
"name": "cobblemon.behaviour.uses_healing_machine.name",
|
||||
"description": "cobblemon.behaviour.uses_healing_machine.desc",
|
||||
"entityType": "cobblemon:npc",
|
||||
"visible": true,
|
||||
"configurations": [
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 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"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### script
|
||||
The `script` type executes a registered MoLang script which will apply some changes to the brain or entity. This can be
|
||||
useful if the goal is to apply some kind of configuration to the entity that would otherwise be performed by an NPC preset
|
||||
or NPC class. `q.entity` will refer to the entity. This is powerful when combined with [add_variables](#add_variables)
|
||||
configs in the same behaviour preset.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "script",
|
||||
"script": "cobblemon:configure_npc_party"
|
||||
}
|
||||
```
|
||||
|
||||
### custom_script
|
||||
The `custom_script` type executes a custom MoLang script from this config which will apply some changes to the brain or
|
||||
entity. This is useful for when you want to apply some kind of configuration to the entity that would otherwise be
|
||||
by an NPC preset or NPC class. `q.entity` will refer to the entity.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "custom_script",
|
||||
"script": "q.entity.set_pathfinding_malus('WATER', -1);"
|
||||
}
|
||||
```
|
||||
+15
-11
@@ -13,12 +13,13 @@ import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.ai.ActivityConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -30,13 +31,16 @@ import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class ScriptBrainConfig : BrainConfig {
|
||||
class ScriptBehaviourConfig : BehaviourConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val script = cobblemonResource("dummy")
|
||||
val variables = mutableListOf<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BrainConfigurationContext) {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
|
||||
val struct = createBrainStruct(entity, context)
|
||||
@@ -48,30 +52,30 @@ class ScriptBrainConfig : BrainConfig {
|
||||
runtime.resolve(script, mapOf("brain" to struct))
|
||||
}
|
||||
|
||||
fun createBrainStruct(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): QueryStruct {
|
||||
fun createBrainStruct(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): QueryStruct {
|
||||
return QueryStruct(hashMapOf()).addStandardFunctions()
|
||||
.addFunction("entity") { (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()) }
|
||||
.addFunction("entity") { entity.asMostSpecificMoLangValue() }
|
||||
.addFunction("create_activity") { params ->
|
||||
val name = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val activity = entity.level().activityRegistry.get(name) ?: return@addFunction run {
|
||||
Cobblemon.LOGGER.error("Tried loading activity $name as part of an entity brain but that activity does not exist")
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
val existingActivityBuilder = brainConfigurationContext.activities.find { it.activity == activity }
|
||||
val existingActivityBuilder = behaviourConfigurationContext.activities.find { it.activity == activity }
|
||||
if (existingActivityBuilder != null) {
|
||||
return@addFunction createActivityStruct(existingActivityBuilder)
|
||||
} else {
|
||||
val activityConfigurationContext = ActivityConfigurationContext(activity)
|
||||
brainConfigurationContext.activities.add(activityConfigurationContext)
|
||||
behaviourConfigurationContext.activities.add(activityConfigurationContext)
|
||||
return@addFunction createActivityStruct(activityConfigurationContext)
|
||||
}
|
||||
}
|
||||
.addFunction("set_core_activities") { params ->
|
||||
brainConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
behaviourConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
.addFunction("set_default_activity") { params ->
|
||||
brainConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
behaviourConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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 {
|
||||
class SetCoreActivities : BehaviourConfig {
|
||||
val activities = mutableListOf<Activity>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.coreActivities = activities.toSet()
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.coreActivities = activities.toSet()
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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 {
|
||||
class SetDefaultActivity : BehaviourConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.defaultActivity = activity
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.defaultActivity = activity
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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 : BehaviourConfig {
|
||||
var variableValues = mutableMapOf<String, ExpressionLike>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
variableValues.forEach { (variableName, valueExpression) ->
|
||||
entity.config.setDirectly(variableName, runtime.resolve(valueExpression))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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.resolveFloat
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
|
||||
|
||||
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 = runtime.resolveFloat(wanderChanceExpression)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-10
@@ -8,25 +8,34 @@
|
||||
|
||||
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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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 = "true".asExpressionLike()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -8,24 +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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
|
||||
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 AttackAngryAtTaskConfig : SingleTaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "should_attack_angry_at", true).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return AttackAngryAtTask.create()
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -8,24 +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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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 = "true".asExpression()
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return VillagerCalmDown.create()
|
||||
}
|
||||
}
|
||||
+13
-14
@@ -8,30 +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.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return DoNothing(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return DoNothing(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt())
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
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.EatGrassTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class EatGrassTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val EATING_GRASS = "eating_grass"
|
||||
const val COOLDOWN = "eating_grass_cooldown_ticks"
|
||||
const val EAT_GRASS_CHANCE = "eat_grass_chance"
|
||||
}
|
||||
|
||||
val cooldown = numberVariable(category = EATING_GRASS, name = COOLDOWN, default = 20 * 20).asExpressible()
|
||||
val eatGrassChance = numberVariable(category = EATING_GRASS, name = EAT_GRASS_CHANCE, default = 1 / (20 * 20F)).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(
|
||||
cooldown,
|
||||
eatGrassChance
|
||||
).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
val chance = eatGrassChance.resolveFloat()
|
||||
if (chance == 0F) {
|
||||
return null
|
||||
}
|
||||
|
||||
return WrapperLivingEntityTask(
|
||||
EatGrassTask(
|
||||
chance,
|
||||
cooldown.resolveInt().toLong()
|
||||
),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+21
-14
@@ -8,14 +8,13 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -24,15 +23,21 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var includePassiveDamage = true
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val includePassiveDamage = includePassiveDamage.resolveBoolean()
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
if (entity is NPCEntity) {
|
||||
fun cancelNPCBattles(npcEntity: NPCEntity): Boolean {
|
||||
@@ -52,7 +57,7 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelNPCBattles(entity as NPCEntity) } }
|
||||
}
|
||||
}
|
||||
} else { return null }/* else if (entity is PokemonEntity) { TODO uncomment when pokemon have brain :)
|
||||
} else if (entity is PokemonEntity) {
|
||||
fun cancelPokemonBattle(pokemonEntity: PokemonEntity): Boolean {
|
||||
val battle = BattleRegistry.getBattle(pokemonEntity.battleId ?: return false)
|
||||
battle?.end()
|
||||
@@ -61,15 +66,17 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
|
||||
return if (includePassiveDamage) {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.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_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
|
||||
}
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import com.cobblemon.mod.common.util.getIsSubmerged
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.Mth
|
||||
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.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.level.LevelReader
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Moves to the nearest surface it can find so it can breathe.
|
||||
*/
|
||||
class FindAirTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.getIsSubmerged()) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 4.0),
|
||||
entity.blockY - 1,
|
||||
Mth.floor(entity.z - 4.0),
|
||||
Mth.floor(entity.x + 4.0),
|
||||
Mth.floor(entity.y + 8.0),
|
||||
Mth.floor(entity.z + 4.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 20L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) { isAirPos(entity.level(), it) }
|
||||
?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 0))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAirPos(world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
val aboveState = world.getBlockState(pos.above())
|
||||
val notFluid = world.getFluidState(pos.above()).isEmpty || blockState.`is`(Blocks.BUBBLE_COLUMN)
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
val solidBelow = !blockState.isPathfindable(PathComputationType.LAND)
|
||||
|
||||
return notFluid && canPathfindThroughAbove && solidBelow
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(
|
||||
FindRestingPlaceTask.create(horizontalSearchDistance.resolveInt(), verticalSearchDistance.resolveInt()),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+19
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
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.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.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,24 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeAttackerTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
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)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+15
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
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.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.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,20 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeNearestHostileTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
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)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.NEAREST_HOSTILE, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+13
-15
@@ -8,32 +8,30 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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: ExpressionLike = "true".asExpressionLike()
|
||||
val minRunTicks: Expression = "150".asExpression()
|
||||
val maxRunTicks: Expression = "250".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minRunTicks: ExpressionOrEntityVariable = Either.left("150".asExpression())
|
||||
val maxRunTicks: ExpressionOrEntityVariable = Either.left("250".asExpression())
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
override fun getVariables(entity: LivingEntity) = listOf(minRunTicks, maxRunTicks).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return WrapperLivingEntityTask(
|
||||
FollowWalkTargetTask(runtime.resolveInt(minRunTicks), runtime.resolveInt(maxRunTicks)),
|
||||
FollowWalkTargetTask(minRunTicks.resolveInt(), maxRunTicks.resolveInt()),
|
||||
PathfinderMob::class.java
|
||||
)
|
||||
}
|
||||
|
||||
+14
-10
@@ -8,26 +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.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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 {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return GetAngryAtAttackerTask.create()
|
||||
}
|
||||
}
|
||||
+26
-21
@@ -8,38 +8,43 @@
|
||||
|
||||
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.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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(
|
||||
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 {
|
||||
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"
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return GoToHealingMachineTask.create(
|
||||
horizontalSearchRange = horizontalSearchRange,
|
||||
verticalSearchRange = verticalSearchRange,
|
||||
speedMultiplier = speedMultiplier,
|
||||
completionRange = completionRange
|
||||
horizontalSearchRange = horizontalSearchRange.asExpression(),
|
||||
verticalSearchRange = verticalSearchRange.asExpression(),
|
||||
speedMultiplier = walkSpeed.asExpression(),
|
||||
completionRange = completionRange.asExpression()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.Mth
|
||||
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.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.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Seeks land if it's underwater.
|
||||
*/
|
||||
class GoToLandTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.isInLiquid) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
entity as PathfinderMob
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 8.0),
|
||||
entity.blockY,
|
||||
Mth.floor(entity.z - 8.0),
|
||||
Mth.floor(entity.x + 8.0),
|
||||
Mth.floor(entity.y + 2.0),
|
||||
Mth.floor(entity.z + 8.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 40L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) {
|
||||
isSafeLandPosAround(entity.level() as ServerLevel, it, entity)
|
||||
} ?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 1))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPos(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
|
||||
val isFluid = world.getFluidState(pos.above()).isEmpty.not()
|
||||
val solidBelow = blockState.isSolid
|
||||
|
||||
if (isFluid || !solidBelow) {
|
||||
return false
|
||||
} else {
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
val minY = pos.y + 1
|
||||
val maxY = minY + ceil(mob.bbHeight).toInt()
|
||||
for (y in minY..maxY) {
|
||||
val aboveState = world.getBlockState(mutable.set(pos.x, y, pos.z))
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
if (!canPathfindThroughAbove) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPosAround(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val minX = pos.x
|
||||
val maxX = minX + floor(mob.bbWidth).toInt()
|
||||
val minZ = pos.z
|
||||
val maxZ = minZ + floor(mob.bbWidth).toInt()
|
||||
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
for (x in minX..maxX) {
|
||||
for (z in minZ..maxZ) {
|
||||
if (!isSafeLandPos(world, mutable.set(x, pos.y, z), mob)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+16
-13
@@ -8,29 +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.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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: ExpressionLike = "true".asExpressionLike()
|
||||
val horizontalUseRange = "3".asExpression()
|
||||
val verticalUseRange = "2".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange, verticalUseRange)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange.asExpression(), verticalUseRange.asExpression())
|
||||
}
|
||||
}
|
||||
+23
-11
@@ -8,29 +8,41 @@
|
||||
|
||||
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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.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 {
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!resolveBooleanVariable(LOOK_AT_BATTLING_POKEMON)) return null
|
||||
return LookAtBattlingPokemonTask.create(
|
||||
minDurationTicks = runtime.resolveInt(minDurationTicks),
|
||||
maxDurationTicks = runtime.resolveInt(maxDurationTicks)
|
||||
minDurationTicks = minDurationTicks.resolveInt(),
|
||||
maxDurationTicks = maxDurationTicks.resolveInt()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
+19
-14
@@ -8,29 +8,34 @@
|
||||
|
||||
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.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.api.ai.BehaviourConfigurationContext
|
||||
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.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 {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val maxDistance = "15".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return SetEntityLookTarget.create(runtime.resolveFloat(maxDistance))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return SetEntityLookTarget.create(maxDistance.resolveFloat())
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookAtSpeakerTask.create()
|
||||
}
|
||||
+18
-15
@@ -8,33 +8,36 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks: Expression = "40".asExpression()
|
||||
val maxDurationTicks: Expression = "80".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
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)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return WrapperLivingEntityTask(LookAtTargetSink(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt()), Mob::class.java)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
return WrapperLivingEntityTask(LookAtTargetedBattlePokemonTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -8,18 +8,29 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
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 yaw: Expression = "0".asExpression()
|
||||
var pitch: Expression = "0".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
) = LookInDirectionTask(yaw, pitch)
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookInDirectionTask(
|
||||
shouldLock = condition.asExpression(),
|
||||
yaw = yaw.asExpression(),
|
||||
pitch = pitch.asExpression()
|
||||
)
|
||||
}
|
||||
+17
-14
@@ -8,32 +8,35 @@
|
||||
|
||||
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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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 = "true".asExpressionLike()
|
||||
val range = "1.5".asExpression()
|
||||
val cooldownTicks = "30".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return MeleeAttackTask.create(
|
||||
range = range,
|
||||
cooldownTicks = cooldownTicks
|
||||
range = range.asExpression(),
|
||||
cooldownTicks = cooldownTicks.asExpression()
|
||||
)
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -8,20 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
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 = "0.5".asExpression()
|
||||
val closeEnoughDistance = "1".asExpression()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = MoveToAttackTargetTask.create(
|
||||
speedMultiplier = speedMultiplier,
|
||||
closeEnoughDistance = closeEnoughDistance
|
||||
speedMultiplier = speedMultiplier.asExpression(),
|
||||
closeEnoughDistance = closeEnoughDistance.asExpression()
|
||||
)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): 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
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.toDF
|
||||
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.DoNothing
|
||||
import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
|
||||
/**
|
||||
@@ -34,15 +32,17 @@ import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
class OneOfTaskConfig : SingleTaskConfig {
|
||||
class OneOfTaskOption {
|
||||
val weight: Int = 1
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val options = mutableListOf<OneOfTaskOption>()
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
override fun getVariables(entity: LivingEntity) = options.flatMap { it.task.getVariables(entity) }
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return RunOne(options.map { it.task.createTasks(entity, brainConfigurationContext).first() toDF it.weight })
|
||||
return RunOne(options.map { it.task.createTasks(entity, behaviourConfigurationContext).first() toDF it.weight })
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
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.phys.Vec3
|
||||
|
||||
class PointToSpawnTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { lookTargetMemory, _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
val lookTarget = entity.brain.getMemory(MemoryModuleType.LOOK_TARGET).orElse(null)
|
||||
if (lookTarget == null) {
|
||||
lookTargetMemory.set(BlockPosTracker(Vec3.atCenterOf(entity.level().sharedSpawnPos).with(Direction.Axis.Y, entity.eyeY)))
|
||||
return@Trigger true
|
||||
} else {
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,4 +183,17 @@ the script to avoid lagging the game.
|
||||
### look_in_direction
|
||||
The 'look_in_direction' type creates a task that will make the entity look in a specific direction at all times where they aren't being told to look elsewhere.
|
||||
- `yaw`: A MoLang expression that determines the yaw angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
|
||||
### move_to_owner
|
||||
The 'move_to_owner' type creates a task that will make the entity move to its owner. This will only work for entities that
|
||||
can be owned, like Pokémon.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick.
|
||||
- `completionRange`: A MoLang expression that determines the distance from the owner that the entity needs to be for the path to be considered complete. Defaults to 4.
|
||||
- `speedMultiplier`: A MoLang expression that determines the speed multiplier for moving to the owner. Defaults to 0.4 which is slightly above the normal walk speed.
|
||||
- `teleportDistance`: A MoLang expression that determines the distance from the owner the entity must be before it resorts to teleporting. A value of -1 will cause it to never teleport. Defaults to 24.
|
||||
- `maxDistance`: A MoLang expression that determines the maximum distance from the owner that the entity can be to move to them. Defaults to 14.
|
||||
|
||||
### point_to_spawn
|
||||
The 'point_to_spawn' type creates a task that will make the entity point to the spawn point of the world whenever they
|
||||
are not moving and are idling. This is basically only here for Nosepass.
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
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.DoNothing
|
||||
|
||||
/**
|
||||
* Randomly chooses one of the possible tasks to add to the brain. This differs from [OneOfTaskConfig] in that
|
||||
@@ -34,19 +32,21 @@ import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
class RandomTaskConfig : TaskConfig {
|
||||
class RandomTaskChoice {
|
||||
val weight = 1.0
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
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)
|
||||
return task.createTasks(entity, behaviourConfigurationContext)
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@
|
||||
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.BehaviourConfigurationContext
|
||||
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.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -31,18 +32,28 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
* @since December 2nd, 2024
|
||||
*/
|
||||
class RunScript : SingleTaskConfig {
|
||||
val script = cobblemonResource("dummy")
|
||||
companion object {
|
||||
const val SCRIPT_CATEGORY = "script"
|
||||
}
|
||||
|
||||
val script = stringVariable(SCRIPT_CATEGORY, "script", "cobblemon:dummy_script").asExpressible()
|
||||
val variables = mutableListOf<MoLangConfigVariable>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(script).asVariables() + variables
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET) // I think I need to have at least something here?
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: entity.asMostSpecificMoLangValue())
|
||||
return@Trigger CobblemonScripts.run(script, runtime) == DoubleValue.ONE
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return@Trigger CobblemonScripts.run(
|
||||
identifier = script.resolveString().asIdentifierDefaultingNamespace(),
|
||||
runtime = runtime
|
||||
) == DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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"
|
||||
}
|
||||
+22
-8
@@ -8,17 +8,31 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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
|
||||
|
||||
fun interface SingleTaskConfig : TaskConfig {
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
return createTask(entity, brainConfigurationContext)?.let { listOf(it) } ?: emptyList()
|
||||
interface SingleTaskConfig : TaskConfig {
|
||||
companion object {
|
||||
fun nothing() = object : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return DoNothing(0, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>?
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
return createTask(entity, behaviourConfigurationContext)?.let { listOf(it) } ?: emptyList()
|
||||
}
|
||||
|
||||
fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>?
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.TamableAnimal
|
||||
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
|
||||
|
||||
class SleepIfOnTrainerBedTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> = emptyList()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.POKEMON_SLEEPING)
|
||||
).apply(it) { walkTarget, pokemonSleeping ->
|
||||
Trigger { world, entity, _ ->
|
||||
if (entity !is TamableAnimal) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val owner = entity.owner ?: return@Trigger false
|
||||
// If it's no longer moving and is generally within range, cancel any outstanding movement targeting and sleep.
|
||||
if (!entity.moveControl.hasWanted() && owner.distanceTo(entity) < 1.5 && owner.isSleeping && entity.blockStateOn.`is`(BlockTags.BEDS)) {
|
||||
pokemonSleeping.set(true)
|
||||
walkTarget.erase()
|
||||
entity.onPathfindingDone()
|
||||
return@Trigger true
|
||||
}
|
||||
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-16
@@ -8,31 +8,30 @@
|
||||
|
||||
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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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: ExpressionLike = "true".asExpressionLike()
|
||||
val chance: Expression = "0.01".asExpression()
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
val chance = runtime.resolveFloat(chance)
|
||||
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()
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return WrapperLivingEntityTask(
|
||||
StayAfloatTask(chance),
|
||||
StayAfloatTask(chance.resolveFloat()),
|
||||
PathfinderMob::class.java
|
||||
)
|
||||
}
|
||||
|
||||
+9
-10
@@ -8,26 +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.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.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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: ExpressionLike = "true".asExpressionLike()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "stop_being_angry_if_attacker_dead", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return StopBeingAngryIfTargetDead.create()
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -9,15 +9,17 @@
|
||||
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.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(CobblemonMemories.ACTIVE_ACTION_EFFECT)
|
||||
|
||||
+4
-2
@@ -9,15 +9,17 @@
|
||||
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.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(CobblemonMemories.DIALOGUES)
|
||||
|
||||
+4
-2
@@ -8,16 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.ATTACK_TARGET)
|
||||
|
||||
+4
-2
@@ -9,16 +9,18 @@
|
||||
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.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(it.absent(CobblemonMemories.NPC_BATTLING)).apply(it) { _ ->
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
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 SwitchFromSleepOnTrainerBedTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
// Why'd you give them this task then, dipshit?
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(CobblemonMemories.POKEMON_SLEEPING)
|
||||
).apply(it) { pokemonSleeping ->
|
||||
Trigger { world, entity, _ ->
|
||||
entity as PokemonEntity
|
||||
|
||||
// If they're owner is gone then we can consider that a reason to wake up, dogs do this too
|
||||
val owner = entity.owner
|
||||
|
||||
val isCurrentlySleeping = entity.brain.getMemory(CobblemonMemories.POKEMON_SLEEPING).orElse(false)
|
||||
// If we should move back to regular behaviours...
|
||||
if (owner == null || !owner.isSleeping) {
|
||||
// If it's willingly sleeping then it can lose the sleeping memory
|
||||
if (isCurrentlySleeping && entity.pokemon.status?.status != Statuses.SLEEP) {
|
||||
pokemonSleeping.erase()
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
// Go back to your usual behaviours
|
||||
entity.brain.useDefaultActivity()
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+4
-2
@@ -10,16 +10,18 @@ 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.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
|
||||
+4
-2
@@ -10,16 +10,18 @@ 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.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(CobblemonMemories.DIALOGUES),
|
||||
|
||||
+9
-10
@@ -8,11 +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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.Difficulty
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -22,20 +20,21 @@ 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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.present(MemoryModuleType.ATTACK_TARGET)
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
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
|
||||
if (entity.commandSenderWorld.getCurrentDifficultyAt(entity.blockPosition()).difficulty == Difficulty.PEACEFUL) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
entity.brain.setActiveActivityIfPossible(activity)
|
||||
return@Trigger true
|
||||
|
||||
+4
-2
@@ -8,14 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> = SwitchToBattleTask.create()
|
||||
}
|
||||
+21
-12
@@ -8,28 +8,37 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
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.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 = "true".asExpression()
|
||||
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "panic_when_hostiles_nearby", true).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
) = 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
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-11
@@ -8,11 +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.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -23,16 +21,21 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class SwitchToPanicWhenHurtTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var includePassiveDamage = false
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return if (includePassiveDamage) {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return if (includePassiveDamage.resolveBoolean()) {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY))
|
||||
.apply(it) { _ ->
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
return SwitchToBattleTask.createForPokemon()
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
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
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.block.BedBlock
|
||||
|
||||
class SwitchToSleepOnTrainerBedTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (entity.pokemon.isWild()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(CobblemonMemories.POKEMON_BATTLE),
|
||||
it.absent(CobblemonMemories.POKEMON_SLEEPING),
|
||||
it.registered(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { _, _, walkTarget ->
|
||||
Trigger { world, entity, _ ->
|
||||
entity as PokemonEntity
|
||||
val owner = entity.owner ?: return@Trigger false
|
||||
if (!owner.isSleeping || owner.distanceTo(entity) > 12) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val blockPos = owner.blockPosition()
|
||||
val blockState = entity.level().getBlockState(blockPos)
|
||||
val bedPos = blockState.getOptionalValue(BedBlock.FACING).orElse(null)
|
||||
?.let { direction -> blockPos.relative(direction.opposite) }
|
||||
?: BlockPos(blockPos)
|
||||
|
||||
walkTarget.set(WalkTarget(bedPos.center, 0.35F, 0))
|
||||
entity.brain.setActiveActivityIfPossible(CobblemonActivities.POKEMON_SLEEP_ON_TRAINER_BED)
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.ast.NumberExpression
|
||||
import com.bedrockk.molang.ast.StringExpression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
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.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
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.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
@@ -23,51 +42,116 @@ import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
* @author Hiroku
|
||||
* @since October 14th, 2024
|
||||
*/
|
||||
fun interface TaskConfig {
|
||||
interface TaskConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out TaskConfig>>(
|
||||
"one_of" to OneOfTaskConfig::class.java,
|
||||
"wander" to WanderTaskConfig::class.java,
|
||||
"look_at_target" to LookAtTargetTaskConfig::class.java,
|
||||
"follow_walk_target" to FollowWalkTargetTaskConfig::class.java,
|
||||
"random" to RandomTaskConfig::class.java,
|
||||
"stay_afloat" to StayAfloatTaskConfig::class.java,
|
||||
"look_at_entities" to LookAtEntitiesTaskConfig::class.java,
|
||||
"do_nothing" to DoNothingTaskConfig::class.java,
|
||||
"get_angry_at_attacker" to GetAngryAtAttackerTaskConfig::class.java,
|
||||
"stop_being_angry_if_attacker_dead" to StopBeingAngryIfAttackerDeadTaskConfig::class.java,
|
||||
"switch_npc_to_battle" to SwitchToNPCBattleTaskConfig::class.java,
|
||||
"look_at_battling_pokemon" to LookAtBattlingPokemonTaskConfig::class.java,
|
||||
"switch_npc_from_battle" to SwitchFromNPCBattleTaskConfig::class.java,
|
||||
"go_to_healing_machine" to GoToHealingMachineTaskConfig::class.java,
|
||||
"heal_using_healing_machine" to HealUsingHealingMachineTaskConfig::class.java,
|
||||
"all_of" to AllOfTaskConfig::class.java,
|
||||
"attack_angry_at" to AttackAngryAtTaskConfig::class.java,
|
||||
"move_to_attack_target" to MoveToAttackTargetTaskConfig::class.java,
|
||||
"melee_attack" to MeleeAttackTaskConfig::class.java,
|
||||
"switch_from_fight" to SwitchFromFightTaskConfig::class.java,
|
||||
"switch_to_fight" to SwitchToFightTaskConfig::class.java,
|
||||
"switch_to_chatting" to SwitchToChattingTaskConfig::class.java,
|
||||
"switch_from_chatting" to SwitchFromChattingTaskConfig::class.java,
|
||||
"look_at_speaker" to LookAtSpeakerTaskConfig::class.java,
|
||||
"switch_to_action_effect" to SwitchToActionEffectTaskConfig::class.java,
|
||||
"switch_from_action_effect" to SwitchFromActionEffectTaskConfig::class.java,
|
||||
"exit_battle_when_hurt" to ExitBattleWhenHurtTaskConfig::class.java,
|
||||
"switch_to_panic_when_hurt" to SwitchToPanicWhenHurtTaskConfig::class.java,
|
||||
"switch_to_panic_when_hostiles_nearby" to SwitchToPanicWhenHostilesNearbyTaskConfig::class.java,
|
||||
"calm_down" to CalmDownTaskConfig::class.java,
|
||||
"flee_attacker" to FleeAttackerTaskConfig::class.java,
|
||||
"flee_nearest_hostile" to FleeNearestHostileTaskConfig::class.java,
|
||||
"run_script" to RunScript::class.java,
|
||||
"look_in_direction" to LookInDirectionTaskConfig::class.java,
|
||||
val types = mutableMapOf<ResourceLocation, Class<out TaskConfig>>(
|
||||
cobblemonResource("one_of") to OneOfTaskConfig::class.java,
|
||||
cobblemonResource("wander") to WanderTaskConfig::class.java,
|
||||
cobblemonResource("water_wander") to WaterWanderTaskConfig::class.java,
|
||||
cobblemonResource("air_wander") to AirWanderTaskConfig::class.java,
|
||||
cobblemonResource("look_at_target") to LookAtTargetTaskConfig::class.java,
|
||||
cobblemonResource("follow_walk_target") to FollowWalkTargetTaskConfig::class.java,
|
||||
cobblemonResource("random") to RandomTaskConfig::class.java,
|
||||
cobblemonResource("stay_afloat") to StayAfloatTaskConfig::class.java,
|
||||
cobblemonResource("look_at_entities") to LookAtEntitiesTaskConfig::class.java,
|
||||
cobblemonResource("do_nothing") to DoNothingTaskConfig::class.java,
|
||||
cobblemonResource("get_angry_at_attacker") to GetAngryAtAttackerTaskConfig::class.java,
|
||||
cobblemonResource("stop_being_angry_if_attacker_dead") to StopBeingAngryIfAttackerDeadTaskConfig::class.java,
|
||||
cobblemonResource("switch_npc_to_battle") to SwitchToNPCBattleTaskConfig::class.java,
|
||||
cobblemonResource("look_at_battling_pokemon") to LookAtBattlingPokemonTaskConfig::class.java,
|
||||
cobblemonResource("switch_npc_from_battle") to SwitchFromNPCBattleTaskConfig::class.java,
|
||||
cobblemonResource("switch_pokemon_to_battle") to SwitchToPokemonBattleTaskConfig::class.java,
|
||||
cobblemonResource("look_at_targeted_battle_pokemon") to LookAtTargetedBattlePokemonTaskConfig::class.java,
|
||||
cobblemonResource("switch_pokemon_from_battle") to SwitchFromPokemonBattleTaskConfig::class.java,
|
||||
cobblemonResource("go_to_healing_machine") to GoToHealingMachineTaskConfig::class.java,
|
||||
cobblemonResource("heal_using_healing_machine") to HealUsingHealingMachineTaskConfig::class.java,
|
||||
cobblemonResource("all_of") to AllOfTaskConfig::class.java,
|
||||
cobblemonResource("attack_angry_at") to AttackAngryAtTaskConfig::class.java,
|
||||
cobblemonResource("move_to_attack_target") to MoveToAttackTargetTaskConfig::class.java,
|
||||
cobblemonResource("melee_attack") to MeleeAttackTaskConfig::class.java,
|
||||
cobblemonResource("switch_from_fight") to SwitchFromFightTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_fight") to SwitchToFightTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_chatting") to SwitchToChattingTaskConfig::class.java,
|
||||
cobblemonResource("switch_from_chatting") to SwitchFromChattingTaskConfig::class.java,
|
||||
cobblemonResource("look_at_speaker") to LookAtSpeakerTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_action_effect") to SwitchToActionEffectTaskConfig::class.java,
|
||||
cobblemonResource("switch_from_action_effect") to SwitchFromActionEffectTaskConfig::class.java,
|
||||
cobblemonResource("exit_battle_when_hurt") to ExitBattleWhenHurtTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_panic_when_hurt") to SwitchToPanicWhenHurtTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_panic_when_hostiles_nearby") to SwitchToPanicWhenHostilesNearbyTaskConfig::class.java,
|
||||
cobblemonResource("calm_down") to CalmDownTaskConfig::class.java,
|
||||
cobblemonResource("flee_attacker") to FleeAttackerTaskConfig::class.java,
|
||||
cobblemonResource("flee_nearest_hostile") to FleeNearestHostileTaskConfig::class.java,
|
||||
cobblemonResource("run_script") to RunScript::class.java,
|
||||
cobblemonResource("look_in_direction") to LookInDirectionTaskConfig::class.java,
|
||||
cobblemonResource("wake_up") to WakeUpTaskConfig::class.java,
|
||||
cobblemonResource("go_to_sleep") to GoToSleepTaskConfig::class.java,
|
||||
cobblemonResource("find_resting_place") to FindRestingPlaceTaskConfig::class.java,
|
||||
cobblemonResource("move_to_owner") to MoveToOwnerTaskConfig::class.java,
|
||||
cobblemonResource("switch_to_sleep_on_trainer_bed") to SwitchToSleepOnTrainerBedTaskConfig::class.java,
|
||||
cobblemonResource("switch_from_sleep_on_trainer_bed") to SwitchFromSleepOnTrainerBedTaskConfig::class.java,
|
||||
cobblemonResource("sleep_if_on_trainer_bed") to SleepIfOnTrainerBedTaskConfig::class.java,
|
||||
cobblemonResource("point_to_spawn") to PointToSpawnTaskConfig::class.java,
|
||||
cobblemonResource("eat_grass") to EatGrassTaskConfig::class.java,
|
||||
cobblemonResource("find_air") to FindAirTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java
|
||||
)
|
||||
|
||||
|
||||
val runtime = MoLangRuntime().setup()
|
||||
}
|
||||
|
||||
val runtime: MoLangRuntime
|
||||
get() = Companion.runtime
|
||||
|
||||
fun checkCondition(entity: LivingEntity, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return expressionOrEntityVariable.resolveBoolean()
|
||||
}
|
||||
|
||||
fun ExpressionOrEntityVariable.asSimplifiedExpression(entity: LivingEntity): Expression {
|
||||
return map(
|
||||
{ it },
|
||||
{
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
val variable = entity.config.map[it.variableName]
|
||||
if (variable is DoubleValue) {
|
||||
return@map NumberExpression(variable.value)
|
||||
} else if (variable is StringValue) {
|
||||
return@map StringExpression(variable)
|
||||
}
|
||||
}
|
||||
return@map "q.entity.config.${it.variableName}".asExpression()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
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>>
|
||||
fun createTasks(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<BehaviorControl<in LivingEntity>>
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(WakeUpTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+104
-31
@@ -8,64 +8,137 @@
|
||||
|
||||
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.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.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.CobblemonWalkTarget
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.core.BlockPos
|
||||
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.LandRandomPos
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
|
||||
class WanderTaskConfig : SingleTaskConfig {
|
||||
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()
|
||||
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()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(MemoryModuleType.LOOK_TARGET)
|
||||
).apply(it) { walkTarget, lookTarget ->
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, lookTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob) {
|
||||
if (entity !is PathfinderMob || entity.isUnderWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(shouldWander)) return@Trigger false
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = runtime.resolveFloat(wanderChanceExpression)
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
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)))
|
||||
pathCooldown.setWithExpiry(true, 40L)
|
||||
|
||||
// val targetVec = getLandTarget(entity) ?: return@Trigger true
|
||||
val targetVec = LandRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt()) ?: return@Trigger false
|
||||
val pos = BlockPos.containing(targetVec)
|
||||
walkTarget.set(CobblemonWalkTarget(pos, speedMultiplier.resolveFloat(), 0, { it !in listOf(PathType.WATER, PathType.WATER_BORDER) }))
|
||||
lookTarget.erase()
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is from the old wander goal. It is very verbose but reliably finds decent land wander targets. Its only advantage over
|
||||
* the LandRandomPos method (with our CobblemonWalkTarget) is that it doesn't lead entities in the direction of water.
|
||||
*/
|
||||
// fun getLandTarget(entity: PathfinderMob): Vec3? {
|
||||
// val roamDistanceCondition: (BlockPos) -> Boolean = if (entity is PokemonEntity) ({ entity.tethering?.canRoamTo(it) != false }) else ({ true })
|
||||
// val iterable: Iterable<BlockPos> = BlockPos.randomBetweenClosed(entity.random, 64, entity.blockX - 10, entity.blockY, entity.blockZ - 10, entity.blockX + 10, entity.blockY, entity.blockZ + 10)
|
||||
// val condition: (BlockState, BlockPos) -> Boolean = { _, pos -> entity.canFit(pos) && roamDistanceCondition(pos) }
|
||||
// val iterator = iterable.iterator()
|
||||
// position@
|
||||
// while (iterator.hasNext()) {
|
||||
// val pos = iterator.next().mutable()
|
||||
// var blockState = entity.level().getBlockState(pos)
|
||||
//
|
||||
// val maxSteps = 16
|
||||
// var steps = 0
|
||||
// var good = false
|
||||
// if (!blockState.isSolid && !blockState.liquid()) {
|
||||
// pos.move(0, -1, 0)
|
||||
// var previousWasAir = true
|
||||
// while (steps++ < maxSteps && pos.y > entity.level().minBuildHeight) {
|
||||
// if (pos.y <= entity.level().minBuildHeight) {
|
||||
// continue@position
|
||||
// }
|
||||
// blockState = entity.level().getBlockState(pos)
|
||||
// if (blockState.isSolid && !blockState.`is`(BlockTags.LEAVES) && previousWasAir) {
|
||||
// pos.move(0, 1, 0)
|
||||
// blockState = entity.level().getBlockState(pos)
|
||||
// good = true
|
||||
// break
|
||||
// } else {
|
||||
// previousWasAir = blockState.isAir
|
||||
// }
|
||||
// pos.move(0, -1, 0)
|
||||
// }
|
||||
// } else {
|
||||
// var previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES)
|
||||
// pos.move(0, 1, 0)
|
||||
// while (steps++ < maxSteps) {
|
||||
// if (pos.y >= entity.level().maxBuildHeight) {
|
||||
// continue@position
|
||||
// }
|
||||
// blockState = entity.level().getBlockState(pos)
|
||||
// if (blockState.isAir && previousWasSolid) {
|
||||
// good = true
|
||||
// break
|
||||
// }
|
||||
// previousWasSolid = blockState.isSolid && !blockState.`is`(BlockTags.LEAVES)
|
||||
// pos.move(0, 1, 0)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (good && condition(blockState, pos)) {
|
||||
// return pos.toVec3d()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return null
|
||||
// }
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.BehaviourConfigurationContext
|
||||
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.resolveFloat
|
||||
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,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
|
||||
|
||||
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 = runtime.resolveFloat(wanderChanceExpression)
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.data
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutionException
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -54,17 +54,22 @@ interface JsonDataRegistry<T> : DataRegistry {
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
try {
|
||||
data[resolvedIdentifier] = gson.fromJson(reader, typeToken.type)
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading JSON for data: $identifier", exception)
|
||||
}
|
||||
data[resolvedIdentifier] = parse(reader, resolvedIdentifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reload(data)
|
||||
}
|
||||
|
||||
fun parse(reader: BufferedReader, identifier: ResourceLocation): T {
|
||||
return try {
|
||||
gson.fromJson(reader, typeToken.type)
|
||||
} catch (exception: Exception) {
|
||||
throw ExecutionException("Error loading JSON for data: $identifier", exception)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads this registry from the deserialized data.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* Settings for the gibbering sound effect that plays gradually as dialogue appears.
|
||||
*
|
||||
* @author Hiroku, landonjw
|
||||
* @since April 19th, 2025
|
||||
*/
|
||||
class DialogueGibber(
|
||||
/** Whether text will gradually appear while the gibbering occurs. */
|
||||
val graduallyShowText: Boolean = true,
|
||||
/** Whether clicking will make the gibber skip to the end. */
|
||||
val allowSkip: Boolean = true,
|
||||
/** The space between gibbers in terms of characters. 'Holy cow' would play 2 sounds if step = 4. */
|
||||
val step: Int = 4,
|
||||
/** The time (in seconds) between gibbers. The smaller this is, the faster the text will progress. */
|
||||
val interval: Double = 0.1,
|
||||
val minPitch: Float = 0.9F,
|
||||
val maxPitch: Float = 1.1F,
|
||||
val minVolume: Float = 0.9F,
|
||||
val maxVolume: Float = 1.0F,
|
||||
/** The possible sounds to play when gibbering. */
|
||||
val sounds: List<ResourceLocation> = listOf(
|
||||
cobblemonResource("entity.npc.gibber.generic")
|
||||
)
|
||||
)
|
||||
@@ -31,6 +31,7 @@ class DialoguePage(
|
||||
var lines: MutableList<DialogueText> = mutableListOf(),
|
||||
var input: DialogueInput = DialogueNoInput(),
|
||||
var background: ResourceLocation? = null,
|
||||
var gibber: DialogueGibber? = null,
|
||||
var clientActions: MutableList<Expression> = mutableListOf(),
|
||||
var escapeAction: DialogueAction? = null,
|
||||
) {
|
||||
@@ -42,6 +43,7 @@ class DialoguePage(
|
||||
speaker: String? = null,
|
||||
lines: Iterable<MutableComponent>,
|
||||
input: DialogueInput = DialogueNoInput(),
|
||||
gibber: DialogueGibber? = null,
|
||||
background: ResourceLocation? = null,
|
||||
clientActions: Iterable<Expression> = emptyList(),
|
||||
/** The thing to do when the player presses ESC while on this page. If null, falls back to the same property on [Dialogue]. */
|
||||
@@ -52,6 +54,7 @@ class DialoguePage(
|
||||
speaker = speaker,
|
||||
lines = lines.map { WrappedDialogueText(it) }.toMutableList(),
|
||||
input = input,
|
||||
gibber = gibber,
|
||||
background = background,
|
||||
clientActions = clientActions.toMutableList(),
|
||||
escapeAction = escapeAction?.let { func -> FunctionDialogueAction { activeDialogue, _ -> func(activeDialogue) } }
|
||||
|
||||
@@ -19,7 +19,16 @@ import net.minecraft.network.chat.MutableComponent
|
||||
*/
|
||||
class DialogueSpeaker(
|
||||
val name: DialogueText? = null,
|
||||
val face: DialogueFaceProvider? = null
|
||||
val face: DialogueFaceProvider? = null,
|
||||
val gibber: DialogueGibber? = null
|
||||
) {
|
||||
fun of(name: MutableComponent = "".text(), face: DialogueFaceProvider? = null) = DialogueSpeaker(WrappedDialogueText(name), face)
|
||||
fun of(
|
||||
name: MutableComponent = "".text(),
|
||||
face: DialogueFaceProvider? = null,
|
||||
gibber: DialogueGibber? = null
|
||||
) = DialogueSpeaker(
|
||||
name = WrappedDialogueText(name),
|
||||
face = face,
|
||||
gibber = gibber
|
||||
)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user