Compare commits

..
Author SHA1 Message Date
Landon Wills 0af70a1433 Update tinkaton animation, support changes in fov 2025-04-17 23:27:54 -04:00
Landon Wills 268e7c4afc Merge branch 'refs/heads/main' into camera-test 2025-04-17 06:39:25 -04:00
Landon Wills 070d6f9529 Add ceruledge test animation 2025-04-17 06:38:56 -04:00
Landon Wills 8420dd6fe3 Embed camera into model locator. Much cleaner solution 2025-04-17 05:20:26 -04:00
Landon Wills 24ee96a85d Allow for either provided animation to played 2025-04-17 01:50:48 -04:00
Landon Wills 32ff4ee609 Use tandemaus animation for example 2025-04-17 01:03:42 -04:00
Landon Wills 7a61ce1a94 Make tinkaton use primary animation 2025-04-17 01:02:48 -04:00
Landon Wills 46f43345f2 Things and stuff 2025-04-16 23:18:38 -04:00
Landon Wills ad438bfbcd Merge branch 'refs/heads/main' into stadium-block-gert
# Conflicts:
#	common/src/main/java/com/cobblemon/mod/common/mixin/client/CameraMixin.java
#	common/src/main/kotlin/com/cobblemon/mod/common/CobblemonNetwork.kt
#	common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt
2025-04-16 03:23:04 -04:00
Gertimoshka 5bc056d28e Breaking my head working on this, but steady progress finalizing the camera system itself 2025-04-15 11:54:29 +03:00
Gertimoshka 3033adcc2f IT MOVES 2025-04-05 11:55:07 +03:00
Gertimoshka 252634bfde Setup the code that will handle the camera data and apply it 2025-04-05 08:04:24 +03:00
Gertimoshka 0f38c6b00e Setup Data Handling and Syncing for Stadium Cameras 2025-04-01 15:27:22 +03:00
Gertimoshka f711f748a8 A lot of Stadium Camera Data for the Data Gods before implementation 2025-03-29 10:27:34 +02:00
Gertimoshka c2fb914e08 Working on Networking for Stadium 2025-03-22 23:33:35 +02:00
Gertimoshka 7947e19337 Fixed Errors with Mergin Main into branch 2025-03-21 21:56:49 +02:00
Gertimoshka 5bde172731 Detached the Camera from the player 2025-03-21 21:43:59 +02:00
Gertimoshka 496e04a779 Merging Main into stadium-block-gert 2025-03-21 14:50:22 +02:00
Gertimoshka ff4192b43c Preparing to handle starting Stadium Battles 2025-03-21 14:47:27 +02:00
Gertimoshka 415591a443 Stadium Block now can innitate a 1v1 battle 2025-03-21 14:47:26 +02:00
Gertimoshka efb1eaf3e1 Setup to prepare to develop Stadium Block Functionality 2025-03-21 14:47:26 +02:00
Plastered_CrabandGertimoshka 7ebd2bdb94 Render Rotom drone camera to start orbiting around + try to avoid collisions using raycast point cloud 2025-03-21 14:47:24 +02:00
FlarkinaterandGertimoshka e07579bf0a Fix drone animation 2025-03-21 14:47:23 +02:00
FlarkinaterandGertimoshka 0695117549 Revert debug change 2025-03-21 14:47:22 +02:00
FlarkinaterandGertimoshka d6cd04e2a4 Attempt to debug the animation issue 2025-03-21 14:47:21 +02:00
FlarkinaterandGertimoshka 8240cd10e2 Attempt to make the drone animated (WIP) 2025-03-21 14:47:19 +02:00
FlarkinaterandGertimoshka 2a1e749787 Refactor - move most drone assets into bedrock/drone 2025-03-21 14:47:18 +02:00
FlarkinaterandGertimoshka 6d9daf692d Fix upside-down drone 2025-03-21 14:47:17 +02:00
FlarkinaterandGertimoshka 1f7df20e77 Render the drone in-game 2025-03-21 14:47:16 +02:00
FlarkinaterandGertimoshka 02a4b91778 Add Rotom drone model/texture/animation placeholders 2025-03-21 14:47:15 +02:00
FlarkinaterandGertimoshka a37da4d4f2 Remove placeholder model, we'll just use some "dev art" for now 2025-03-21 14:47:14 +02:00
FlarkinaterandGertimoshka 66817b5e9b Update deprecated methods, imports, and formatting 2025-03-21 14:47:10 +02:00
FlarkinaterandGertimoshka fd54e3a7e0 Rebase old stadium camera test branch 2025-03-21 14:47:08 +02:00
Gertimoshka 79f2b67bf9 Preparing to send client reqired info about Stadium Battle 2025-03-21 14:44:34 +02:00
Gertimoshka 2352dae6e0 Preparing to handle starting Stadium Battles 2025-03-20 18:35:46 +02:00
Gertimoshka 9ec100f9ea Stadium Block now can innitate a 1v1 battle 2025-03-20 12:36:12 +02:00
Gertimoshka 17c524ab9e Setup to prepare to develop Stadium Block Functionality 2025-03-17 22:30:28 +02:00
Plastered_Crab 86d48df9fe Render Rotom drone camera to start orbiting around + try to avoid collisions using raycast point cloud 2025-02-28 16:59:03 -08:00
Flarkinater 3401ba9cbb Fix drone animation 2025-02-15 21:48:29 -05:00
Flarkinater dac9ccb461 Revert debug change 2025-02-15 21:47:59 -05:00
Flarkinater 191a62f693 Attempt to debug the animation issue 2025-02-15 16:50:52 -05:00
Flarkinater d8d410e539 Merge branch 'main' of https://gitlab.com/cable-mc/cobblemon into stadium-block 2025-02-15 15:37:37 -05:00
Flarkinater b7c6e1ea77 Attempt to make the drone animated (WIP) 2025-02-15 15:35:48 -05:00
Flarkinater 186812d6fd Refactor - move most drone assets into bedrock/drone 2025-02-14 12:23:27 -05:00
Flarkinater 1c0bdc766a Fix upside-down drone 2025-02-12 14:55:41 -05:00
Flarkinater c697bcd2e9 Render the drone in-game 2025-02-12 01:17:42 -05:00
Flarkinater 9d6ff01d80 Add Rotom drone model/texture/animation placeholders 2025-02-10 20:20:24 -05:00
Flarkinater 1691853a19 Remove placeholder model, we'll just use some "dev art" for now 2025-02-10 20:20:12 -05:00
Flarkinater 4e9a4e1e5a Update deprecated methods, imports, and formatting 2025-02-10 20:20:03 -05:00
Flarkinater 6450255a0b Rebase old stadium camera test branch 2025-02-10 20:19:13 -05:00
1064 changed files with 28417 additions and 48853 deletions
-11
View File
@@ -1,11 +0,0 @@
### Additions
- Added the Campfire Pot, made from apricorns and placed onto campfires.
- This pot can be used to make bait for fishing, Poké Cakes, Lure Cakes, local specialties, and potions (less efficiently than a brewing stand).
- There is a different pot for each apricorn colour because at this point I think we may have an addiction.
- Added Aprijuice, made from the Campfire Pot using apricorns with seasoning to give flavours.
- Aprijuice can be fed to ride-able Pokémon to improve their riding characteristics, depending on the flavour and the Pokémon's nature.
### Datapack and Addon Changes
- Renamed the fishing_baits datapack folder to spawn_bait_effects.
- Added `seasonings` datapack folder for controlling usable items in the campfire pot and what colour and flavour they apply.
- Added campfire pot recipe type, which you could use to make anything work as fishing bait.
-1
View File
@@ -6,7 +6,6 @@
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
- Added IVs and EVs stat displays in PC.
### Developer
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
+1 -18
View File
@@ -19,8 +19,6 @@
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
- Added lang keys for all moves and abilities up to Generation 9.
- Fixed Moon Ball moon phase logic to actually work correctly
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
### Pokémon Added
@@ -129,11 +127,6 @@
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
- Improved the zoom functionality of the Pokédex Scanner by giving the levels logarithmic scaling.
- Added a subtle rotation effect to the Pokédex Scanner's wheel when zooming.
- 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
### Fixes
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
@@ -163,8 +156,6 @@
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
- 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
### Developer
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
@@ -183,15 +174,7 @@
- Updated NPCEntity pokeball throw positioning to properly account for the baseScale property.
- Fixed `[Pokemon].copyFrom` error causing forms, IVs, and EVs to not be applied properly when using `[Pokemon].loadFromJSON` or `[Pokemon].loadFromNBT`
- Added new item class, `WearableItem`. Instances of this class should have a corresponding 3D model. These models render when the items display context is `HEAD`.
- Pokemon now have a fireImmune attribute in their behaviour that can be set to true to ignore all fire damage (lava, magma blocks, etc.)
`JSON
{
"behaviour": {
"fireImmune": true
}
}
`
### MoLang & Datapacks
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
- The `requiredContext` for an item interaction evolution
+2 -3
View File
@@ -1,9 +1,8 @@
import utilities.isSnapshot
import utilities.version
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import utilities.isSnapshot
import utilities.version
/*
*
@@ -13,12 +13,10 @@ import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokemon.FormData;
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
import dev.lambdaurora.lambdynlights.LambDynLights;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,19 +53,15 @@ public class LambDynamicLightsCompat {
private static int resolvedPokemonLightLevel(PokemonEntity pokemon) {
var underwater = !pokemon.level().getFluidState(BlockPos.containing(pokemon.getX(), pokemon.getEyeY(), pokemon.getZ())).isEmpty();
ItemStack item = pokemon.getShownItem();
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
return Math.max(itemLightLevel, formLightLevel);
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
}
private static int resolvedShoulderLightLevel(Player player) {
final var shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
var underwater = !player.level().getFluidState(BlockPos.containing(player.getX(), player.getEyeY(), player.getZ())).isEmpty();
final int leftLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
final int rightLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
return Math.max(leftLightLevel, rightLightLevel);
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getFirst(), underwater);
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getSecond(), underwater);
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
}
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
@@ -77,16 +71,11 @@ public class LambDynamicLightsCompat {
return Optional.of(form.getLightingData().getLightLevel());
}
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
if (shoulderData == null) {
return 0;
return Optional.empty();
}
ItemStack item = shoulderData.getShownItem();
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
return Math.max(itemLightLevel, formLightLevel);
return extractFormLightLevel(shoulderData.getForm(), underwater);
}
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
@@ -1,62 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.block.SaccharineLeafBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Desc;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Slice;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
public abstract class BeeEntityMixin {
@Unique
private BlockState cobblemon$result = null;
@Inject(method = "tick()V", at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
shift = At.Shift.BY,
by = 2
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
if (block instanceof SaccharineLeafBlock) {
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
if (age < 2) {
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
}
}
}
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
private BlockState applyCustomBlockState(BlockState before) {
if(this.cobblemon$result != null && before == null) {
BlockState result = this.cobblemon$result;
this.cobblemon$result = null;
return result;
}
return before;
}
}
@@ -8,46 +8,19 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.OrientationControllable;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Map;
@Mixin(LocalPlayer.class)
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable {
public abstract class LocalPlayerMixin {
@Shadow
private float jumpRidingScale;
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
super(clientLevel, gameProfile);
}
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
LocalPlayer player = (LocalPlayer) (Object) this;
@@ -61,59 +34,4 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
}
}
}
@Override
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
Seat seat = pokemonEntity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator == null) {
super.pick(hitDistance, partialTicks, hitFluids);
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
OrientationController controller = this.getOrientationController();
float currEyeHeight = this.getEyeHeight();
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
offset.add(cobblemon$getFirstPersonOffset(model, seat));
}
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
return super.pick(hitDistance, partialTicks, hitFluids);
}
@Unique
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, Seat seat) {
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
if (cameraOffsets.containsKey(seat.getLocator())) {
return cameraOffsets.get(seat.getLocator()).toVector3f();
} else {
return new Vector3f(0f, 0f, 0f);
}
}
}
@@ -15,9 +15,12 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
import com.cobblemon.mod.common.api.riding.Seat;
import com.cobblemon.mod.common.api.storage.party.PartyStore;
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
@@ -37,16 +40,18 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix3f;
import org.joml.Vector3f;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -279,4 +284,41 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
public OrientationController getOrientationController() {
return cobblemon$orientationController;
}
@Override
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
Entity vehicle = this.getVehicle();
if (vehicle instanceof PokemonEntity pokemonEntity) {
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
Seat seat = pokemonEntity.getSeats().get(seatIndex);
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator == null) {
super.pick(hitDistance, partialTicks, hitFluids);
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
OrientationController controller = this.getOrientationController();
float currEyeHeight = this.getEyeHeight();
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
Vec3 viewVector = this.getViewVector(partialTicks);
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
return this.level()
.clip(
new ClipContext(
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
)
);
}
return super.pick(hitDistance, partialTicks, hitFluids);
}
}
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import net.minecraft.stats.RecipeBookSettings;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(RecipeBookSettings.class)
public class RecipeBookSettingsMixin {
@Shadow @Final public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
@Inject(method = "<init>", at = @At("TAIL"))
private void cobblemon$init(CallbackInfo ci) {
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
}
}
@@ -1,46 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import net.minecraft.world.inventory.RecipeBookType;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.List;
@Mixin(value = RecipeBookType.class)
public class RecipeBookTypeMixin {
@Final
@Mutable
@Shadow
private static RecipeBookType[] $VALUES; // moj
@Invoker("<init>")
private static RecipeBookType cobblemon$createBookType(String name, int ordinal) {
throw new AssertionError();
}
@Inject(
method = "<clinit>",
at = @At("TAIL")
)
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
types.add(cobblemon$createBookType("COOKING_POT", $VALUES.length));
$VALUES = types.toArray(RecipeBookType[]::new);
}
}
@@ -1,20 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.Camera;
import net.minecraft.world.level.BlockGetter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Camera.class)
public interface CameraAccessor {
@Accessor("level")
BlockGetter getLevel();
}
@@ -1,22 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.StateSwitchingButton;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RecipeBookComponent.class)
public interface RecipeBookComponentAccessor {
@Accessor("filterButton")
StateSwitchingButton getFilterButton();
}
@@ -10,17 +10,26 @@ 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.api.riding.Seat;
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
import com.cobblemon.mod.common.client.render.MatrixWrapper;
import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix3f;
import org.joml.Quaternionf;
@@ -33,51 +42,39 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Map;
@Mixin(Camera.class)
public abstract class CameraMixin {
@Shadow
private Entity entity;
@Shadow
@Final
private Quaternionf rotation;
@Shadow
@Final
private Vector3f forwards;
@Shadow
@Final
private Vector3f up;
@Shadow
@Final
private Vector3f left;
@Shadow
private float xRot;
@Shadow
private float yRot;
@Shadow private Entity entity;
@Shadow @Final private Quaternionf rotation;
@Shadow @Final private Vector3f forwards;
@Shadow @Final private Vector3f up;
@Shadow @Final private Vector3f left;
@Shadow private float xRot;
@Shadow private float yRot;
@Shadow private float eyeHeight;
@Shadow private float eyeHeightOld;
@Shadow protected abstract void setPosition(Vec3 pos);
@Shadow
private float eyeHeight;
@Shadow
private float eyeHeightOld;
private BlockGetter level;
@Shadow
protected abstract void setPosition(Vec3 pos);
@Shadow private float partialTickTime;
@Unique private float returnTimer = 0;
@Unique private float rollAngleStart = 0;
@Unique Minecraft minecraft = Minecraft.getInstance();
@Unique
private float returnTimer = 0;
@Unique
private float rollAngleStart = 0;
@Unique
Minecraft minecraft = Minecraft.getInstance();
@Unique
boolean disableRollableCameraDebug = false;
@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;
var controller = controllable.getOrientationController();
if (!controller.isActive() && controller.getOrientation() != null) {
if (this.returnTimer < 1) {
if(this.returnTimer < 1) {
//Rotation is taken from entity since we no longer handle mouse ourselves
//Stops a period of time when you can't input anything.
controller.getOrientation().set(
@@ -85,17 +82,16 @@ public abstract class CameraMixin {
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
);
if (rollAngleStart == 0) {
if(rollAngleStart == 0){
this.returnTimer = 1;
controller.reset();
return;
}
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart * (1 - returnTimer)));
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
cobblemon$applyRotation();
this.returnTimer += .05F;
ci.cancel();
}
else {
} else {
this.returnTimer = 1;
controller.reset();
}
@@ -109,37 +105,92 @@ public abstract class CameraMixin {
ci.cancel();
}
@Inject(method = "setup", at = @At("HEAD"))
private void cobblemon$tickAnimationPreRenders(BlockGetter level, Entity entity, boolean detached, boolean thirdPersonReverse, float partialTick, CallbackInfo ci) {
MountedPokemonAnimationRenderController.INSTANCE.reset();
}
//If you want to move this to a delagate you need an AW for position
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
if (cobblemon$isRidingPokemon(entity)) {
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(instance, entity, entity.getVehicle(), thirdPersonReverse, eyeHeightOld, eyeHeight);
if (position != null) {
setPosition(position);
Entity entity = instance.getEntity();
Entity vehicle = entity.getVehicle();
MountedPokemonAnimationRenderController.INSTANCE.reset();
if(vehicle instanceof Rideable){
//RidingCameraDelagate.INSTANCE.positionCamera(instance, x, y, z, original);
if (!(vehicle instanceof PokemonEntity pokemon)) {
original.call(instance, x, y, z);
return;
}
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemon.getDelegate();
Vec3 entityPos = new Vec3(
Mth.lerp(instance.getPartialTickTime(), pokemon.xOld, pokemon.getX()),
Mth.lerp(instance.getPartialTickTime(), pokemon.yOld, pokemon.getY()),
Mth.lerp(instance.getPartialTickTime(), pokemon.zOld, pokemon.getZ())
);
MountedPokemonAnimationRenderController.INSTANCE.setup(pokemon, partialTickTime);
int seatIndex = pokemon.getPassengers().indexOf(entity);
Seat seat = pokemon.getSeats().get(seatIndex);
OrientationControllable rollable = (OrientationControllable) entity;
OrientationController controller = rollable.getOrientationController();
if (!instance.isDetached() || Cobblemon.config.getThirdPartyViewBobbing()) {
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
if (locator == null) {
original.call(instance, x, y, z);
return;
}
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
float currEyeHeight = Mth.lerp(instance.getPartialTickTime(), eyeHeightOld, eyeHeight);
var rotatedEyeHeight = new Vector3f(0f, currEyeHeight - (entity.getBbHeight() / 2), 0f);
if (controller.isActive()) {
rotatedEyeHeight = controller.getRenderOrientation(partialTickTime).transform(rotatedEyeHeight);
}
Vec3 position = locatorOffset.add(entityPos).add(new Vec3(rotatedEyeHeight));
setPosition(position);
} else {
Vector3f pos = entityPos.add(new Vec3(0, pokemon.getBbHeight() / 2, 0)).toVector3f();
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemon.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
Map<String, Vec3> cameraOffsets = model.getSeatToCameraOffset();
Vec3 cameraOffset;
if (thirdPersonReverse && cameraOffsets.containsKey(seat.getLocator() + "_reverse")) {
cameraOffset = cameraOffsets.get(seat.getLocator() + "_reverse");
} else if (cameraOffsets.containsKey(seat.getLocator())) {
cameraOffset = cameraOffsets.get(seat.getLocator());
} else {
cameraOffset = new Vec3(0f, 2f, 4f);
}
Vector3f offset = cameraOffset.toVector3f();
if (thirdPersonReverse) offset.z *= -1;
float xRot = (float) (-1 * Math.toRadians(instance.getXRot()));
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f().rotateY((float) Math.toRadians(180f - instance.getYRot())).rotateX(xRot);
Vector3f rotatedOffset = orientation.transform(offset);
float offsetDistance = rotatedOffset.length();
Vector3f offsetDirection = rotatedOffset.mul(1 / offsetDistance);
float maxZoom = cobblemon$getMaxZoom(offsetDistance, offsetDirection, pos);
setPosition(new Vec3(offsetDirection.mul(maxZoom).add(pos)));
}
} else {
original.call(instance, x, y, z);
}
original.call(instance, x, y, z);
}
@Unique
private boolean cobblemon$isRidingPokemon(Entity entity) {
return entity.getVehicle() instanceof PokemonEntity;
}
@Unique
private void cobblemon$applyRotation() {
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null)
return;
private void cobblemon$applyRotation(){
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
var controller = controllable.getOrientationController();
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
if (this.minecraft.options.getCameraType().isMirrored()) {
newRotation.rotateY((float) Math.toRadians(180));
newRotation.rotateY((float)Math.toRadians(180));
}
this.rotation.set(newRotation);
this.xRot = controller.getPitch();
@@ -154,8 +205,30 @@ public abstract class CameraMixin {
Entity entity = instance.getEntity();
Entity vehicle = entity.getVehicle();
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getViewBobTranslation()) {
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPartyViewBobbing()) {
original.call(instance, zoom, dy, dx);
}
}
//Modified vanilla code
@Unique
private float cobblemon$getMaxZoom(float maxZoom, Vector3f directionVector, Vector3f positionVector) {
Vec3 pos = new Vec3(positionVector);
for (int i = 0; i < 8; i++) {
float g = (float) ((i & 1) * 2 - 1);
float h = (float) ((i >> 1 & 1) * 2 - 1);
float j = (float) ((i >> 2 & 1) * 2 - 1);
Vec3 vec3 = pos.add(g * 0.1F, h * 0.1F, j * 0.1F);
Vec3 vec32 = vec3.add(new Vec3(directionVector).scale(maxZoom));
HitResult hitResult = this.level.clip(new ClipContext(vec3, vec32, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, this.entity));
if (hitResult.getType() != HitResult.Type.MISS) {
float k = (float) hitResult.getLocation().distanceToSqr(pos);
if (k < Mth.square(maxZoom)) {
maxZoom = Mth.sqrt(k);
}
}
}
return maxZoom;
}
}
@@ -1,85 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
import java.util.Map;
@Mixin(ClientRecipeBook.class)
public abstract class ClientRecipeBookMixin {
@Shadow
protected static Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> categorizeAndGroupRecipes(Iterable<RecipeHolder<?>> recipes) {
return null;
}
@Shadow private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
@Shadow private List<RecipeCollection> allCollections;
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
Recipe<?> recipe2 = recipe.value();
if (recipe2 instanceof CookingPotRecipe || recipe2 instanceof CookingPotShapelessRecipe) {
CookingPotBookCategory category = recipe2 instanceof CookingPotRecipe
? ((CookingPotRecipe) recipe2).getCategory()
: ((CookingPotShapelessRecipe) recipe2).category();
RecipeBookCategories var7;
switch (category) {
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
case BAITS -> var7 = CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory();
default -> throw new MatchException(null, null);
}
cir.setReturnValue(var7);
}
}
@Inject(method = "setupCollections", at = @At("RETURN"))
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
map.forEach((recipeBookCategories, list) -> {
List<RecipeCollection> collections = list.stream()
.map(listx -> new RecipeCollection(registryAccess, listx))
.peek(builder::add)
.collect(ImmutableList.toImmutableList());
map2.put(recipeBookCategories, collections);
});
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
this.collectionsByTab = ImmutableMap.copyOf(map2);
this.allCollections = builder.build();
}
}
@@ -8,11 +8,24 @@
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.api.orientation.OrientationController;
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
import com.cobblemon.mod.common.stadium.StadiumClientManager;
import com.cobblemon.mod.common.util.CameraExtensionsKt;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -20,6 +33,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameRenderer.class)
public class GameRendererMixin {
@Shadow @Final Minecraft minecraft;
@Shadow float renderDistance;
@Shadow @Final private LightTexture lightTexture;
@Shadow private boolean renderHand;
@Shadow private double getFov(Camera activeRenderInfo, float partialTicks, boolean useFOVSetting) { return 0.0; }
@Shadow public void resetProjectionMatrix(Matrix4f matrix) {}
@Shadow public Matrix4f getProjectionMatrix(double fov) { return new Matrix4f(); }
@Shadow private void renderItemInHand(Camera camera, float partialTick, Matrix4f projectionMatrix) {}
@Shadow public void pick(float partialTicks) {}
@Unique
long lastTime = -1;
@@ -42,4 +66,54 @@ public class GameRendererMixin {
lastTime = newTime;
}
@Inject(method = "renderLevel", at = @At(value = "HEAD"), cancellable = true)
public void renderLevel(DeltaTracker deltaTracker, CallbackInfo ci) {
if (StadiumClientManager.INSTANCE.shouldUseStadiumCamera()) {
float f = deltaTracker.getGameTimeDeltaPartialTick(true);
this.lightTexture.updateLightTexture(f);
if (this.minecraft.getCameraEntity() == null) {
this.minecraft.setCameraEntity(this.minecraft.player);
}
this.minecraft.getProfiler().push("camera");
Camera stadiumCamera = new Camera();
Entity entity = (Entity) this.minecraft.player;
stadiumCamera.setup(this.minecraft.level, entity, false, false, 1.0F);
//adjust camera
StadiumClientManager.INSTANCE.updateCameraData(f);
var position = StadiumClientManager.INSTANCE.getCameraPosition();
stadiumCamera.setPosition(position);
Quaternionf rotation = StadiumClientManager.INSTANCE.getCameraRotation();
var forwardVector = rotation.transform(Camera.FORWARDS, new Vector3f());
var upVector = rotation.transform(Camera.UP, new Vector3f());
var leftVector = rotation.transform(Camera.LEFT, new Vector3f());
stadiumCamera.rotation.set(rotation);
stadiumCamera.xRot = (float)Mth.wrapDegrees(-Math.toDegrees(Math.asin(forwardVector.y)));
stadiumCamera.yRot = Mth.wrapDegrees((float)-Math.toDegrees(Camera.FORWARDS.angleSigned(forwardVector, Camera.UP)) + 180);
stadiumCamera.forwards.set(forwardVector);
stadiumCamera.up.set(upVector);
stadiumCamera.left.set(leftVector);
this.renderDistance = (float)(this.minecraft.options.getEffectiveRenderDistance() * 16);
double d = this.getFov(stadiumCamera, f, true);
Matrix4f matrix4f = this.getProjectionMatrix(d);
this.resetProjectionMatrix(matrix4f);
Quaternionf quaternionf = stadiumCamera.rotation().conjugate(new Quaternionf());
Matrix4f matrix4f2 = (new Matrix4f()).rotation(quaternionf);
this.minecraft.levelRenderer.prepareCullFrustum(stadiumCamera.getPosition(), matrix4f2, this.getProjectionMatrix(Math.max(d, (double)(Integer)this.minecraft.options.fov().get())));
this.minecraft.levelRenderer.renderLevel(deltaTracker, false, stadiumCamera, (GameRenderer) (Object) this, this.lightTexture, matrix4f2, matrix4f);
this.minecraft.getProfiler().pop();
ci.cancel();
}
}
@Inject(method = "tick", at = @At(value = "TAIL"))
public void tick(CallbackInfo ci) {
// StadiumClientManager.INSTANCE.tickCameraManager();
}
}
@@ -1,73 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonItems;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import com.google.common.collect.ImmutableList;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.world.inventory.RecipeBookType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList;
import java.util.List;
@Mixin(RecipeBookCategories.class)
public class RecipeBookCategoriesMixin {
@Final
@Mutable
@Shadow
private static RecipeBookCategories[] $VALUES;
@Invoker("<init>")
private static RecipeBookCategories cobblemon$createCategory(String name, int ordinal, ItemStack... icons) {
throw new AssertionError();
}
@Inject(
method = "<clinit>",
at = @At("TAIL")
)
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
ArrayList<RecipeBookCategories> types = new ArrayList<>(List.of($VALUES));
types.add(cobblemon$createCategory("COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.ROASTED_LEEK)));
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.HP_UP)));
types.add(cobblemon$createCategory("COOKING_POT_BAITS", $VALUES.length + 3, new ItemStack(CobblemonItems.PERSIM_BERRY)));
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.MIRROR_HERB)));
$VALUES = types.toArray(RecipeBookCategories[]::new);
}
@Inject(method = "getCategories", at = @At("HEAD"), cancellable = true)
private static void modifyCategories(RecipeBookType recipeBookType, CallbackInfoReturnable<List<RecipeBookCategories>> cir) {
if (recipeBookType == RecipeBookType.valueOf("COOKING_POT")) {
List var10000 = ImmutableList.of(
CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory(),
CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory());
cir.setReturnValue(var10000);
return;
}
}
}
@@ -1,63 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.CobblemonRecipeCategories;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.Minecraft;
import net.minecraft.client.RecipeBookCategories;
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RecipeBookComponent.class)
public class RecipeBookComponentMixin {
@Shadow private ClientRecipeBook book;
@Shadow protected Minecraft minecraft;
@Shadow private int width;
@Shadow private int xOffset;
@Shadow private int height;
@Shadow @Final private RecipeBookPage recipeBookPage;
@Inject(method = "updateTabs", at = @At("HEAD"), cancellable = true)
private void customUpdateTabs(CallbackInfo ci) {
RecipeBookComponent instance = (RecipeBookComponent) (Object) this;
int i = (width - 147) / 2 - xOffset - 30;
int j = (height - 166) / 2 + 3;
int k = 27;
int l = 0;
for (RecipeBookTabButton recipeBookTabButton : instance.tabButtons) {
RecipeBookCategories recipeBookCategories = recipeBookTabButton.getCategory();
if (recipeBookCategories != RecipeBookCategories.CRAFTING_SEARCH && recipeBookCategories != RecipeBookCategories.FURNACE_SEARCH && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory()) {
if (recipeBookTabButton.updateVisibility(book)) {
recipeBookTabButton.setPosition(i, j + 27 * l++);
recipeBookTabButton.startAnimation(minecraft);
}
} else {
recipeBookTabButton.visible = true;
recipeBookTabButton.setPosition(i, j + k * l++);
}
}
ci.cancel();
}
}
@@ -1,40 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import net.minecraft.client.ClientRecipeBook;
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.List;
@Mixin(RecipeBookTabButton.class)
public class RecipeBookTabButtonMixin {
@Inject(method = "updateVisibility", at = @At("HEAD"), cancellable = true)
private void customUpdateVisibility(ClientRecipeBook recipeBook, CallbackInfoReturnable<Boolean> cir) {
RecipeBookTabButton instance = (RecipeBookTabButton) (Object) this;
List<RecipeCollection> list = recipeBook.getCollection(instance.getCategory());
boolean visible = false;
if (list != null) {
for (RecipeCollection recipeCollection : list) {
if (recipeCollection.hasKnownRecipes() && recipeCollection.hasFitting()) {
visible = true;
break;
}
}
}
instance.visible = visible;
cir.setReturnValue(visible);
}
}
@@ -1,53 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
import net.minecraft.stats.RecipeBook;
import net.minecraft.world.entity.player.StackedContents;
import net.minecraft.world.item.crafting.RecipeHolder;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.Set;
@Mixin(RecipeCollection.class)
public class RecipeCollectionMixin {
@Shadow @Final private Set<RecipeHolder<?>> fitsDimensions;
@Shadow @Final private Set<RecipeHolder<?>> craftable;
@Shadow @Final private List<RecipeHolder<?>> recipes;
@Inject(method = "canCraft", at = @At("HEAD"), cancellable = true)
private void customCanCraft(StackedContents handler, int width, int height, RecipeBook book, CallbackInfo ci) {
for (RecipeHolder<?> recipeHolder : recipes) {
boolean bl = recipeHolder.value().canCraftInDimensions(width, height) && book.contains(recipeHolder);
if (bl) {
fitsDimensions.add(recipeHolder);
} else {
fitsDimensions.remove(recipeHolder);
}
if (bl && handler.canCraft(recipeHolder.value(), null)) {
craftable.add(recipeHolder);
} else {
craftable.remove(recipeHolder);
}
}
ci.cancel();
}
}
@@ -128,7 +128,6 @@ import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaField
import net.minecraft.client.Minecraft
import net.minecraft.commands.synchronization.SingletonArgumentInfo
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
@@ -195,8 +194,6 @@ object Cobblemon {
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
}
implementation.registerRecipeSerializers()
implementation.registerRecipeTypes()
implementation.registerPermissionValidator()
implementation.registerSoundEvents()
implementation.registerDataComponents()
@@ -205,11 +202,9 @@ object Cobblemon {
implementation.registerEntityTypes()
implementation.registerEntityAttributes()
implementation.registerBlockEntityTypes()
implementation.registerPoiTypes()
implementation.registerVillagers()
implementation.registerWorldGenFeatures()
implementation.registerParticles()
implementation.registerMenu()
implementation.registerEntityDataSerializers()
implementation.registerCriteria()
implementation.registerEntitySubPredicates()
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.entity.PokeCakeBlockEntity
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
import com.cobblemon.mod.common.block.entity.PCBlockEntity
@@ -37,6 +36,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.of(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val STADIUM: BlockEntityType<StadiumBlockEntity> = this.create("stadium_terminal", BlockEntityType.Builder.of(::StadiumBlockEntity, CobblemonBlocks.STADIUM).build(null))
@JvmField
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
@@ -46,9 +48,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.of(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
@JvmField
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.of(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN, CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN).build(null))
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.of(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
@JvmField
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN).build(null))
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
@JvmField
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.of(::GildedChestBlockEntity,
@@ -87,36 +89,4 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
BlockEntityType.Builder.of(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
)
@JvmField
val INCENSE_SWEET: BlockEntityType<SweetIncenseBlockEntity> = this.create("incense_sweet",
BlockEntityType.Builder.of(::SweetIncenseBlockEntity, CobblemonBlocks.INCENSE_SWEET).build(null)
)
@JvmField
val CAMPFIRE: BlockEntityType<CampfireBlockEntity> = this.create("campfire_pot",
BlockEntityType.Builder.of(::CampfireBlockEntity, CobblemonBlocks.CAMPFIRE).build(null)
)
/*@JvmField
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> =
BlockEntityType.Builder.of({ pos, state -> LureCakeBlockEntity(pos, state) },
CobblemonBlocks.LURE_CAKE
).build(null)*/
@JvmField
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> = this.create(
"lure_cake",
BlockEntityType.Builder.of(::LureCakeBlockEntity, CobblemonBlocks.LURE_CAKE).build(null)
)
@JvmField
val POKE_CAKE: BlockEntityType<PokeCakeBlockEntity> = this.create(
"poke_cake",
BlockEntityType.Builder.of(::PokeCakeBlockEntity, CobblemonBlocks.POKE_CAKE).build(null)
)
@JvmField
val CANDLE_POKE_CAKE: BlockEntityType<CandlePokeCakeBlockEntity> = this.create(
"candle_poke_cake",
BlockEntityType.Builder.of(::CandlePokeCakeBlockEntity, CobblemonBlocks.CANDLE_POKE_CAKE).build(null)
)
}
@@ -10,10 +10,8 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
import com.cobblemon.mod.common.block.LecternBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
@@ -22,7 +20,6 @@ import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
import com.cobblemon.mod.common.mixin.invoker.*
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.core.BlockPos
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
@@ -30,13 +27,9 @@ import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.EntityType
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.block.*
import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.properties.BlockSetType
import net.minecraft.world.level.block.state.properties.BlockStateProperties.LIT
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
import net.minecraft.world.level.block.state.properties.WoodType
import net.minecraft.world.level.material.MapColor
@@ -50,8 +43,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val APRICORN_BLOCK_SET_TYPE = BlockSetType("apricorn")
val APRICORN_WOOD_TYPE = WoodType.register(WoodType("apricorn", APRICORN_BLOCK_SET_TYPE))
val SACCHARINE_BLOCK_SET_TYPE = BlockSetType("saccharine")
val SACCHARINE_WOOD_TYPE = WoodType.register(WoodType("saccharine", SACCHARINE_BLOCK_SET_TYPE))
// Evolution Ores
@JvmField
@@ -168,80 +159,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
// Saccharines
@JvmField
val SACCHARINE_LOG = this.create("saccharine_log", SaccharineLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
@JvmField
val SACCHARINE_HONEY_LOG = this.create("saccharine_honey_log", SaccharineHoneyLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
@JvmField
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
@JvmField
val SACCHARINE_WOOD = log("saccharine_wood")
@JvmField
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
@JvmField
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_LEAVES = this.create("saccharine_leaves", SaccharineLeafBlock(
BlockBehaviour.Properties.of().mapColor(
MapColor.PLANT
).strength(0.2f).randomTicks().sound(SoundType.GRASS).noOcclusion()
.isValidSpawn { _: BlockState?, _: BlockGetter?, _: BlockPos?, entity: EntityType<*>? ->
entity === EntityType.OCELOT || entity === EntityType.PARROT
}.isSuffocating { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
false
}.isViewBlocking { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
false
}.ignitedByLava().pushReaction(PushReaction.DESTROY)
.isRedstoneConductor { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
false
}))
@JvmField
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(SACCHARINE_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
val SACCHARINE_BUTTON = this.create("saccharine_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
@JvmField
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).noCollission().strength(0.5f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_SIGN = this.create("saccharine_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
@JvmField
val SACCHARINE_SLAB = this.create("saccharine_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
@JvmField
val SACCHARINE_STAIRS = this.create("saccharine_stairs", StairsBlockInvoker.`cobblemon$create`(SACCHARINE_PLANKS.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SACCHARINE_PLANKS)))
@JvmField
val SACCHARINE_DOOR = this.create("saccharine_door", DoorBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(3.0F).sound(SoundType.WOOD).noOcclusion()))
@JvmField
val SACCHARINE_TRAPDOOR = this.create("saccharine_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(3.0F).sound(SoundType.WOOD).noOcclusion()))
@JvmField
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaccharineSaplingBlock(PLANT_PROPERTIES))
@JvmField
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.CRIMSON_NYLIUM).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val BUGWORT = this.create("bugwort", BugwortBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.COLOR_PURPLE).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
@JvmField
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.DIRT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
@JvmField
val BIG_ROOT = this.create("big_root", BigRootBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.BIG_ROOT_SOUNDS)))
@JvmField
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.PLANT).ignitedByLava().noCollission().instabreak().sound(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
@JvmField
val LURE_CAKE = this.create("lure_cake", LureCakeBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)))
@JvmField
val POKE_CAKE = this.create("poke_cake", PokeCakeBlock(BlockBehaviour.Properties.ofFullCopy(LURE_CAKE)))
@JvmField
val CANDLE_POKE_CAKE = this.create("candle_poke_cake", CandlePokeCakeBlock(BlockBehaviour.Properties.ofFullCopy(LURE_CAKE).lightLevel { blockState -> if (blockState.getValue(LIT) == true) 3 else 0 }))
@JvmField
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
@JvmField
@@ -393,60 +319,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
@JvmField
val BLACK_CAMPFIRE_POT = create("campfire_pot_black",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val BLUE_CAMPFIRE_POT = create("campfire_pot_blue",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val GREEN_CAMPFIRE_POT = create("campfire_pot_green",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val PINK_CAMPFIRE_POT = create("campfire_pot_pink",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PINK).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val RED_CAMPFIRE_POT = create("campfire_pot_red",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val WHITE_CAMPFIRE_POT = create("campfire_pot_white",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_GRAY)
.sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS).strength(0.5F).pushReaction(PushReaction.BLOCK)
.noOcclusion()
)
)
@JvmField
val YELLOW_CAMPFIRE_POT = create("campfire_pot_yellow",
CampfirePotBlock(
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_YELLOW).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
)
)
@JvmField
val CAMPFIRE = create("campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel { if ((it.getValue(CampfireBlock.SOUL) as Boolean)) 9 else 14 }))
@JvmField
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
@JvmField
@@ -482,15 +354,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
@JvmField
val PC = create("pc", PCBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if ((it.getValue(PCBlock.ON) as Boolean) && (it.getValue(PCBlock.PART) == PCBlock.PCPart.TOP)) 10 else 0 }))
@JvmField
val STADIUM = create("stadium_terminal", StadiumBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F)))
@JvmField
val LECTERN = create("lectern", LecternBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).sound(SoundType.WOOD).strength(2.5F).ignitedByLava()))
@JvmField
val DISPLAY_CASE = create("display_case", DisplayCaseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F)))
@JvmField
val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3f)))
@JvmField
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 10 else 0 }))
@@ -512,8 +384,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(MobEffects.LEVITATION, 10F, BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).offsetType(BlockBehaviour.OffsetType.XZ).pushReaction(PushReaction.DESTROY)))
@JvmField
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
@JvmField
val HEARTY_GRAINS = this.create("hearty_grains", HeartyGrainsBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.VIVICHOKE_SOUNDS)))
/**
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
@@ -522,10 +392,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
*/
fun strippedBlocks(): Map<Block, Block> = mapOf(
APRICORN_WOOD to STRIPPED_APRICORN_WOOD,
APRICORN_LOG to STRIPPED_APRICORN_LOG,
SACCHARINE_WOOD to STRIPPED_SACCHARINE_WOOD,
SACCHARINE_LOG to STRIPPED_SACCHARINE_LOG,
SACCHARINE_HONEY_LOG to STRIPPED_SACCHARINE_LOG
APRICORN_LOG to STRIPPED_APRICORN_LOG
)
@@ -94,17 +94,12 @@ interface CobblemonImplementation {
*/
fun registerBlockEntityTypes()
fun registerPoiTypes()
/**
* TODO
*
*/
fun registerVillagers()
fun registerRecipeSerializers()
fun registerRecipeTypes()
/**
* TODO
*
@@ -113,8 +108,6 @@ interface CobblemonImplementation {
fun registerParticles()
fun registerMenu()
fun registerEntitySubPredicates()
@@ -8,13 +8,9 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.PotComponent
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
import com.cobblemon.mod.common.item.components.FlavourComponent
import com.cobblemon.mod.common.item.components.FoodColourComponent
import com.cobblemon.mod.common.item.components.HeldItemCapableComponent
import com.cobblemon.mod.common.item.components.PokemonItemComponent
import com.cobblemon.mod.common.item.components.RodBaitComponent
import com.cobblemon.mod.common.item.RodBaitComponent
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.component.DataComponentType
@@ -40,34 +36,11 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
.build())
val POT_DATA: DataComponentType<PotComponent> = create("cooking_pot_item", DataComponentType.builder<PotComponent>()
.persistent(PotComponent.CODEC)
.networkSynchronized(PotComponent.PACKET_CODEC)
.build())
val BAIT_EFFECTS: DataComponentType<BaitEffectsComponent> = create("bait_effects", DataComponentType.builder<BaitEffectsComponent>()
.persistent(BaitEffectsComponent.CODEC)
.networkSynchronized(BaitEffectsComponent.PACKET_CODEC)
.build())
val FLAVOUR: DataComponentType<FlavourComponent> = create("flavour", DataComponentType.builder<FlavourComponent>()
.persistent(FlavourComponent.CODEC)
.networkSynchronized(FlavourComponent.PACKET_CODEC)
.build())
val FOOD_COLOUR: DataComponentType<FoodColourComponent> = create("food_colour", DataComponentType.builder<FoodColourComponent>()
.persistent(FoodColourComponent.CODEC)
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
.build())
fun register() {
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait"), BAIT)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:cooking_pot_item"), POT_DATA)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
}
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
@@ -8,7 +8,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
import com.cobblemon.mod.common.api.mulch.MulchVariant
import com.cobblemon.mod.common.api.pokeball.PokeBalls
@@ -27,14 +26,9 @@ import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
import com.cobblemon.mod.common.item.battle.DireHitItem
import com.cobblemon.mod.common.item.battle.GuardSpecItem
import com.cobblemon.mod.common.item.battle.XStatItem
import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.item.berry.FriendshipRaisingBerryItem
import com.cobblemon.mod.common.item.berry.HealingBerryItem
import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
import com.cobblemon.mod.common.item.berry.*
import com.cobblemon.mod.common.item.interactive.*
import com.cobblemon.mod.common.item.interactive.PotionItem
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
import com.cobblemon.mod.common.platform.PlatformRegistry
import com.cobblemon.mod.common.pokeball.PokeBall
@@ -50,14 +44,7 @@ import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.HangingSignItem
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.SignItem
import net.minecraft.world.item.SmithingTemplateItem
import net.minecraft.world.item.*
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
@@ -184,25 +171,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val POKEDEX_WHITE = pokedexItem(PokedexType.WHITE)
val campfire_pots = mutableListOf<CampfirePotItem>()
@JvmField
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
@JvmField
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
@JvmField
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, "green")
@JvmField
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, "pink")
@JvmField
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
@JvmField
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, "white")
@JvmField
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
@JvmField
val Hearty_Grains = compostableItem("hearty_grains", HeartyGrainsItem(CobblemonBlocks.HEARTY_GRAINS))
@JvmField
val VIVICHOKE = compostableItem("vivichoke")
@@ -293,321 +261,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Properties()))
// Saccharines
@JvmField
val SACCHARINE_LOG = blockItem("saccharine_log", CobblemonBlocks.SACCHARINE_LOG)
@JvmField
val SACCHARINE_HONEY_LOG = blockItem("saccharine_honey_log", CobblemonBlocks.SACCHARINE_HONEY_LOG)
@JvmField
val STRIPPED_SACCHARINE_LOG = blockItem("stripped_saccharine_log", CobblemonBlocks.STRIPPED_SACCHARINE_LOG)
@JvmField
val SACCHARINE_WOOD = blockItem("saccharine_wood", CobblemonBlocks.SACCHARINE_WOOD)
@JvmField
val STRIPPED_SACCHARINE_WOOD = blockItem("stripped_saccharine_wood", CobblemonBlocks.STRIPPED_SACCHARINE_WOOD)
@JvmField
val SACCHARINE_PLANKS = blockItem("saccharine_planks", CobblemonBlocks.SACCHARINE_PLANKS)
@JvmField
val SACCHARINE_LEAVES = compostableBlockItem("saccharine_leaves", CobblemonBlocks.SACCHARINE_LEAVES)
@JvmField
val SACCHARINE_BOAT = create("saccharine_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, false, Item.Properties().stacksTo(1)))
@JvmField
val SACCHARINE_CHEST_BOAT = create("saccharine_chest_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, true, Item.Properties().stacksTo(1)))
@JvmField
val SACCHARINE_DOOR = blockItem("saccharine_door", CobblemonBlocks.SACCHARINE_DOOR)
@JvmField
val SACCHARINE_TRAPDOOR = blockItem("saccharine_trapdoor", CobblemonBlocks.SACCHARINE_TRAPDOOR)
@JvmField
val SACCHARINE_FENCE = blockItem("saccharine_fence", CobblemonBlocks.SACCHARINE_FENCE)
@JvmField
val SACCHARINE_FENCE_GATE = blockItem("saccharine_fence_gate", CobblemonBlocks.SACCHARINE_FENCE_GATE)
@JvmField
val SACCHARINE_BUTTON = blockItem("saccharine_button", CobblemonBlocks.SACCHARINE_BUTTON)
@JvmField
val SACCHARINE_PRESSURE_PLATE = blockItem("saccharine_pressure_plate", CobblemonBlocks.SACCHARINE_PRESSURE_PLATE)
@JvmField
val SACCHARINE_SLAB = blockItem("saccharine_slab", CobblemonBlocks.SACCHARINE_SLAB)
@JvmField
val SACCHARINE_STAIRS = blockItem("saccharine_stairs", CobblemonBlocks.SACCHARINE_STAIRS)
@JvmField
val SACCHARINE_SIGN = this.create("saccharine_sign", SignItem(Item.Properties().stacksTo(16), CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN))
@JvmField
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", HangingSignItem(CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN, Item.Properties().stacksTo(16)))
@JvmField
val SACCHARINE_SAPLING = saccharineSaplingItem("saccharine_sapling", SaccharineSaplingItem(CobblemonBlocks.SACCHARINE_SAPLING))
@JvmField
val BUGWORT = bugwortItem("bugwort", BugwortItem(CobblemonBlocks.BUGWORT))
@JvmField
val POKE_BAIT = noSettingsItem("poke_bait")
@JvmField
val LURE_CAKE = blockItem("lure_cake", CobblemonBlocks.LURE_CAKE)
@JvmField
val POKE_CAKE = blockItem("poke_cake", CobblemonBlocks.POKE_CAKE)
val aprijuices = mutableListOf<AprijuiceItem>()
@JvmField
val APRIJUICE_BLACK = aprijuiceItem(Apricorn.BLACK)
@JvmField
val APRIJUICE_RED = aprijuiceItem(Apricorn.RED)
@JvmField
val APRIJUICE_BLUE = aprijuiceItem(Apricorn.BLUE)
@JvmField
val APRIJUICE_GREEN = aprijuiceItem(Apricorn.GREEN)
@JvmField
val APRIJUICE_YELLOW = aprijuiceItem(Apricorn.YELLOW)
@JvmField
val APRIJUICE_WHITE = aprijuiceItem(Apricorn.WHITE)
@JvmField
val APRIJUICE_PINK = aprijuiceItem(Apricorn.PINK)
@JvmField
val POKE_PUFF = noSettingsItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
// FOODS
@JvmField
val SWEET_HEART = noSettingsItem("sweet_heart") // todo make a SweetHeartItem class for breeding purposes
@JvmField
val PEWTER_CRUNCHIES = create("pewter_crunchies", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val RAGE_CANDY_BAR = create("rage_candy_bar", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val LAVA_COOKIE = create("lava_cookie", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val OLD_GATEAU = create("old_gateau", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val CASTELIACONE = create("casteliacone", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val SHALOR_SABLE = create("shalor_sable", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val LUMIOSE_GALETTE = create("lumiose_galette", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val BIG_MALASADA = create("big_malasada", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val CURRY = create("curry", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.usingConvertsTo(Items.BOWL)
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})*/
@JvmField
val JUBILIFE_MUFFIN = create("jubilife_muffin", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
/*@JvmField // todo see what we are doing for these (are there different kinds?)
val SANDWICH = create("sandwich", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.usingConvertsTo(Items.BOWL)
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})*/
// todo we might need to wait on these for later?
/*@JvmField
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for breeding purposes
@JvmField
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for breeding purposes
@JvmField
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for breeding purposes
*/
@JvmField
val POTATO_MOCHI = create("potato_mochi", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val FRIED_RICE = create("fried_rice", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val CANDIED_APPLE = create("candied_apple", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val CANDIED_BERRY = create("candied_berry", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
@JvmField
val JELLY_DOUGHNUT = create("jelly_doughnut", object : Item(Properties().stacksTo(16)
.food(FoodProperties.Builder()
.nutrition(10)
.saturationModifier(1.2F)
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
.alwaysEdible()
.build())) {
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
user.removeAllEffects()
return super.finishUsingItem(stack, world, user)
}
})
// todo etc?
//@JvmField
//val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
//@JvmField
//val STICKY_GLOB = this.create("sticky_glob", StickyGlobItem(Item.Settings()))
@JvmField
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
@JvmField
@@ -619,12 +272,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val PC = blockItem("pc", CobblemonBlocks.PC)
@JvmField
val STADIUM = blockItem("stadium_terminal", CobblemonBlocks.STADIUM)
@JvmField
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val INCENSE_SWEET = blockItem("incense_sweet", CobblemonBlocks.INCENSE_SWEET)
val LECTERN = blockItem("lectern", CobblemonBlocks.LECTERN)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -769,20 +423,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
@JvmField
val HEALTH_MOCHI = create("health_mochi", MochiItem(Stats.HP))
@JvmField
val MUSCLE_MOCHI = create("muscle_mochi", MochiItem(Stats.ATTACK))
@JvmField
val RESIST_MOCHI = create("resist_mochi", MochiItem(Stats.DEFENCE))
@JvmField
val GENIUS_MOCHI = create("genius_mochi", MochiItem(Stats.SPECIAL_ATTACK))
@JvmField
val CLEVER_MOCHI = create("clever_mochi", MochiItem(Stats.SPECIAL_DEFENCE))
@JvmField
val SWIFT_MOCHI = create("swift_mochi", MochiItem(Stats.SPEED))
@JvmField
val FRESH_START_MOCHI = create("fresh_start_mochi", FreshStartMochiItem())
@JvmField
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
@JvmField
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
@@ -1630,18 +1270,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
}
)
private fun campfirePotItem(block: Block, type: String): CampfirePotItem {
val item = create("campfire_pot_${type}", CampfirePotItem(block))
campfire_pots.add(item)
return item
}
private fun aprijuiceItem(type: Apricorn): AprijuiceItem {
val item = create("aprijuice_${type.name.lowercase()}", AprijuiceItem(type))
aprijuices.add(item)
return item
}
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
name,
CobblemonItem(Item.Properties()).also {
@@ -1701,21 +1329,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
return item
}
private fun saccharineSaplingItem(name: String, saccharineSaplingItem: SaccharineSaplingItem): SaccharineSaplingItem {
val finalName = "saccharine_sapling"
val item = this.create(finalName, saccharineSaplingItem)
compostable(item, .65f)
return item
}
private fun bugwortItem(name: String, bugwortItem: BugwortItem): BugwortItem {
val finalName = "bugwort"
val item = this.create(finalName, bugwortItem)
compostable(item, .65f)
return item
}
private fun mintSeed(name: String, mintBlock: MintBlock): Item {
val finalName = "${name}_mint_seeds"
val item = this.blockItem(finalName, mintBlock)
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.client.gui.screens.MenuScreens
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.inventory.MenuType
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
val COOKING_POT = MenuType.register("cooking_pot", ::CookingPotMenu)
override val registry: Registry<MenuType<*>>
get() = BuiltInRegistries.MENU
override val resourceKey: ResourceKey<Registry<MenuType<*>>>
get() = Registries.MENU
}
@@ -17,7 +17,6 @@ import com.cobblemon.mod.common.client.net.battle.*
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
@@ -68,8 +67,6 @@ import com.cobblemon.mod.common.net.messages.client.battle.*
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
import com.cobblemon.mod.common.net.messages.client.data.*
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
@@ -145,8 +142,6 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatRangePacket
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
@@ -191,8 +186,6 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatRangeHandler
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatsHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
@@ -225,6 +218,10 @@ import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHa
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
import com.cobblemon.mod.common.stadium.StadiumCamerasSyncPacket
import com.cobblemon.mod.common.stadium.StadiumJoinHandler
import com.cobblemon.mod.common.stadium.StadiumJoinPacket
import com.cobblemon.mod.common.stadium.StadiumCameraManagersSyncPacket
import com.cobblemon.mod.common.util.server
import net.minecraft.server.level.ServerPlayer
@@ -288,7 +285,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(MarksUpdatePacket.ID, MarksUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
// Evolution start
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
@@ -378,11 +374,12 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(ScriptRegistrySyncPacket.ID, ScriptRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(PokedexDexSyncPacket.ID, PokedexDexSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(SpawnBaitRegistrySyncPacket.ID, SpawnBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(SeasoningRegistrySyncPacket.ID, SeasoningRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(StadiumCamerasSyncPacket.ID, StadiumCamerasSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(StadiumCameraManagersSyncPacket.ID, StadiumCameraManagersSyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
@@ -445,6 +442,9 @@ object CobblemonNetwork {
// Riding
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
// Stadium packets
list.add(PacketRegisterInfo(StadiumJoinPacket.ID, StadiumJoinPacket::decode, StadiumJoinHandler))
return list
}
@@ -545,11 +545,6 @@ object CobblemonNetwork {
// Riding packet(s)
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
// Cooking
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
return list
}
@@ -1,40 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import net.minecraft.client.RecipeBookCategories
enum class CobblemonRecipeCategories {
COOKING_POT_SEARCH("COOKING_POT_SEARCH"),
COOKING_POT_FOODS("COOKING_POT_FOODS"),
COOKING_POT_MEDICINES("COOKING_POT_MEDICINES"),
COOKING_POT_BAITS("COOKING_POT_BAITS"),
COOKING_POT_MISC("COOKING_POT_MISC");
companion object {
val customAggregateCategories: Map<RecipeBookCategories, List<RecipeBookCategories>> = mapOf(
COOKING_POT_SEARCH.toVanillaCategory() to listOf(
COOKING_POT_FOODS.toVanillaCategory(), COOKING_POT_MISC.toVanillaCategory(), COOKING_POT_MEDICINES.toVanillaCategory(), COOKING_POT_BAITS.toVanillaCategory()
)
)
}
var id: String
constructor(id: String) {
this.id = id
}
fun toVanillaCategory(): RecipeBookCategories {
return RecipeBookCategories.valueOf(this.id)
}
}
@@ -1,35 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeSerializer
object CobblemonRecipeSerializers : PlatformRegistry<Registry<RecipeSerializer<*>>, ResourceKey<Registry<RecipeSerializer<*>>>, RecipeSerializer<*>>() {
val COOKING_POT_COOKING: RecipeSerializer<*> = register("cobblemon:cooking_pot", CookingPotRecipe.Serializer())
val COOKING_POT_SHAPELESS: RecipeSerializer<*> = register("cobblemon:cooking_pot_shapeless", CookingPotShapelessRecipe.Serializer())
override val registry: Registry<RecipeSerializer<*>>
get() = BuiltInRegistries.RECIPE_SERIALIZER
override val resourceKey: ResourceKey<Registry<RecipeSerializer<*>>>
get() = Registries.RECIPE_SERIALIZER
fun <S : RecipeSerializer<T>, T : Recipe<*>> register(key: String, recipeSerializer: S): S {
return Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, key, recipeSerializer) as S
}
}
@@ -1,44 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
import com.cobblemon.mod.common.platform.PlatformRegistry
import net.minecraft.core.Registry
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.core.registries.Registries
import net.minecraft.resources.ResourceKey
import net.minecraft.world.item.crafting.Recipe
import net.minecraft.world.item.crafting.RecipeType
object CobblemonRecipeTypes : PlatformRegistry<Registry<RecipeType<*>>, ResourceKey<Registry<RecipeType<*>>>, RecipeType<*>>() {
val COOKING_POT_COOKING: RecipeType<CookingPotRecipe> = register("cobblemon:cooking_pot")
val COOKING_POT_SHAPELESS: RecipeType<CookingPotShapelessRecipe> = register("cobblemon:cooking_pot_shapeless")
override val registry: Registry<RecipeType<*>>
get() = BuiltInRegistries.RECIPE_TYPE
override val resourceKey: ResourceKey<Registry<RecipeType<*>>>
get() = Registries.RECIPE_TYPE
fun <T : Recipe<*>> register(identifier: String): RecipeType<T> {
return Registry.register(
BuiltInRegistries.RECIPE_TYPE,
identifier,
object : RecipeType<T> {
override fun toString(): String {
return identifier
}
}
)
}
}
@@ -112,8 +112,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val MEDICINE_SPRAY_USE = this.create("item.medicine.spray.use")
@JvmField
val MEDICINE_FEATHER_USE = this.create("item.medicine.feather.use")
@JvmField
val MOCHI_USE = this.create("item.medicine.feather.use")
@JvmField
val MULCH_PLACE = this.create("block.mulch.place")
@@ -427,37 +425,5 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
DISPLAY_CASE_STEP
)
@JvmField
val CAMPFIRE_POT_PLACE_CAMPFIRE = this.create("block.campfire_pot.place_campfire")
@JvmField
val CAMPFIRE_POT_RETRIEVE = this.create("block.campfire_pot.retrieve")
@JvmField
val CAMPFIRE_POT_OPEN = this.create("block.campfire_pot.open")
@JvmField
val CAMPFIRE_POT_CLOSE = this.create("block.campfire_pot.close")
@JvmField
val CAMPFIRE_POT_USE = this.create("block.campfire_pot.use")
@JvmField
val CAMPFIRE_POT_COOK = this.create("block.campfire_pot.cook")
@JvmField
val CAMPFIRE_POT_CRAFT = this.create("block.campfire_pot.craft")
@JvmField
val CAMPFIRE_POT_PLACE = this.create("block.campfire_pot.place")
@JvmField
val CAMPFIRE_POT_BREAK = this.create("block.campfire_pot.break")
@JvmField
val CAMPFIRE_POT_HIT = this.create("block.campfire_pot.hit")
@JvmField
val CAMPFIRE_POT_STEP = this.create("block.campfire_pot.step")
@JvmField
val CAMPFIRE_POT_SOUNDS = SoundType(1f, 1.1f,
CAMPFIRE_POT_BREAK,
CAMPFIRE_POT_STEP,
CAMPFIRE_POT_PLACE,
CAMPFIRE_POT_HIT,
CAMPFIRE_POT_STEP
)
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
}
@@ -19,7 +19,7 @@ import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
object CobblemonVillagerPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
override val registry: Registry<PoiType> = BuiltInRegistries.POINT_OF_INTEREST_TYPE
override val resourceKey: ResourceKey<Registry<PoiType>> = Registries.POINT_OF_INTEREST_TYPE
@@ -27,20 +27,8 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
val NURSE_KEY: ResourceKey<PoiType> = createKey("nurse")
@JvmField
val NURSE = create(NURSE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.HEALING_MACHINE), 1, 1))
@JvmField
val LURE_CAKE_KEY: ResourceKey<PoiType> = createKey("lure_cake")
@JvmField
val LURE_CAKE = create(LURE_CAKE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.LURE_CAKE), 0, 1))
@JvmField
val SACCHARINE_HONEY_LOG_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
@JvmField
val SACCHARINE_HONEY_LOG = create(SACCHARINE_HONEY_LOG_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.SACCHARINE_HONEY_LOG), 0, 1))
@JvmField
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
@JvmField
val INCENSE_SWEET = create(INCENSE_SWEET_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.INCENSE_SWEET), 0, 1))
private fun createKey(string: String): ResourceKey<PoiType> = ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string))
private fun getBlockStates(block: Block): Set<BlockState> = ImmutableSet.copyOf(block.stateDefinition.possibleStates)
}
}
@@ -24,7 +24,7 @@ object CobblemonVillagerProfessions: PlatformRegistry<Registry<VillagerProfessio
override val resourceKey: ResourceKey<Registry<VillagerProfession>> = Registries.VILLAGER_PROFESSION
@JvmField
val NURSE = profession(CobblemonPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
val NURSE = profession(CobblemonVillagerPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
/**
* Register a villager profession texture override for Cobblemon villagers of the given [VillagerProfession] for specified names.
@@ -20,8 +20,8 @@ import net.minecraft.resources.ResourceLocation
class CastPokeRodContext(val baitId: ResourceLocation)
class CastPokeRodCriterionCondition(
playerCtx: Optional<ContextAwarePredicate>,
val baitId: String
playerCtx: Optional<ContextAwarePredicate>,
val baitId: String
): SimpleCriterionCondition<CastPokeRodContext>(playerCtx) {
companion object {
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.apricorn
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.block.ApricornBlock
import com.cobblemon.mod.common.block.ApricornSaplingBlock
import com.cobblemon.mod.common.item.ApricornItem
@@ -28,43 +27,15 @@ import net.minecraft.world.level.material.MapColor
* @author Licious
* @since October 29th, 2022
*/
enum class Apricorn(
/** A value of true means it buffs that flavour, a value of false means it weakens that flavour. */
val flavourStrength: Map<Flavour, Boolean> = emptyMap()
) : StringRepresentable {
enum class Apricorn : StringRepresentable {
BLACK,
BLUE(
mapOf(
Flavour.DRY to true,
Flavour.BITTER to false
)
),
GREEN(
mapOf(
Flavour.BITTER to true,
Flavour.SWEET to false
)
),
PINK(
mapOf(
Flavour.SWEET to true,
Flavour.SPICY to false
)
),
RED(
mapOf(
Flavour.SPICY to true,
Flavour.SOUR to false
)
),
BLUE,
GREEN,
PINK,
RED,
WHITE,
YELLOW(
mapOf(
Flavour.SOUR to true,
Flavour.DRY to false
)
);
YELLOW;
fun item(): ApricornItem = when(this) {
BLACK -> CobblemonItems.BLACK_APRICORN
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.berry
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.api.berry.spawncondition.BerrySpawnCondition
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
import com.cobblemon.mod.common.api.mulch.MulchVariant
@@ -21,10 +20,16 @@ import com.cobblemon.mod.common.item.berry.BerryItem
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.util.readBox
import com.cobblemon.mod.common.util.readEnumConstant
import com.cobblemon.mod.common.util.readEnumSet
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readList
import com.cobblemon.mod.common.util.readMap
import com.cobblemon.mod.common.util.writeBox
import com.cobblemon.mod.common.util.writeCollection
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeEnumSet
import com.cobblemon.mod.common.util.writeIdentifier
import com.cobblemon.mod.common.util.writeMap
import com.google.gson.annotations.SerializedName
import net.minecraft.core.BlockPos
import net.minecraft.network.RegistryFriendlyByteBuf
@@ -33,7 +38,6 @@ import java.util.EnumSet
import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.item.DyeColor
import net.minecraft.world.level.Level
import net.minecraft.world.level.biome.Biome
import net.minecraft.world.level.block.Block
@@ -57,7 +61,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
* @property growthPoints A collection of [GrowthPoint]s for the berry flowers and fruit.
* @property sproutShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the sprouting stages.
* @property matureShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the mature stages.
* @property flavours The [com.cobblemon.mod.common.api.cooking.Flavour] values.
* @property flavors The [Flavor] values.
* @property tintIndexes Determines tints at specific indexes if any.
* @property flowerModelIdentifier The [ResourceLocation] for the model of the berry in flower form.
* @property flowerTexture The [ResourceLocation] for the texture of the berry in flower form. This is resolved into a [ModelPart] on the client.
@@ -83,10 +87,7 @@ class Berry(
private val sproutShapeBoxes: Collection<AABB>,
@SerializedName("matureShape")
private val matureShapeBoxes: Collection<AABB>,
@SerializedName("flavours", alternate = ["flavor"])
val flavours: Map<Flavour, Int>,
@SerializedName("colour", alternate = ["color"])
val colour: DyeColor,
private val flavors: Map<Flavor, Int>,
val tintIndexes: Map<Int, Color>,
@SerializedName("flowerModel")
val flowerModelIdentifier: ResourceLocation,
@@ -143,13 +144,13 @@ class Berry(
/**
* Query the value of a certain flavor.
*
* @param flavour The [Flavour] being queried.
* @param flavor The [Flavor] being queried.
* @return The value if any or 0.
*/
fun flavor(flavour: Flavour): Int = this.flavours[flavour] ?: 0
fun flavor(flavor: Flavor): Int = this.flavors[flavor] ?: 0
fun dislikedBy(nature: Nature): Boolean {
val dislikedFlavor = nature.dislikedFlavour ?: return false
val dislikedFlavor = nature.dislikedFlavor ?: return false
return flavor(dislikedFlavor) > 0
}
@@ -280,8 +281,7 @@ class Berry(
buffer.writeCollection(this.matureShapeBoxes) { writer, value ->
writer.writeBox(value)
}
buffer.writeMap(this.flavours, { writer, key -> writer.writeEnumConstant(key) }, { writer, value -> writer.writeInt(value) })
buffer.writeEnumConstant(colour)
buffer.writeMap(this.flavors, { writer, key -> writer.writeEnumConstant(key) }, { writer, value -> writer.writeInt(value) })
buffer.writeMap(this.tintIndexes, { writer, key -> writer.writeInt(key) }, { writer, value -> writer.writeInt(value.rgb) })
buffer.writeIdentifier(this.flowerModelIdentifier)
buffer.writeIdentifier(this.flowerTexture)
@@ -353,8 +353,7 @@ class Berry(
val mutations = buffer.readMap({ reader -> reader.readIdentifier() }, { reader -> reader.readIdentifier() })
val sproutShapeBoxes = buffer.readList { it.readBox() }
val matureShapeBoxes = buffer.readList { it.readBox() }
val flavors = buffer.readMap({ reader -> reader.readEnumConstant(Flavour::class.java) }, { reader -> reader.readInt() })
val colour = buffer.readEnumConstant(DyeColor::class.java)
val flavors = buffer.readMap({ reader -> reader.readEnumConstant(Flavor::class.java) }, { reader -> reader.readInt() })
val tintIndexes = buffer.readMap({ reader -> reader.readInt() }, { reader -> Color(reader.readInt()) })
val flowerModelIdentifier = buffer.readIdentifier()
val flowerTexture = buffer.readIdentifier()
@@ -362,7 +361,7 @@ class Berry(
val fruitTexture = buffer.readIdentifier()
val stageOneYPos = GrowthPoint(Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()), Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()))
val boneMealChance = buffer.readFloat()
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, colour, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, stageOneYPos, 0F, boneMealChance)
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, stageOneYPos, 0F, boneMealChance)
}
}
@@ -0,0 +1,24 @@
/*
* 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.berry
/**
* Represents the different flavors associated with berries and other Pokémon consumables.
* See the [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Flavor) article for more information.
*
* @author Licious
* @since November 28th, 2022
*/
enum class Flavor(val colour: Int) {
SPICY(0x00FF00),
DRY(0xFF0000),
SWEET(0x0000FF),
BITTER(0xFFFF00),
SOUR(0xFF00FF);
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.cooking
import net.minecraft.ChatFormatting
import net.minecraft.util.StringRepresentable
/**
* Represents the different flavors associated with berries and other Pokémon consumables.
* See the [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Flavor) article for more information.
*
* @author Licious
* @since November 28th, 2022
*/
enum class Flavour(val colour: Int, val chatFormatting: ChatFormatting): StringRepresentable {
SPICY(0x00FF00, ChatFormatting.RED),
DRY(0xFF0000, ChatFormatting.DARK_AQUA),
SWEET(0x0000FF, ChatFormatting.LIGHT_PURPLE),
BITTER(0xFFFF00, ChatFormatting.GREEN),
SOUR(0xFF00FF, ChatFormatting.YELLOW);
override fun getSerializedName() = name
companion object {
val CODEC = StringRepresentable.fromEnum<Flavour> { Flavour.entries.toTypedArray() }
}
}
@@ -1,63 +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.cooking
import net.minecraft.util.FastColor
import net.minecraft.world.item.ItemStack
private val colourMap = mapOf(
Flavour.SPICY to 0xFEB37D,
Flavour.DRY to 0x8AE9FC,
Flavour.SWEET to 0xFFBEED,
Flavour.BITTER to 0x9EED8F,
Flavour.SOUR to 0xFCF38A
)
private val bubbleColourMap = mapOf(
Flavour.SPICY to 0xFFD9AD,
Flavour.DRY to 0xBCF8FE,
Flavour.SWEET to 0xFEE3F9,
Flavour.BITTER to 0xC8F7BC,
Flavour.SOUR to 0xFDFAB8
)
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
val flavors = seasonings
.flatMap { Seasonings.getFlavoursFromItemStack(it).entries }
.groupingBy { it.key }
.fold(0) { acc, entry -> acc + entry.value }
val maxFlavorValue = flavors.values.maxOrNull()
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
return getColourMixFromFlavours(dominantFlavors, forBubbles)
}
fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolean = false): Int? {
val colors =
dominantFlavours.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
.map { FastColor.ARGB32.opaque(it) }
if (colors.isEmpty()) return null
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
acc[0] += FastColor.ARGB32.alpha(color)
acc[1] += FastColor.ARGB32.red(color)
acc[2] += FastColor.ARGB32.green(color)
acc[3] += FastColor.ARGB32.blue(color)
acc
}
return FastColor.ARGB32.color(
alphaSum / colors.size,
redSum / colors.size,
greenSum / colors.size,
blueSum / colors.size
)
}
@@ -1,53 +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.cooking
import com.cobblemon.mod.common.api.conditional.ITEM_REGISTRY_LIKE_CODEC
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.annotations.SerializedName
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
data class Seasoning(
val ingredient: RegistryLikeCondition<Item>,
@SerializedName("flavours", alternate = ["flavors"])
val flavours: Map<Flavour, Int>,
@SerializedName("colour", alternate = ["color"])
val colour: DyeColor,
@SerializedName("baitEffects")
val baitEffects: List<SpawnBait.Effect> = emptyList()
) {
companion object {
val CODEC: Codec<Seasoning> = RecordCodecBuilder.create { builder ->
builder.group(
ITEM_REGISTRY_LIKE_CODEC.fieldOf("ingredient").forGetter { it.ingredient },
Codec.unboundedMap(Flavour.CODEC, Codec.INT).fieldOf("flavours").forGetter { it.flavours }, // Use map codec
DyeColor.CODEC.fieldOf("colour").forGetter { it.colour },
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects }
).apply(builder, ::Seasoning)
}
val STREAM_CODEC: StreamCodec<ByteBuf, Seasoning> = ByteBufCodecs.fromCodec(CODEC)
val BLANK_SEASONING = Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = Flavour.entries.associate { it to 0 },
colour = DyeColor.WHITE,
baitEffects = emptyList()
)
}
}
@@ -1,92 +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.cooking
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.berry.Berries
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
object Seasonings : JsonDataRegistry<Seasoning> {
override val id = cobblemonResource("seasonings")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<Seasonings>()
override val typeToken: TypeToken<Seasoning> = TypeToken.get(Seasoning::class.java)
override val resourcePath = "seasonings"
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.setPrettyPrinting()
.create()
val seasonings = mutableListOf<Seasoning>()
val BLANK_SEASONING = Seasoning(
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
flavours = emptyMap(),
colour = DyeColor.WHITE
)
override fun sync(player: ServerPlayer) {
SeasoningRegistrySyncPacket(seasonings.toList()).sendToPlayer(player)
}
override fun reload(data: Map<ResourceLocation, Seasoning>) {
// this needs to sideload the berry data so we don't get duplicate JSONs.
val finalData = Berries.all().associate {
it.identifier to Seasoning(
ingredient = RegistryLikeIdentifierCondition(it.identifier),
flavours = it.flavours.toMap(),
colour = it.colour
)
}.toMutableMap()
finalData.putAll(data)
seasonings.addAll(finalData.values)
}
fun reloadEntries(seasonings: Collection<Seasoning>) {
this.seasonings.clear()
this.seasonings.addAll(seasonings)
}
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int> {
val holder = stack.itemHolder
val seasoning = seasonings.find { it.ingredient.fits(holder) } ?: BLANK_SEASONING
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: emptyMap()
return seasoning.flavours.mapValues { (flavour, value) -> inherentFlavours.getOrDefault(flavour, 0) + value }
}
fun getBaitEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
return getFromItemStack(stack)?.baitEffects ?: emptyList()
}
fun getFromItemStack(stack: ItemStack): Seasoning? {
val holder = stack.itemHolder
return seasonings.find { it.ingredient.fits(holder) }
}
fun isSeasoning(stack: ItemStack) = getFromItemStack(stack) != null
}
@@ -255,11 +255,6 @@ object CobblemonEvents {
@JvmField
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
// Baits and Lures
@JvmField
val BAIT_SPAWN_POKEMON_MODIFY = EventObservable<BaitSpawnPokemonEvent.Modify>()
@JvmField
val COLLECT_EGG = CancelableObservable<CollectEggEvent>()
@JvmField
@@ -8,19 +8,19 @@
package com.cobblemon.mod.common.api.events.fishing
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.fishing.FishingBait
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.resources.ResourceLocation
/**
* Event to register code-based functions for bait effects.
* @see SpawnBait.Effect
* @see SpawnBait.Effects
* @see FishingBait.Effect
* @see FishingBait.Effects
*/
class BaitEffectFunctionRegistryEvent {
val functions = mutableMapOf<ResourceLocation, (PokemonEntity, SpawnBait.Effect) -> Unit>()
val functions = mutableMapOf<ResourceLocation, (PokemonEntity, FishingBait.Effect) -> Unit>()
fun registerFunction(id: ResourceLocation, function: (PokemonEntity, SpawnBait.Effect) -> Unit) {
fun registerFunction(id: ResourceLocation, function: (PokemonEntity, FishingBait.Effect) -> Unit) {
functions[id] = function
}
}
@@ -1,59 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.fishing
import com.cobblemon.mod.common.api.events.Cancelable
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.world.item.ItemStack
/**
* Event that is fired when a Pokemon is spawned by a bobber.
*/
interface BaitSpawnPokemonEvent {
/**
* Event that is fired before a Pokemon is spawned by a bobber.
* @param bobber The PokeRodFishingBobberEntity that is spawning the Pokemon.
* @param chosenBucket The bucket that is chosen.
* @param rod The ItemStack of the rod that the bobber is attached to.
*/
data class Pre(
val bobber: PokeRodFishingBobberEntity, // todo replace this with the bait entity
val chosenBucket: SpawnBucket,
val rod: ItemStack
) : Cancelable(), BobberSpawnPokemonEvent
/**
* Event that is fired when a Pokemon is modified before it is spawned by a bobber.
* @param chosenBucket The bucket that is chosen.
* @param rod The ItemStack of the rod that the bobber is attached to.
* @param pokemon The Pokemon that is modified.
*/
data class Modify(
val chosenBucket: SpawnBucket,
val rod: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent
/**
* Event that is fired after a Pokemon is spawned by a bobber.
* @param bobber The PokeRodFishingBobberEntity that is spawning the Pokemon.
* @param chosenBucket The bucket that is chosen.
* @param bait The ItemStack of the bait that is set on the rod.
* @param pokemon The Pokemon that is spawned.
*/
data class Post(
val bobber: PokeRodFishingBobberEntity,
val chosenBucket: SpawnBucket,
val bait: ItemStack,
val pokemon: PokemonEntity
) : BobberSpawnPokemonEvent
}
@@ -8,8 +8,6 @@
package com.cobblemon.mod.common.api.fishing
import com.cobblemon.mod.common.api.conditional.ITEM_REGISTRY_LIKE_CODEC
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.fishing.BaitEffectFunctionRegistryEvent
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
@@ -18,14 +16,18 @@ import com.cobblemon.mod.common.util.cobblemonResource
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.Optional
import net.minecraft.core.Registry
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class SpawnBait(
val item: RegistryLikeCondition<Item>,
data class FishingBait(
val item: ResourceLocation,
val effects: List<Effect>,
) {
fun toItemStack(itemRegistry: Registry<Item>) = item.let(itemRegistry::get)?.let { ItemStack(it) } ?: ItemStack.EMPTY
data class Effect(
val type: ResourceLocation,
val subcategory: ResourceLocation?,
@@ -47,14 +49,19 @@ class SpawnBait(
}
companion object {
val CODEC = RecordCodecBuilder.create<SpawnBait> { instance ->
val CODEC = RecordCodecBuilder.create<FishingBait> { instance ->
instance.group(
ITEM_REGISTRY_LIKE_CODEC.fieldOf("item").forGetter { it.item },
ResourceLocation.CODEC.fieldOf("item").forGetter { it.item },
Effect.CODEC.listOf().fieldOf("effects").forGetter {it.effects}
).apply(instance, ::SpawnBait)
).apply(instance, ::FishingBait)
}
val STREAM_CODEC = ByteBufCodecs.fromCodec(CODEC)
val BLANK_BAIT = FishingBait(
cobblemonResource("blank"),
emptyList()
)
}
object Effects {
@@ -71,7 +78,7 @@ class SpawnBait(
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
val FRIENDSHIP = cobblemonResource("friendship")
val RARITY_BUCKET = cobblemonResource("rarity_bucket")
val INERT = cobblemonResource("inert")
fun registerEffect(type: ResourceLocation, effect: (PokemonEntity, Effect) -> Unit) {
EFFECT_FUNCTIONS[type] = effect
@@ -82,15 +89,15 @@ class SpawnBait(
}
fun setupEffects() {
registerEffect(NATURE) { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
registerEffect(IV) { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
registerEffect(SHINY_REROLL) { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
registerEffect(GENDER_CHANCE) { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
registerEffect(LEVEL_RAISE) { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
registerEffect(HIDDEN_ABILITY_CHANCE) { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
registerEffect(FRIENDSHIP) { entity, effect -> FishingSpawnCause.alterFriendshipAttempt(entity, effect) }
EFFECT_FUNCTIONS[NATURE] = { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
EFFECT_FUNCTIONS[IV] = { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
EFFECT_FUNCTIONS[SHINY_REROLL] = { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
EFFECT_FUNCTIONS[GENDER_CHANCE] = { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
EFFECT_FUNCTIONS[LEVEL_RAISE] = { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
EFFECT_FUNCTIONS[HIDDEN_ABILITY_CHANCE] = { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
EFFECT_FUNCTIONS[FRIENDSHIP] = { entity, effect -> FishingSpawnCause.alterFriendshipAttempt(entity, effect) }
CobblemonEvents.BAIT_EFFECT_REGISTRATION.post(BaitEffectFunctionRegistryEvent()) { event ->
event.functions.forEach { (type, function) -> registerEffect(type, function) }
EFFECT_FUNCTIONS.putAll(event.functions)
}
}
}
@@ -0,0 +1,114 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.fishing
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.FishingBaitRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.item.ItemStack
object FishingBaits : JsonDataRegistry<FishingBait>{
override val id = cobblemonResource("fishing_baits")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<FishingBaits>()
override val typeToken: TypeToken<FishingBait> = TypeToken.get(FishingBait::class.java)
override val resourcePath = "fishing_baits"
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.setPrettyPrinting()
.create()
private val itemMap = mutableMapOf<ResourceLocation, FishingBait>()
override fun sync(player: ServerPlayer) {
FishingBaitRegistrySyncPacket(this.itemMap.values.toList()).sendToPlayer(player)
}
override fun reload(data: Map<ResourceLocation, FishingBait>) {
itemMap.clear()
data.forEach { id, bait ->
itemMap[bait.item] = bait
}
}
fun getFromRodItemStack(stack: ItemStack): FishingBait? {
return stack.components.get(CobblemonItemComponents.BAIT)?.bait
}
fun getFromBaitItemStack(stack: ItemStack): FishingBait? {
return getFromIdentifier(BuiltInRegistries.ITEM.getKey(stack.item))
}
fun getFromIdentifier(identifier: ResourceLocation): FishingBait? {
return itemMap[identifier]
}
fun isFishingBait(stack: ItemStack) = itemMap.containsKey(BuiltInRegistries.ITEM.getKey(stack.item))
//
//
// fun getBaitSubcategory(item: ItemStack): String? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.subcategory
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.subcategory
// }
// return null
// }
//
// fun getBaitSuccessChance(item: ItemStack): Double? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.chance
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.chance
// }
// return null
// }
//
// fun getBaitEffectValue(item: ItemStack): Double? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.value
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.value
// }
// return null
// }
//
//
// fun getBaitNote(item: ItemStack): String? {
// val itemId = Registries.ITEM.getId(item.item)
// if (itemId in itemMap.keys) {
// return itemMap[itemId]?.note
// }
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
// if (tag != null) {
// return tagMap[tag]?.note
// }
// return null
// }
}
@@ -1,103 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.fishing
import com.cobblemon.mod.common.CobblemonItemComponents
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.SpawnBaitRegistrySyncPacket
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
import com.cobblemon.mod.common.util.cobblemonResource
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import net.minecraft.core.Holder
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.PackType
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
override val id = cobblemonResource("spawn_bait_effects")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<SpawnBaitEffects>()
override val typeToken: TypeToken<SpawnBait> = TypeToken.get(SpawnBait::class.java)
override val resourcePath = "spawn_bait_effects"
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
.setPrettyPrinting()
.create()
private val effectsMap = mutableMapOf<ResourceLocation, SpawnBait>()
override fun sync(player: ServerPlayer) {
SpawnBaitRegistrySyncPacket(this.effectsMap.toMap()).sendToPlayer(player)
}
override fun reload(data: Map<ResourceLocation, SpawnBait>) {
effectsMap.clear()
data.forEach { id, bait ->
effectsMap[id] = bait
}
}
fun getEffectsFromRodItemStack(stack: ItemStack): List<SpawnBait.Effect> {
return getEffectsFromItemStack(stack.components.get(CobblemonItemComponents.BAIT)?.stack ?: ItemStack.EMPTY)
}
fun getEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
val componentEffects = stack.get(CobblemonItemComponents.BAIT_EFFECTS)?.effects ?: emptyList()
return componentEffects.mapNotNull(::getFromIdentifier).flatMap { it.effects } +
getEffectsFromItem(stack.itemHolder)
}
fun getBaitIdentifiersFromItem(holder: Holder<Item>): List<ResourceLocation> {
return effectsMap.entries.filter { it.value.item.fits(holder) }.map { it.key }
}
fun getBaitFromItemStack(holder: Holder<Item>): List<SpawnBait> {
return effectsMap.values.filter { it.item.fits(holder) }
}
private fun getEffectsFromItem(holder: Holder<Item>): List<SpawnBait.Effect> {
return getBaitFromItemStack(holder).flatMap { it.effects }
}
fun getFromIdentifier(identifier: ResourceLocation): SpawnBait? {
// Check normal spawn bait registry
effectsMap[identifier]?.let { return it }
// check seasoning spawn bait registry
if (identifier.namespace == "seasonings") {
val seasoning = com.cobblemon.mod.common.api.cooking.Seasonings.seasonings.find {
it.ingredient is RegistryLikeIdentifierCondition &&
(it.ingredient as RegistryLikeIdentifierCondition<Item>).identifier.path == identifier.path
}
if (seasoning != null && seasoning.baitEffects.isNotEmpty()) {
return SpawnBait(
item = seasoning.ingredient,
effects = seasoning.baitEffects
)
}
}
return null
}
fun isFishingBait(stack: ItemStack): Boolean {
val holder = stack.itemHolder
return stack.has(CobblemonItemComponents.BAIT_EFFECTS) || effectsMap.values.any { it.item.fits(holder) }
}
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.fishing
object SpawnBaitUtils {
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
return grouped.map { (key, groupEffects) ->
val (type, subcategory) = key
if (type == SpawnBait.Effects.RARITY_BUCKET) {
// we want to keep the highest rarity bucket effect instead of merging them
groupEffects.maxByOrNull { it.value }!!
} else {
val count = groupEffects.size
val totalChance = groupEffects.sumOf { it.chance }
val totalValue = groupEffects.sumOf { it.value }
val multiplier = when (count) {
2 -> 0.8
3 -> 0.9
else -> 1.0
}
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
val adjustedValue = totalValue * multiplier
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
}
}
}
}
@@ -215,7 +215,6 @@ fun drawPosablePortrait(
ageInTicks: Float = 0F,
headYaw: Float = 0F,
headPitch: Float = 0F,
doQuirks: Boolean = true,
r: Float = 1F,
g: Float = 1F,
b: Float = 1F,
@@ -241,7 +240,6 @@ fun drawPosablePortrait(
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, state.currentAspects)
context.put(RenderContext.POSABLE_STATE, state)
context.put(RenderContext.DO_QUIRKS, doQuirks)
val renderType = RenderType.entityCutout(texture)
@@ -82,7 +82,7 @@ interface PokemonAndMoveSelectingItem {
val bagItem = bagItem
if (!battlePokemon.actor.canFitForcedAction()) {
player.sendSystemMessage(battleLang("bagitem.cannot").red())
} else if (!bagItem!!.canUse(stack, battle, battlePokemon)) {
} else if (!bagItem!!.canUse(battle, battlePokemon)) {
player.sendSystemMessage(battleLang("bagitem.invalid").red())
} else {
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon, move.template.name))
@@ -92,10 +92,10 @@ interface PokemonAndMoveSelectingItem {
}
}
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
fun canUseOnMove(stack: ItemStack, pokemon: Pokemon, move: Move): Boolean = canUseOnMove(stack, move)
fun canUseOnMove(stack: ItemStack, move: Move): Boolean
fun canUseOnPokemon(pokemon: Pokemon): Boolean
fun canUseOnBattlePokemon(battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(battlePokemon.actor.battle, battlePokemon)
fun canUseOnMove(pokemon: Pokemon, move: Move): Boolean = canUseOnMove(move)
fun canUseOnMove(move: Move): Boolean
fun interactWithSpecific(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
@@ -106,18 +106,18 @@ interface PokemonAndMoveSelectingItem {
MoveSelectCallbacks.create(
player = player,
moves = pokemon.moveSet.toList(),
canSelect = { canUseOnMove(stack, it)},
canSelect = ::canUseOnMove,
handler = { move -> if (stack.isHeld(player)) applyToPokemon(player, stack, pokemon, move) }
)
return InteractionResultHolder.success(stack)
}
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack>? {
return if (canUseOnBattlePokemon(stack, battlePokemon)) {
return if (canUseOnBattlePokemon(battlePokemon)) {
MoveSelectCallbacks.create(
player = player,
moves = battlePokemon.moveSet.getMoves(),
canSelect = { canUseOnMove(stack, it) },
canSelect = ::canUseOnMove,
handler = { applyToBattlePokemon(player, stack, battlePokemon, it) }
)
InteractionResultHolder.success(stack)
@@ -131,8 +131,8 @@ interface PokemonAndMoveSelectingItem {
PartyMoveSelectCallbacks.createFromPokemon(
player = player,
pokemon = player.party().toList(),
canSelectPokemon = { canUseOnPokemon(stack, it) },
canSelectMove = { pokemon, move -> canUseOnMove(stack, pokemon, move) },
canSelectPokemon = ::canUseOnPokemon,
canSelectMove = ::canUseOnMove,
handler = { pk, mv -> if (stack.isHeld(player)) applyToPokemon(player, stack, pk, mv) }
)
@@ -144,8 +144,8 @@ interface PokemonAndMoveSelectingItem {
player = player,
pokemon = actor.pokemonList.map { it.effectedPokemon },
moves = { pk -> actor.pokemonList.find { it.effectedPokemon == pk }!!.moveSet.getMoves() },
canSelectPokemon = { pk -> canUseOnBattlePokemon(stack, actor.pokemonList.find { it.effectedPokemon == pk }!!) },
canSelectMove = { pokemon, move -> canUseOnMove(stack, pokemon, move) },
canSelectPokemon = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk }!!) },
canSelectMove = ::canUseOnMove,
handler = { pk, mv -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk }!!, mv) }
)
@@ -92,7 +92,7 @@ interface PokemonSelectingItem {
val bagItem = bagItem
if (!battlePokemon.actor.canFitForcedAction()) {
player.sendSystemMessage(battleLang("bagitem.cannot").red())
} else if (!bagItem!!.canUse(stack, battle, battlePokemon)) {
} else if (!bagItem!!.canUse(battle, battlePokemon)) {
player.sendSystemMessage(battleLang("bagitem.invalid").red())
} else {
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon))
@@ -105,11 +105,11 @@ interface PokemonSelectingItem {
}
}
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
fun canUseOnPokemon(pokemon: Pokemon): Boolean
fun canUseOnBattlePokemon(battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(battlePokemon.actor.battle, battlePokemon)
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack> {
return if (canUseOnBattlePokemon(stack, battlePokemon)) {
return if (canUseOnBattlePokemon(battlePokemon)) {
applyToBattlePokemon(player, stack, battlePokemon)
InteractionResultHolder.success(stack)
} else {
@@ -127,7 +127,7 @@ interface PokemonSelectingItem {
PartySelectCallbacks.createFromPokemon(
player = player,
pokemon = party,
canSelect = { pk -> canUseOnPokemon(stack, pk) },
canSelect = ::canUseOnPokemon,
handler = { pk ->
if (stack.isHeld(player)) {
applyToPokemon(player, stack, pk)
@@ -143,7 +143,7 @@ interface PokemonSelectingItem {
PartySelectCallbacks.createBattleSelect(
player = player,
pokemon = actor.pokemonList,
canSelect = { pk -> canUseOnBattlePokemon(stack, actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) },
canSelect = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) },
handler = { pk -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) }
)
@@ -831,11 +831,7 @@ object MoLangFunctions {
map.put("in_battle") { DoubleValue(pokemonEntity.isBattling) }
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
map.put("get_alt_pose") { StringValue(pokemonEntity.getAltPose()) }
map.put("is_gliding") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("gliding"))) }
map.put("is_sprinting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("sprinting"))) }
map.put("in_air") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("in_air"))) }
map.put("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
map.put("is_pokemon") { DoubleValue.ONE }
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.net.serializers
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.network.syncher.EntityDataSerializer
object RideBoostsDataSerializer : EntityDataSerializer<Map<RidingStat, Float>> {
val ID = cobblemonResource("ride_boosts")
fun read(buf: RegistryFriendlyByteBuf): Map<RidingStat, Float> {
return buf.readMap(
{ RidingStat.valueOf(it.readString()) },
{ it.readFloat() }
)
}
override fun copy(value: Map<RidingStat, Float>) = value.toMap()
fun write(buf: RegistryFriendlyByteBuf, value: Map<RidingStat, Float>) {
buf.writeMap(
value,
{ _, it -> buf.writeString(it.name) },
{ _, it -> buf.writeFloat(it) }
)
}
override fun codec() = StreamCodec.of(::write, ::read)
}
@@ -17,7 +17,6 @@ import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3f
import kotlin.math.asin
import kotlin.math.sign
open class OrientationController(val entity: LivingEntity) {
@@ -109,15 +108,21 @@ open class OrientationController(val entity: LivingEntity) {
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
fun applyGlobalYaw(deltaYawDegrees: Float) = updateOrientation { original ->
return@updateOrientation original.rotateLocalY(-deltaYawDegrees.toRadians())
}
val euler = Vector3f()
original.getEulerAnglesXYZ(euler)
val pitch0 = euler.x
val roll0 = euler.z
fun applyGlobalPitch(deltaPitchDegrees: Float) = updateOrientation { original ->
val currQuat = Quaternionf().setFromUnnormalized(original)
val horzLeftVector = Vector3f(this.leftVector.x, 0.0f, this.leftVector.z)
val globalPitch = Quaternionf().fromAxisAngleRad(horzLeftVector.normalize(), -deltaPitchDegrees.toRadians())
val resultQuat = globalPitch.mul(currQuat)
return@updateOrientation Matrix3f().set(resultQuat)
val unroll = Matrix3f().rotateZ(-roll0)
val unpitch = Matrix3f().rotateX(-pitch0)
val flattened = Matrix3f(original).mul(unroll).mul(unpitch)
//Flip to reflect current acceptance of what direction is pos for yaw
val globalYaw = Matrix3f().rotationY(-1.0f * deltaYawDegrees.toRadians())
val rePitch = Matrix3f().rotateX(pitch0)
val reRoll = Matrix3f().rotateZ(roll0)
return@updateOrientation Matrix3f(globalYaw).mul(flattened).mul(rePitch).mul(reRoll)
}
}
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.pokemon
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.berry.Flavor
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.pokemon.Nature
import com.cobblemon.mod.common.util.cobblemonResource
@@ -31,27 +31,27 @@ object Natures {
val LONELY = registerNature(
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
Stats.ATTACK, Stats.DEFENCE, Flavour.SPICY, Flavour.SOUR)
Stats.ATTACK, Stats.DEFENCE, Flavor.SPICY, Flavor.SOUR)
)
val BRAVE = registerNature(
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
Stats.ATTACK, Stats.SPEED, Flavour.SPICY, Flavour.SWEET)
Stats.ATTACK, Stats.SPEED, Flavor.SPICY, Flavor.SWEET)
)
val ADAMANT = registerNature(
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavour.SPICY, Flavour.DRY)
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavor.SPICY, Flavor.DRY)
)
val NAUGHTY = registerNature(
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavour.SPICY, Flavour.BITTER)
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavor.SPICY, Flavor.BITTER)
)
val BOLD = registerNature(
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
Stats.DEFENCE, Stats.ATTACK, Flavour.SOUR, Flavour.SPICY)
Stats.DEFENCE, Stats.ATTACK, Flavor.SOUR, Flavor.SPICY)
)
val DOCILE = registerNature(
@@ -61,27 +61,27 @@ object Natures {
val RELAXED = registerNature(
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
Stats.DEFENCE, Stats.SPEED, Flavour.SOUR, Flavour.SWEET)
Stats.DEFENCE, Stats.SPEED, Flavor.SOUR, Flavor.SWEET)
)
val IMPISH = registerNature(
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavour.SOUR, Flavour.DRY)
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavor.SOUR, Flavor.DRY)
)
val LAX = registerNature(
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavour.SOUR, Flavour.BITTER)
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavor.SOUR, Flavor.BITTER)
)
val TIMID = registerNature(
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
Stats.SPEED, Stats.ATTACK, Flavour.SWEET, Flavour.SPICY)
Stats.SPEED, Stats.ATTACK, Flavor.SWEET, Flavor.SPICY)
)
val HASTY = registerNature(
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
Stats.SPEED, Stats.DEFENCE, Flavour.SWEET, Flavour.SOUR)
Stats.SPEED, Stats.DEFENCE, Flavor.SWEET, Flavor.SOUR)
)
val SERIOUS = registerNature(
@@ -91,12 +91,12 @@ object Natures {
val JOLLY = registerNature(
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavour.SWEET, Flavour.DRY)
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavor.SWEET, Flavor.DRY)
)
val NAIVE = registerNature(
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavour.SWEET, Flavour.BITTER)
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavor.SWEET, Flavor.BITTER)
)
val MODEST = registerNature(
@@ -106,12 +106,12 @@ object Natures {
val MILD = registerNature(
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavour.DRY, Flavour.SOUR)
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavor.DRY, Flavor.SOUR)
)
val QUIET = registerNature(
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavour.DRY, Flavour.SWEET)
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavor.DRY, Flavor.SWEET)
)
val BASHFUL = registerNature(
@@ -121,27 +121,27 @@ object Natures {
val RASH = registerNature(
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavour.DRY, Flavour.BITTER)
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavor.DRY, Flavor.BITTER)
)
val CALM = registerNature(
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavour.BITTER, Flavour.SPICY)
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavor.BITTER, Flavor.SPICY)
)
val GENTLE = registerNature(
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavour.BITTER, Flavour.SOUR)
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavor.BITTER, Flavor.SOUR)
)
val SASSY = registerNature(
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavour.BITTER, Flavour.SWEET)
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavor.BITTER, Flavor.SWEET)
)
val CAREFUL = registerNature(
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavour.BITTER, Flavour.DRY)
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavor.BITTER, Flavor.DRY)
)
val QUIRKY = registerNature(
@@ -9,7 +9,6 @@
package com.cobblemon.mod.common.api.riding
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.stats.RidingStat
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
@@ -18,18 +17,17 @@ import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
import net.minecraft.network.RegistryFriendlyByteBuf
class RidingProperties(
val stats: MutableMap<RidingStat, RidingStatDefinition> = mutableMapOf(),
val seats: List<Seat> = listOf(),
val conditions: List<Expression> = listOf(),
val behaviour: RidingBehaviourSettings? = null
val stats: Map<RidingStat, RidingStatDefinition> = mapOf(),
val seats: List<Seat> = listOf(),
val conditions: List<Expression> = listOf(),
val behaviour: RidingBehaviourSettings? = null
) {
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
val stats: MutableMap<RidingStat, RidingStatDefinition> = buffer.readMap(
{ buffer.readEnum(RidingStat::class.java) },
{ RidingStatDefinition.decode(buffer) }
).toMutableMap()
val stats: Map<RidingStat, RidingStatDefinition> = buffer.readMap(
{ buffer.readEnum(RidingStat::class.java) },
{ RidingStatDefinition.decode(buffer) }
)
val seats: List<Seat> = buffer.readList { _ -> Seat.decode(buffer) }
val conditions = buffer.readList { buffer.readString().asExpression() }
val behaviour = buffer.readNullable { _ ->
@@ -43,19 +41,11 @@ class RidingProperties(
}
}
internal fun updateStatRange(stat: RidingStat, style: RidingStyle, min: Int, max: Int) {
if (!Cobblemon.config.enableDebugKeys) return
if (stats[stat] == null) {
stats[stat] = RidingStatDefinition()
}
stats[stat]!!.ranges[style] = min..max
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeMap(
stats,
{ _, stat -> buffer.writeEnum(stat) },
{ _, stat -> stat.encode(buffer) }
stats,
{ _, stat -> buffer.writeEnum(stat) },
{ _, stat -> stat.encode(buffer) }
)
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
@@ -72,4 +62,4 @@ class RidingProperties(
fun hasStat(stat: RidingStat, style: RidingStyle): Boolean {
return stats[stat]?.ranges?.containsKey(style) == true
}
}
}
@@ -18,5 +18,6 @@ package com.cobblemon.mod.common.api.riding
enum class RidingStyle {
LAND,
LIQUID,
AIR
AIR,
COMPOSITE
}
@@ -28,8 +28,7 @@ import net.minecraft.world.phys.Vec3
*/
interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBehaviourState> {
val key: ResourceLocation
fun getRidingStyle(settings: Settings, state: State): RidingStyle
val style: RidingStyle
fun isActive(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
@@ -74,7 +73,7 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
fun useAngVelSmoothing(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): ResourceLocation
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
fun inertia(settings: Settings, state: State, vehicle: PokemonEntity): Double
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.riding.behaviour
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
@@ -26,10 +25,7 @@ import net.minecraft.world.phys.Vec3
class RidingController<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(val behaviour: RidingBehaviour<Settings, State>) : RidingBehaviour<Settings, State> {
override val key = behaviour.key
override fun getRidingStyle(settings: Settings, state: State): RidingStyle {
return behaviour.getRidingStyle(settings, state)
}
override val style = behaviour.style
override fun isActive(settings: Settings, state: State, vehicle: PokemonEntity) =
behaviour.isActive(settings, state, vehicle)
@@ -139,8 +135,8 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
return behaviour.inertia(settings, state, vehicle)
}
override fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): ResourceLocation {
if (!isActive(settings, state, vehicle)) return cobblemonResource("no_pose")
override fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean {
if (!isActive(settings, state, vehicle)) return false
return behaviour.useRidingAltPose(settings, state, vehicle, driver)
}
@@ -179,5 +175,4 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
return behaviour.createDefaultState(settings)
}
}
@@ -18,10 +18,7 @@ import com.cobblemon.mod.common.api.riding.posing.PoseOption
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.minecraft.client.Minecraft
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
@@ -30,6 +27,8 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import org.joml.Matrix3f
import org.joml.Quaternionf
import org.joml.Vector3f
import kotlin.math.*
@@ -39,10 +38,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
override val key: ResourceLocation = KEY
override fun getRidingStyle(settings: BirdAirSettings, state: BirdAirState): RidingStyle {
return RidingStyle.AIR
}
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<BirdAirSettings, BirdAirState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
@@ -114,7 +110,6 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
upForce = if (vehicle.y >= altitudeLimit && upForce > 0) 0.0 else upForce
}
val velocity = Vec3(state.rideVelocity.get().x , upForce, forwardForce)
return velocity
}
@@ -159,7 +154,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
if (controller != null) {
//Base glide speed change on current pitch of the ride.
glideSpeedChange = sin(Math.toRadians(controller.pitch.toDouble()))
glideSpeedChange = glideSpeedChange * 0.25
glideSpeedChange = glideSpeedChange.pow(3) * 0.5
//TODO: Possibly create a deadzone around parallel where glide doesn't affect speed?
if (glideSpeedChange <= 0.0) {
@@ -186,6 +181,22 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
}
}
//Lateral movement based on driver input.
// val latTopSpeed = topSpeed / 2.0
// if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
// newVelocity = Vec3(
// (newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
// newVelocity.y,
// newVelocity.z)
// activeInput = true
// }
// else {
// newVelocity = Vec3(
// lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
// newVelocity.y,
// newVelocity.z)
// }
//Vertical movement based on driver input.
val vertTopSpeed = topSpeed / 2.0
val vertInput = when {
@@ -258,21 +269,33 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
val rotMin = 15.0
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
var yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
val rotationChangeRate = 100.0
var yawForce = rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble()))
//for a bit of correction on the rolls limit it to a quarter the amount
var pitchForce = -0.35 * rotationChangeRate * abs(sin(Math.toRadians(controller.roll.toDouble())))
//limit rotation modulation when pitched up heavily or pitched down heavily
yawForce *= abs(cos(Math.toRadians(controller.pitch.toDouble())))
pitchForce *= abs(cos(Math.toRadians(controller.pitch.toDouble()))) * 1.5
var yawDeltaDeg = deltaTime * rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))
//val pitchedYawDelt = yawDeltaDeg - trueYawDelt
controller.applyGlobalYaw(trueYawDelt.toFloat())
//Calculate correcting roll force.
val correctionRate = 5.0
if(abs(controller.roll) > rotLimit && state.rideVelocity.get().length() < 0.2) {
//Calculate correcting roll force.
if(abs(controller.roll) > rotLimit) {
state.currRollCorrectionForce.set(
state.currRollCorrectionForce.get() + ((abs(controller.roll) - rotLimit) / 180 - rotLimit) * controller.roll.sign * correctionRate * deltaTime * 0.01
)
} else {
state.currRollCorrectionForce.set(
//reduce rollCorrection gradually
//reduce rollCorrection gradually and make sure to
//state.currRollCorrectionForce.get() - max(correctionRate * deltaTime * 0.04, abs(state.currRollCorrectionForce.get())) * state.currRollCorrectionForce.get().sign
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
)
}
@@ -312,7 +335,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
val rotMin = 15.0
var rollForce = xInput
val rotLimit = max(90 * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
//Limit roll by non linearly decreasing inputs towards
// a rotation limit based on the current distance from
@@ -323,12 +346,12 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
val d = abs(abs(controller.roll) - rotLimit)
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
}
} else { //if (sign(rollForce) == sign(controller.roll).toDouble()) {
rollForce *= max(abs(sin(controller.pitch.toRadians())),0.1f)
} else if (sign(rollForce) == sign(controller.roll).toDouble()) {
rollForce = 0.0
}
//Give the ability to yaw with x mouse input when at low speeds.
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
//Yaw locally a bit when up or down so that its more intuitive to make it out of a dive or a straight vertical
//climb
@@ -336,24 +359,10 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
if (controller.upVector.dot(Vector3f(0f,1f,0f)) > 0) {
controller.applyGlobalYaw(yawForce.toFloat())
}
// Pitch up globally
controller.applyGlobalPitch(-1 * yInput.toFloat())
// roll to 0 if pitching and not upside down. This is to prevent odd back and forth wobbling when
// pitching globally and experiencing axis changes
if (controller.upVector.dot(Vector3f(0f,1f,0f)) > 0) {
// correct roll equal to the amount the ride is pitching (yInput)
// correct roll only when near to horizontal (cos(pitch))
// correct roll proportional to how rolled the ride currently is
rollForce += controller.roll * -0.01 * abs(yInput) * abs(cos(controller.pitch.toRadians())) * abs(sin(controller.roll.toRadians()))
}
controller.applyGlobalYaw(yawForce.toFloat())
//yaw, pitch, roll
return Vec3(0.0, 0.0, rollForce)
return Vec3(yawForcePitched, yInput, rollForce)
}
/*
@@ -432,11 +441,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
state: BirdAirState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
if (state.gliding.get()) {
return cobblemonResource("gliding")
}
return cobblemonResource("no_pose")
): Boolean {
return state.gliding.get()
}
override fun inertia(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Double {
@@ -468,7 +474,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
state: BirdAirState,
vehicle: PokemonEntity
): Boolean {
return true
return false
}
override fun createDefaultState(settings: BirdAirSettings) = BirdAirState()
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
@@ -36,10 +35,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
}
override val key = KEY
override fun getRidingStyle(settings: DolphinSettings, state: DolphinState): RidingStyle {
return RidingStyle.LIQUID
}
override val style = RidingStyle.LIQUID
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
@@ -225,8 +221,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
state: DolphinState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Double {
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.riding.behaviour.types
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangMath.lerp
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.*
import com.cobblemon.mod.common.api.riding.posing.PoseOption
@@ -16,14 +17,10 @@ import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.core.Direction
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
@@ -36,14 +33,11 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
override val key = KEY
override fun getRidingStyle(settings: GenericLandSettings, state: GenericLandState): RidingStyle {
return RidingStyle.LAND
}
override val style = RidingStyle.LAND
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, state, _ ->
return@PoseOption abs(state.rideVelocity.get().z) > 0.0
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
})
override fun isActive(
@@ -79,25 +73,6 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
vehicle: PokemonEntity,
driver: Player
): Float {
// Use this as a "tick" function and calculate sprinting and inAir state here
state.sprinting.set(driver.isSprinting)
// Check both vertical movement and if there are blocks below.
val posBelow = vehicle.blockPosition().below()
val blockStateBelow = vehicle.level().getBlockState(posBelow)
val isAirOrLiquid = blockStateBelow.isAir || !blockStateBelow.fluidState.isEmpty
val canSupportEntity = blockStateBelow.isFaceSturdy(vehicle.level(), posBelow, Direction.UP)
val standingOnSolid = canSupportEntity && !isAirOrLiquid
// val level = vehicle.level()
// val toesBox = vehicle.boundingBox.move(0.0, -0.1, 0.0)
// inAir if not on the ground
val inAir = !(vehicle.deltaMovement.y == 0.0 || standingOnSolid)
state.inAir.set(inAir)
return state.rideVelocity.get().length().toFloat()
}
@@ -167,11 +142,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
driver: LivingEntity
): Float {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
//In degrees per second
val walkHandling = 140.0 * 2
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * 2
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
@@ -186,8 +158,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
//Take the inverse so that you turn less at higher speeds
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
// TurnRate should always be quick if not sprinting
val turnRate = if(state.sprinting.get()) (handling.toFloat() / 20.0f) else (walkHandling.toFloat() / 20.0f)
// TODO: This needs to be tweaked with in game results and testing
val turnRate = (handling.toFloat() / 20.0f) * 2
//Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod * normSpeed
@@ -204,8 +176,26 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
driver: Player,
input: Vec3
): Vec3 {
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
return state.rideVelocity.get()
//Limit horizontal velocity that may have accumulated through alternate behaviour
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val currVel = state.rideVelocity.get()
// state.rideVelocity.set(Vec3(
// max(currVel.x, topSpeed),
// currVel.y,
// max(currVel.z, topSpeed)
// ))
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
//This is cheap.
//Also make it stop quicker the slower it is.
val maxSpeed = 1.0
//state.currVel = state.currVel.lerp( Vec3(0.0, state.currVel.y, 0.0), 1.0/20.0 )
//entity.deltaMovement = entity.deltaMovement.lerp(velocity, 1.0)
//state.currVel = state.currVel.add( f.toDouble() / 20.0, gravity / 20.0 , g.toDouble() / 20.0)
return state.rideVelocity.get()
}
private fun calculateRideSpaceVel(
@@ -214,13 +204,9 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
vehicle: PokemonEntity,
driver: Player
): Vec3 {
// Check to see if the ride should be walking or sprinting
val walkSpeed = getWalkSpeed(vehicle)
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val topSpeed = if(state.sprinting.get()) rideTopSpeed else walkSpeed
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
val speed = state.rideVelocity.get().length()
//Flag for determining if player is actively inputting
var activeInput = false
@@ -257,19 +243,18 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
}
//ground Friction
if( (newVelocity.horizontalDistance() > 0 && vehicle.onGround() && !activeInput) || newVelocity.horizontalDistance() > topSpeed) {
if( abs(newVelocity.z) > 0 && vehicle.onGround() && !activeInput) {
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.03 * newVelocity.z.sign, newVelocity.z))
}
//Jump the thang!
if (driver.jumping && vehicle.onGround()) {
val jumpForce = 1.0
val horz = state.rideVelocity.get().horizontalDistance()
newVelocity = newVelocity.add(0.0, jumpForce, 0.0)
val jumpVel = 1.0
newVelocity = newVelocity.add(0.0, 1.0, 0.0)
//Ensure this doesn't add unwanted forward velocity
//val mag = if(newVelocity.length() < rideTopSpeed) newVelocity.length() else rideTopSpeed
//newVelocity = newVelocity.normalize().scale(mag)
val mag = if(newVelocity.length() < topSpeed) newVelocity.length() else topSpeed
newVelocity = newVelocity.normalize().scale(mag)
}
return newVelocity
@@ -284,14 +269,6 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
}
private fun getWalkSpeed( vehicle: PokemonEntity ): Double {
val walkspeed = vehicle.runtime.resolveDouble(vehicle.behaviour.moving.walk.walkSpeed)
val movementSpeed = vehicle.attributes.getValue(Attributes.MOVEMENT_SPEED)
val speedModifier = 1.2 * 0.35
return walkspeed * movementSpeed * speedModifier
}
override fun angRollVel(
settings: GenericLandSettings,
state: GenericLandState,
@@ -383,12 +360,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
state: GenericLandState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
when {
state.inAir.get() -> cobblemonResource("in_air")
state.sprinting.get() -> return cobblemonResource("sprinting")
}
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(
@@ -396,7 +369,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
state: GenericLandState,
vehicle: PokemonEntity
): Double {
return 1.0
return 0.5
}
override fun shouldRoll(
@@ -436,7 +409,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
state: GenericLandState,
vehicle: PokemonEntity
): Boolean {
return true
return false
}
override fun createDefaultState(settings: GenericLandSettings) = GenericLandState()
@@ -487,38 +460,15 @@ class GenericLandSettings : RidingBehaviourSettings {
}
class GenericLandState : RidingBehaviourState() {
var sprinting = ridingState(false, Side.CLIENT)
var inAir = ridingState(false, Side.CLIENT)
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
buffer.writeBoolean(sprinting.get())
buffer.writeBoolean(inAir.get())
}
override fun decode(buffer: FriendlyByteBuf) {
super.decode(buffer)
sprinting.set(buffer.readBoolean(), forced = true)
inAir.set(buffer.readBoolean(), forced = true)
}
override fun reset() {
super.reset()
sprinting.set(false, forced = true)
inAir.set(false, forced = true)
}
var currSpeed = ridingState(0.0, Side.BOTH)
override fun copy() = GenericLandState().also {
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
it.stamina.set(this.stamina.get(), forced = true)
it.sprinting.set(this.sprinting.get(), forced = true)
it.inAir.set(this.inAir.get(), forced = true)
}
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is GenericLandState) return false
if (previous.sprinting.get() != sprinting.get()) return true
if (previous.inAir.get() != inAir.get()) return true
return super.shouldSync(previous)
}
}
@@ -35,10 +35,7 @@ class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviou
}
override val key = KEY
override fun getRidingStyle(settings: GenericSwimSettings, state: RidingBehaviourState): RidingStyle {
return RidingStyle.LIQUID
}
override val style = RidingStyle.LIQUID
val poseProvider = PoseProvider<GenericSwimSettings, RidingBehaviourState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
@@ -179,8 +176,8 @@ class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviou
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
@@ -35,13 +35,10 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override val key = KEY
override fun getRidingStyle(settings: GliderAirSettings, state: RidingBehaviourState): RidingStyle {
return RidingStyle.AIR
}
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<GliderAirSettings, RidingBehaviourState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
override fun isActive(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
return true
@@ -56,20 +53,20 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun rotation(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: LivingEntity
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: LivingEntity
): Vec2 {
return Vec2(driver.xRot, driver.yRot)
}
override fun velocity(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
input: Vec3
): Vec3 {
val xVector = if (vehicle.runtime.resolveBoolean(settings.canStrafe)) driver.xxa.toDouble() else 0.0
val yVector = -vehicle.runtime.resolveDouble(settings.glideSpeed)
@@ -80,26 +77,26 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun angRollVel(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
deltaTime: Double
): Vec3 {
return Vec3.ZERO
}
override fun rotationOnMouseXY(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
mouseX: Double,
mouseYSmoother: SmoothDouble,
mouseXSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
mouseY: Double,
mouseX: Double,
mouseYSmoother: SmoothDouble,
mouseXSmoother: SmoothDouble,
sensitivity: Double,
deltaTime: Double
): Vec3 {
if (driver !is OrientationControllable) return Vec3.ZERO
@@ -114,38 +111,38 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
}
override fun setRideBar(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 0.0f
}
override fun jumpForce(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player,
jumpStrength: Int
): Vec3 {
return Vec3.ZERO
}
override fun gravity(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
regularGravity: Double
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
regularGravity: Double
): Double {
return 0.0
}
override fun rideFovMultiplier(
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
settings: GliderAirSettings,
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): Float {
return 1.0f
}
@@ -159,8 +156,8 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
@@ -39,10 +39,7 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
}
override val key = KEY
override fun getRidingStyle(settings: HelicopterSettings, state: RidingBehaviourState): RidingStyle {
return RidingStyle.AIR
}
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<HelicopterSettings, RidingBehaviourState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
@@ -240,8 +237,8 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
state: RidingBehaviourState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: HelicopterSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.api.riding.behaviour.types
import com.bedrockk.molang.Expression
import com.bedrockk.molang.runtime.MoLangMath.lerp
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.*
import com.cobblemon.mod.common.api.riding.posing.PoseOption
@@ -16,20 +17,14 @@ import com.cobblemon.mod.common.api.riding.posing.PoseProvider
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.util.math.geometry.toRadians
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.Mth
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import net.minecraft.world.phys.shapes.Shapes
import org.joml.Matrix3f
import org.joml.Vector3f
import kotlin.math.*
class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
@@ -38,10 +33,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
}
override val key = KEY
override fun getRidingStyle(settings: HoverSettings, state: HoverState): RidingStyle {
return RidingStyle.AIR
}
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, state, _ ->
@@ -151,7 +143,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
): Float {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
//In degrees per second
val handling = 220.0
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
val maxYawDiff = 90.0f
//Normalize the current rotation diff
@@ -166,7 +158,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
//Take the inverse so that you turn less at higher speeds
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
val turnRate = (handling.toFloat() / 20.0f)
// TODO: This needs to be tweaked with in game results and testing
val turnRate = (handling.toFloat() / 20.0f) * 2
//Ensure you only ever rotate as much difference as there is between the angles.
val turnSpeed = turnRate * rotDiffMod * normSpeed
@@ -175,6 +168,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
return rotAmount
}
override fun velocity(
settings: HoverSettings,
state: HoverState,
@@ -183,35 +177,14 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
input: Vec3
): Vec3 {
// if (Minecraft.getInstance().options.keySprint.isDown) {
// val belowBox = vehicle.boundingBox.expandTowards(0.0,-1.5, 0.0).inflate(5.0, 10.0,5.0)
//
// val level = vehicle.level()
// val toBeSucked = level.getEntities(vehicle, belowBox)
// for (suckee in toBeSucked) {
// if (suckee != null) {
// abductify(suckee, vehicle.position().add(0.0,-2.0,0.0))
// suckee.deltaMovement = suckee.deltaMovement.add(0.0, 0.5,0.0)
//
// }
// }
// }
val strafeFactor = 0.2
val f = driver.xxa * strafeFactor
var g = driver.zza
if (g <= 0.0f) {
g *= -1.0f
}
//
// if (firstEntity != null) {
// // Example action: print the entity name
// println("Found nearby entity: ${firstEntity.name.string}")
//
// firstEntity.deltaMovement = firstEntity.deltaMovement.add(0.0, 0.1,0.0)
// }
val retVel = calculateRideSpaceVel(settings, state, vehicle, driver)
//state.rideVelocity.set(retVel)
return retVel
}
private fun abductify(abductee: Entity, pos: Vec3) {
val diff = pos.subtract(abductee.position()).scale(1.0)
abductee.deltaMovement = abductee.deltaMovement.add(diff)
return calculateRideSpaceVel(settings, state, vehicle, driver).scale(10.0)
}
private fun calculateRideSpaceVel(
@@ -222,27 +195,24 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
): Vec3 {
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
val speed = vehicle.deltaMovement.length()
val speed = state.rideVelocity.get().length()
//Flag for determining if player is actively inputting
var activeInput = false
val minSpeed = 0.0
var newVelocity = vehicle.deltaMovement
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
val yawAligned = Matrix3f().rotateY(vehicle.yRot.toRadians())
newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
//air Resistance
//newVelocity = newVelocity.lerp(Vec3.ZERO,(((topSpeed - speed) / topSpeed))*0.001)
var jumpVec = Vec3.ZERO
//speed up and slow down based on input
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
//make sure it can't exceed top speed
val forwardInput = when {
speed > topSpeed && (driver.zza.sign == newVelocity.z.sign.toFloat()) -> 0.0
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
else -> driver.zza.sign
}
@@ -251,60 +221,48 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
newVelocity.y,
(newVelocity.z + (accel * forwardInput.toDouble())))
} else {
// newVelocity = Vec3(
// newVelocity.x,
// newVelocity.y,
// newVelocity.z - (((topSpeed - speed) / topSpeed)*0.001)
// )
activeInput = true
jumpVec = jumpVec.add(0.0, 0.0, forwardInput.toDouble())
}
//speed up and slow down based on input
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
//make sure it can't exceed top speed
val lateralInput = when {
speed > topSpeed && (driver.xxa.sign == newVelocity.x.sign.toFloat()) -> 0.0
val forwardInput = when {
driver.xxa > 0 && newVelocity.x > topSpeed -> 0.0
driver.xxa < 0 && newVelocity.x < (-topSpeed / 3.0) -> 0.0
else -> driver.xxa.sign
}
newVelocity = Vec3(
newVelocity.x + (accel * lateralInput.toDouble()),
newVelocity.x + (accel * forwardInput.toDouble()),
newVelocity.y,
(newVelocity.z ))
//air resistance
// if (lateralInput == 0.0) {
// newVelocity = Vec3(
// newVelocity.x - (((topSpeed - speed) / topSpeed)*0.001),
// newVelocity.y,
// newVelocity.z
// )
// }
activeInput = true
}
//Vertical movement based on driver input.
val vertTopSpeed = topSpeed / 2.0
val vertInput = when {
driver.jumping && !(speed > topSpeed && (newVelocity.y.sign.toFloat() > 0.0))-> 1.0
driver.isShiftKeyDown && !(speed > topSpeed && (newVelocity.y.sign.toFloat() < 0.0))-> -1.0
driver.jumping -> 1.0
driver.isShiftKeyDown -> -1.0
else -> 0.0
}
//air resistance
// if (vertInput == 0.0) {
// newVelocity = Vec3(
// newVelocity.x,
// newVelocity.y - (((topSpeed - speed) / topSpeed)*0.001),
// newVelocity.z
// )
// }
if (state.stamina.get() > 0.0) {
if (vertInput != 0.0 && state.stamina.get() > 0.0) {
newVelocity = Vec3(
newVelocity.x,
(newVelocity.y + (accel * vertInput)), //.coerceIn(-vertTopSpeed, vertTopSpeed),
(newVelocity.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
newVelocity.z)
activeInput = true
}
//air Friction
return newVelocity
}
@@ -408,8 +366,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
state: HoverState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(
@@ -417,7 +375,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
state: HoverState,
vehicle: PokemonEntity
): Double {
return 1.0
return 0.05
}
override fun shouldRoll(
@@ -469,12 +427,12 @@ class HoverSettings : RidingBehaviourSettings {
var canJump = "true".asExpression()
private set
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 0.65, 0.3)".asExpression()
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.3)".asExpression()
private set
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
var accelerationExpr: Expression =
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 3.0)))".asExpression()
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
private set
// Between 30 seconds and 10 seconds at the lowest when at full speed.
@@ -20,7 +20,6 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import com.bedrockk.molang.runtime.MoLangMath.lerp
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.SmoothDouble
import net.minecraft.world.entity.LivingEntity
@@ -36,10 +35,7 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
}
override val key = KEY
override fun getRidingStyle(settings: JetAirSettings, state: JetAirState): RidingStyle {
return RidingStyle.AIR
}
override val style = RidingStyle.AIR
val poseProvider = PoseProvider<JetAirSettings, JetAirState>(PoseType.HOVER)
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
@@ -178,7 +174,7 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel) / 4), minSpeed)))
} else if (driver.zza < 0.0 && speed > minSpeed) {
//modify deccel to be slower when at closer speeds to minimum speed
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 4, 0.1)
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 8, 0.1)
//Decelerate currently always a constant half of max acceleration.
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel * deccelMod) / 2), minSpeed)))
@@ -230,8 +226,13 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
// Accumulate the mouse input
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
// Smooth out and accumulate roll input
val smoothingSpeed = 4.0
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
// Accumulate the y mouse input for pitch
//state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY * invertPitch)).coerceIn(-1.0, 1.0))
//Get handling in degrees per second
@@ -252,24 +253,12 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
val pitchRot = handling * state.currMouseYForce.get()
// Roll
val rollRot = handling * 1.5 * state.currMouseXForce.get()
val mouseRotation = Vec3(0.0, pitchRot, rollRot)
// Have accumulated input begin decay when no input detected
if(abs(mouseX) == 0.0) {
// Have decay on roll be much stronger.
state.currMouseXForce.set(lerp( state.currMouseXForce.get(), 0.0, 0.02 ))
}
if(mouseY == 0.0) {
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005 ))
}
//Roll is 1.5 times as fast as pitch
//val rollRot = handling * 1.5 * state.currMouseXForce.get()
val rollRot = handling * 1.5 * xInput.coerceIn(-1.0,1.0)
//yaw, pitch, roll
return mouseRotation
return Vec3(0.0, pitchRot, rollRot)
}
override fun canJump(
@@ -335,12 +324,12 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
state: JetAirState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Double {
return 1.0
return 0.5
}
override fun shouldRoll(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
@@ -376,7 +365,7 @@ class JetAirSettings : RidingBehaviourSettings {
var gravity: Expression = "0".asExpression()
private set
var minSpeed: Expression = "1.2".asExpression()
var minSpeed: Expression = "0.8".asExpression()
private set
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
@@ -34,10 +34,7 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
}
override val key = KEY
override fun getRidingStyle(settings: SwimDashSettings, state: SwimDashState): RidingStyle {
return RidingStyle.LIQUID
}
override val style = RidingStyle.LIQUID
val poseProvider = PoseProvider<SwimDashSettings, SwimDashState>(PoseType.FLOAT)
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
@@ -186,8 +183,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
state: SwimDashState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Double {
@@ -53,10 +53,7 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
}
override val key = KEY
override fun getRidingStyle(settings: VehicleLandSettings, state: VehicleLandState): RidingStyle {
return RidingStyle.LAND
}
override val style = RidingStyle.LAND
val poseProvider = PoseProvider<VehicleLandSettings, VehicleLandState>(PoseType.STAND)
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
@@ -225,8 +222,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
state: VehicleLandState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
return cobblemonResource("no_pose")
): Boolean {
return false
}
override fun inertia(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Double {
@@ -30,14 +30,8 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
}
override val key = KEY
override val style = RidingStyle.COMPOSITE
override fun getRidingStyle(settings: CompositeSettings, state: CompositeState): RidingStyle {
return chooseBehaviour(settings, state) {
behaviour, behaviourSettings, behaviourState ->
behaviour.getRidingStyle(behaviourSettings, behaviourState)
}
}
override fun createDefaultState(settings: CompositeSettings): CompositeState {
val defaultBehaviour = RidingBehaviours.get(settings.defaultBehaviour.key)
val defaultState = defaultBehaviour.createDefaultState(settings.defaultBehaviour)
@@ -57,7 +51,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
): T {
val defaultBehaviour = RidingBehaviours.get(settings.defaultBehaviour.key)
val alternativeBehaviour = RidingBehaviours.get(settings.alternateBehaviour.key)
return when (state.activeBehaviour.get()) {
return when (state.activeController.get()) {
settings.defaultBehaviour.key -> action(
defaultBehaviour,
settings.defaultBehaviour,
@@ -69,7 +63,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
state.alternateBehaviourState
)
else -> error("Invalid controller: ${state.activeBehaviour.get()}")
else -> error("Invalid controller: ${state.activeController.get()}")
}
}
@@ -171,7 +165,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
state: CompositeState,
vehicle: PokemonEntity,
driver: Player
): ResourceLocation {
): Boolean {
return chooseBehaviour(settings, state) { behaviour, behaviourSettings, behaviourState ->
behaviour.useRidingAltPose(behaviourSettings, behaviourState, vehicle, driver)
}
@@ -370,28 +364,28 @@ open class CompositeSettings : RidingBehaviourSettings {
}
class CompositeState(
val defaultBehaviour: ResourceLocation,
private val defaultBehaviour: ResourceLocation,
val defaultBehaviourState: RidingBehaviourState,
val alternateBehaviourState: RidingBehaviourState
) : RidingBehaviourState() {
var activeBehaviour = ridingState(defaultBehaviour, Side.CLIENT)
var activeController = ridingState(defaultBehaviour, Side.CLIENT)
var lastTransition = ridingState(-100L, Side.BOTH)
override val rideVelocity: SidedRidingState<Vec3>
get() = when (activeBehaviour.get()) {
get() = when (activeController.get()) {
defaultBehaviour -> defaultBehaviourState.rideVelocity
else -> alternateBehaviourState.rideVelocity
}
override val stamina: SidedRidingState<Float>
get() = when (activeBehaviour.get()) {
get() = when (activeController.get()) {
defaultBehaviour -> defaultBehaviourState.stamina
else -> alternateBehaviourState.stamina
}
override fun reset() {
super.reset()
activeBehaviour.set(defaultBehaviour, forced = true)
activeController.set(defaultBehaviour, forced = true)
lastTransition.set(-100L, forced = true)
defaultBehaviourState.reset()
alternateBehaviourState.reset()
@@ -400,7 +394,7 @@ class CompositeState(
override fun copy(): CompositeState {
val state =
CompositeState(defaultBehaviour, defaultBehaviourState.copy(), alternateBehaviourState.copy())
state.activeBehaviour.set(activeBehaviour.get(), forced = true)
state.activeController.set(activeController.get(), forced = true)
state.lastTransition.set(lastTransition.get(), forced = true)
state.rideVelocity.set(rideVelocity.get(), forced = true)
state.stamina.set(stamina.get(), forced = true)
@@ -409,7 +403,7 @@ class CompositeState(
override fun shouldSync(previous: RidingBehaviourState): Boolean {
if (previous !is CompositeState) return false
if (previous.activeBehaviour.get() != activeBehaviour.get()) return true
if (previous.activeController.get() != activeController.get()) return true
if (defaultBehaviourState.shouldSync(previous.defaultBehaviourState)) return true
if (alternateBehaviourState.shouldSync(previous.alternateBehaviourState)) return true
return super.shouldSync(previous)
@@ -417,14 +411,14 @@ class CompositeState(
override fun encode(buffer: FriendlyByteBuf) {
super.encode(buffer)
buffer.writeResourceLocation(activeBehaviour.get())
buffer.writeResourceLocation(activeController.get())
defaultBehaviourState.encode(buffer)
alternateBehaviourState.encode(buffer)
}
override fun decode(buffer: FriendlyByteBuf) {
super.decode(buffer)
activeBehaviour.set(buffer.readResourceLocation(), forced = true)
activeController.set(buffer.readResourceLocation(), forced = true)
defaultBehaviourState.decode(buffer)
alternateBehaviourState.decode(buffer)
}
@@ -44,10 +44,10 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
toState.stamina.set(fromState.stamina.get())
toState.rideVelocity.set(fromState.rideVelocity.get())
fromState.reset()
state.activeBehaviour.set(toSettings.key)
state.activeController.set(toSettings.key)
state.lastTransition.set(vehicle.level().gameTime)
val behaviour = RidingBehaviours.get(toSettings.key)
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, behaviour.getRidingStyle(toSettings, toState) == RidingStyle.AIR)
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, behaviour.style == RidingStyle.AIR)
}
}
@@ -9,11 +9,13 @@
package com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies
import com.bedrockk.molang.Expression
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.*
import net.minecraft.network.RegistryFriendlyByteBuf
@@ -45,7 +47,7 @@ object FallStrategy : CompositeRidingStrategy<FallCompositeSettings> {
defaultSettings: RidingBehaviourSettings,
vehicle: PokemonEntity
): Boolean {
if (state.activeBehaviour.get() == defaultSettings.key) return false
if (state.activeController.get() == defaultSettings.key) return false
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
if (!vehicle.onGround()) return false
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
@@ -59,7 +61,7 @@ object FallStrategy : CompositeRidingStrategy<FallCompositeSettings> {
vehicle: PokemonEntity,
driver: Player
): Boolean {
if (state.activeBehaviour.get() == alternateSettings.key) return false
if (state.activeController.get() == alternateSettings.key) return false
if (!driver.jumping) return false
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
@@ -8,11 +8,13 @@
package com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies
import com.cobblemon.mod.common.api.riding.RidingStyle
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeSettings
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.util.cobblemonResource
import net.minecraft.world.entity.player.Player
@@ -43,7 +45,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
defaultSettings: RidingBehaviourSettings,
vehicle: PokemonEntity
): Boolean {
if (state.activeBehaviour.get() == defaultSettings.key) return false
if (state.activeController.get() == defaultSettings.key) return false
if (!vehicle.onGround()) return false
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
@@ -56,7 +58,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
vehicle: PokemonEntity,
driver: Player
): Boolean {
if (state.activeBehaviour.get() == alternativeSettings.key) return false
if (state.activeController.get() == alternativeSettings.key) return false
if (!driver.jumping) return false
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
val alternativeBehaviour = RidingBehaviours.get(alternativeSettings.key)
@@ -45,7 +45,7 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
entity: PokemonEntity,
driver: Player
): Boolean {
if (state.activeBehaviour.get() == defaultSettings.key) return false
if (state.activeController.get() == defaultSettings.key) return false
if (!entity.onGround()) return false
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
@@ -60,7 +60,7 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
driver: Player,
input: Vec3
): Boolean {
if (state.activeBehaviour.get() == alternativeSettings.key) return false
if (state.activeController.get() == alternativeSettings.key) return false
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
val alternativeBehaviour = RidingBehaviours.get(alternativeSettings.key)
return driver.isSprinting && input.z > 0.5 && alternativeBehaviour.isActive(alternativeSettings, state.alternateBehaviourState, entity)
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.riding.stats
import com.cobblemon.mod.common.api.cooking.Flavour
import com.cobblemon.mod.common.api.berry.Flavor
import com.cobblemon.mod.common.util.lang
import net.minecraft.network.chat.Component
@@ -19,13 +19,13 @@ import net.minecraft.network.chat.Component
* @since February 17th, 2025
*/
enum class RidingStat(
val flavour: Flavour
val flavour: Flavor
) {
SPEED(Flavour.SWEET),
ACCELERATION(Flavour.SPICY),
SKILL(Flavour.DRY),
JUMP(Flavour.BITTER),
STAMINA(Flavour.SOUR);
SPEED(Flavor.SWEET),
ACCELERATION(Flavor.SPICY),
SKILL(Flavor.DRY),
JUMP(Flavor.BITTER),
STAMINA(Flavor.SOUR);
companion object {
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
@@ -43,12 +43,12 @@ class RidingStatDefinition {
buffer.writeNullable(displayName) { _, it -> buffer.writeText(it) }
buffer.writeNullable(description) { _, it -> buffer.writeText(it) }
buffer.writeMap(
ranges,
{ _, it -> buffer.writeEnum(it) },
{ _, it ->
buffer.writeSizedInt(IntSize.U_BYTE, it.first)
buffer.writeSizedInt(IntSize.U_BYTE, it.last)
}
ranges,
{ _, it -> buffer.writeEnum(it) },
{ _, it ->
buffer.writeSizedInt(IntSize.U_BYTE, it.first)
buffer.writeSizedInt(IntSize.U_BYTE, it.last)
}
)
}
@@ -57,8 +57,8 @@ class RidingStatDefinition {
val displayName = buffer.readNullable { buffer.readText() }
val description = buffer.readNullable { buffer.readText() }
val ranges = buffer.readMap<RidingStyle, IntRange>(
{ buffer.readEnum<RidingStyle>(RidingStyle::class.java) },
{ IntRange(buffer.readSizedInt(IntSize.U_BYTE), buffer.readSizedInt(IntSize.U_BYTE)) }
{ buffer.readEnum<RidingStyle>(RidingStyle::class.java) },
{ IntRange(buffer.readSizedInt(IntSize.U_BYTE), buffer.readSizedInt(IntSize.U_BYTE)) }
)
return RidingStatDefinition().apply {
this.displayName = displayName
@@ -39,10 +39,10 @@ class RidingAnimationData
var currRot = Vec3.ZERO
var angDelta = Vec3.ZERO
val stiffness = 90.0
val damping = 18.0
// val stiffness = 16.0
// val damping = 8.0
// val stiffness = 90.0
// val damping = 18.0
val stiffness = 16.0
val damping = 8.0
// Update velocity first
val currentVelocity = Vec3(
@@ -127,7 +127,6 @@ class ParticleEvent(
sourceAlive = storm.sourceAlive,
sourceVisible = storm.sourceVisible,
onDespawn = {},
getParticleColor = storm.getParticleColor,
targetPos = storm.targetPos,
runtime = MoLangRuntime().setup(),
entity = storm.entity
@@ -37,6 +37,7 @@ import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.config
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningInfluenceProspector
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
@@ -81,7 +79,6 @@ object CobblemonSpawningProspector : SpawningProspector {
val blocks = Array(area.length) { Array(height) { Array(area.width) { defaultBlockData } } }
val skyLevel = Array(area.length) { Array(area.width) { world.maxBuildHeight } }
val pos = BlockPos.MutableBlockPos()
val worldSlicedSpawningInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
val chunks = mutableMapOf<Pair<Int, Int>, ChunkAccess?>()
val yRange = (baseY until baseY + height).reversed()
@@ -101,7 +98,6 @@ object CobblemonSpawningProspector : SpawningProspector {
light = world.getMaxLocalRawBrightness(pos),
skyLight = skyLight
)
worldSlicedSpawningInfluences.addAll(SpawningInfluenceProspector.prospectors.mapNotNull { it.prospectBlock(world, pos, state) })
if (canSeeSky) {
skyLevel[x - area.baseX][z - area.baseZ] = y
}
@@ -112,10 +108,6 @@ object CobblemonSpawningProspector : SpawningProspector {
}
}
for (prospector in SpawningInfluenceProspector.prospectors) {
worldSlicedSpawningInfluences.addAll(prospector.prospect(spawner, area))
}
return WorldSlice(
cause = area.cause,
world = world,
@@ -124,8 +116,7 @@ object CobblemonSpawningProspector : SpawningProspector {
baseZ = area.baseZ,
blocks = blocks,
skyLevel = skyLevel,
nearbyEntityPositions = nearbyEntityPositions,
influences = worldSlicedSpawningInfluences
nearbyEntityPositions = nearbyEntityPositions
)
}
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.util.weightedSelection
object SpawnBucketUtils {
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, bucketLureStrength: Int): SpawnBucket {
val baseValues = listOf(88.5F, 8.5F, 2.4F, 0.6F)
val adjustments = listOf(-6.9F, 3.6F, 2.3F, 1F)
val adjustedWeights = buckets.mapIndexed { index, bucket ->
if (index >= baseValues.size) {
bucket to bucket.weight
} else {
val base = baseValues[index]
val adjustment = adjustments[index]
val adjusted = base + adjustment * bucketLureStrength
bucket to adjusted.coerceAtLeast(0f) // we do not want the weights to be negative
}
}.toMap()
return buckets.weightedSelection { adjustedWeights[it]!! }!!
}
}
@@ -9,8 +9,6 @@
package com.cobblemon.mod.common.api.spawning
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
@@ -37,8 +35,7 @@ class WorldSlice(
val baseZ: Int,
val blocks: Array<Array<Array<BlockData>>>,
val skyLevel: Array<Array<Int>>,
var nearbyEntityPositions: List<Vec3>,
val influences: List<WorldSlicedSpawningInfluence>
var nearbyEntityPositions: List<Vec3>
) {
class BlockData(
val state: BlockState,
@@ -55,7 +55,7 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
}
}
if (bait != null) { // check for the bait on the bobber
val pokerodBait = ctx.baitStack.itemHolder.unwrapKey().orElse(null)?.location()
val pokerodBait = ctx.rodBait?.item
if (pokerodBait != bait) {
return false
}
@@ -66,6 +66,16 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
return false
}
}
/*if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
val pokerodItem = (ctx as FishingSpawningContext).rodItem
// todo check if the EV yield of the berry matches the bait EV attract maybe?
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
return false
}*/
return true
}
@@ -54,12 +54,6 @@ interface AreaContextResolver {
if (fittedContextCalculator != null) {
val context = fittedContextCalculator.calculate(input)
if (context != null) {
slice.influences.forEach {
if (it.appliesTo(context)) {
context.influences.add(it.influence)
}
}
contexts.add(context)
// The position BlockPos has been used in a context, editing the same one
// will cause entities to spawn at the wrong location (buried in walls, usually).
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.spawning.context
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.item.interactive.PokerodItem
import com.cobblemon.mod.common.util.toVec3d
import net.minecraft.world.level.block.Block
import net.minecraft.server.level.ServerLevel
@@ -41,5 +40,5 @@ class FishingSpawningContext(
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.map { it.block }.distinct().toList() }
val rodStack = cause.rodStack
val rodItem = cause.rodItem
val baitStack = PokerodItem.getBaitStackOnRod(cause.rodStack)
val rodBait = cause.bait
}
@@ -55,12 +55,13 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
CobblemonSpawnPools.onServerLoad(server)
}
precalculate()
this.observable.emit(this)
}
val details = mutableListOf<SpawnDetail>()
var precalculation: PrecalculationResult<*> = RootPrecalculation.generate(details, emptyList())
val precalculators = mutableListOf<SpawningPrecalculation<*>>()
// /** A set of all [RegisteredSpawningContext]s that are mentioned in this pool. */
// val contexts = mutableSetOf<RegisteredSpawningContext<*>>()
override fun iterator() = details.iterator()
@@ -12,24 +12,26 @@ import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.fishing.BobberSpawnPokemonEvent
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.fishing.FishingBait
import com.cobblemon.mod.common.api.pokemon.Natures
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.item.interactive.PokerodItem
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
import com.cobblemon.mod.common.util.cobblemonResource
import kotlin.random.Random.Default.nextInt
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.ItemStack
import kotlin.random.Random.Default.nextInt
/**
* A spawning cause that is embellished with fishing information. Could probably also
@@ -46,7 +48,7 @@ class FishingSpawnCause(
) : SpawnCause(spawner, bucket, entity) {
companion object {
const val FISHED_ASPECT = "fished"
fun shinyReroll(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun shinyReroll(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
if (pokemonEntity.pokemon.shiny) return
val shinyOdds = Cobblemon.config.shinyRate.toInt()
@@ -60,7 +62,7 @@ class FishingSpawnCause(
}
}
fun alterNatureAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun alterNatureAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
val baitStat = effect.subcategory?.let { it1 -> Stats.getStat(it1.path).identifier } ?: run {
LOGGER.warn("One of your nature baits is missing a subcategory and failed to effect a fished Pokemon")
return
@@ -74,7 +76,7 @@ class FishingSpawnCause(
pokemonEntity.pokemon.nature = Natures.getNature(takenNature.name.path) ?: return
}
fun alterIVAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun alterIVAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
val iv = effect.subcategory ?: return
if ((pokemonEntity.pokemon.ivs[Stats.getStat(iv.path)] ?: 0) + effect.value > 31) // if HP IV is already less than 3 away from 31
@@ -83,7 +85,7 @@ class FishingSpawnCause(
pokemonEntity.pokemon.ivs.set(Stats.getStat(iv.path), (pokemonEntity.pokemon.ivs[Stats.getStat(iv.path)] ?: 0) + (effect.value).toInt())
}
fun alterGenderAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun alterGenderAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
if (pokemonEntity.pokemon.species.maleRatio > 0 && pokemonEntity.pokemon.species.maleRatio < 1) // if the pokemon is allowed to be male or female
when (effect.subcategory) {
cobblemonResource("male") -> if (pokemonEntity.pokemon.gender != Gender.MALE) pokemonEntity.pokemon.gender = Gender.MALE
@@ -91,7 +93,7 @@ class FishingSpawnCause(
}
}
fun alterLevelAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun alterLevelAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
var level = pokemonEntity.pokemon.level + effect.value.toInt()
if (level > Cobblemon.config.maxPokemonLevel)
level = Cobblemon.config.maxPokemonLevel
@@ -122,7 +124,7 @@ class FishingSpawnCause(
}
fun alterFriendshipAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
fun alterFriendshipAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
if (pokemonEntity.pokemon.friendship + effect.value > Cobblemon.config.maxPokemonFriendship)
pokemonEntity.pokemon.setFriendship(Cobblemon.config.maxPokemonFriendship)
else
@@ -131,14 +133,18 @@ class FishingSpawnCause(
}
val rodItem = rodStack.item as? PokerodItem
// Determine the combined bait effects if any
val baitEffects = SpawnBaitInfluence(SpawnBaitEffects.getEffectsFromRodItemStack(rodStack))
val bait = PokerodItem.getBaitOnRod(rodStack)
override fun affectSpawn(entity: Entity) {
super.affectSpawn(entity)
if (entity is PokemonEntity) {
entity.pokemon.forcedAspects += FISHED_ASPECT
baitEffects.affectSpawn(entity)
bait?.effects?.forEach { it ->
if (Math.random() > it.chance) return
FishingBait.Effects.getEffectFunction(it.type)?.invoke(entity, it)
}
// Some of the bait actions might have changed the aspects and we need it to be
// in the entityData IMMEDIATELY otherwise it will flash as what it would be
// with the old aspects.
@@ -148,8 +154,68 @@ class FishingSpawnCause(
}
}
// EV related bait effects
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
val weight = baitEffects.affectWeight(detail, ctx, weight)
// if bait exists and any effects are related to EV yields
if (bait != null && bait.effects.any{ it.type == FishingBait.Effects.EV }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEVStat = bait.effects.firstOrNull { it.type == FishingBait.Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
if (detailSpecies != null && baitEVStat != null) {
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
return when {
evYieldValue > 0 -> super.affectWeight(detail, ctx, weight) // use original weight if EV yield is greater than 0
else -> super.affectWeight(detail, ctx, 0f) // use spawn weight of 0 if EV yield is 0
}
}
}
}
// if bait exists and any effects are related to Typing
if (bait != null && bait.effects.any{ it.type == FishingBait.Effects.TYPING }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEffect = bait.effects.firstOrNull { it.type == FishingBait.Effects.TYPING }
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
if (detailSpecies != null && baitTypingEffect != null) {
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
return when {
isMatchingType -> super.affectWeight(detail, ctx, weight * baitEffect.value.toFloat()) // multiply weight by multiplier of bait effect if typing is found
else -> super.affectWeight(detail, ctx, weight) // use base spawn weight if typing is not same as bait
}
}
}
}
// if bait exists and any effects are related to Egg Groups
if (bait != null && bait.effects.any { it.type == FishingBait.Effects.EGG_GROUP }) {
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
if (detailSpecies != null) {
// Collect all the egg group effects
val eggGroupEffects = bait.effects.filter { it.type == FishingBait.Effects.EGG_GROUP }
// Check if any of the egg group effects match the species' egg groups
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
if (eggGroup == null) {
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
return@firstOrNull false
}
detailSpecies.eggGroups.contains(eggGroup)
}
if (matchingEffect != null) {
val multiplier = matchingEffect.value
return super.affectWeight(detail, ctx, (weight * multiplier).toFloat())
}
}
}
}
return super.affectWeight(detail, ctx, weight)
}
}
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.Entity
class IncenseSweetInfluence(val pos: BlockPos? = null) : SpawningInfluence {
override fun affectSpawn(entity: Entity) {
super.affectSpawn(entity)
}
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
return super.affectWeight(detail, ctx, weight)
}
}
@@ -1,45 +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.spawning.influence
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.Entity
class SaccharineHoneyLogInfluence(val pos: BlockPos? = null) : SpawningInfluence {
var used = false
val chanceForHA = 0.05
private fun markUsed() {
used = true // todo even though I call this it is not saved.... hmmmm
}
override fun affectSpawn(entity: Entity) {
super.affectSpawn(entity)
if (entity is PokemonEntity) {
if (Math.random() <= chanceForHA) {
FishingSpawnCause.alterHAAttempt(entity)
}
this.markUsed()
}
}
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
return super.affectWeight(detail, ctx, weight)
}
fun wasUsed(): Boolean = used
}
@@ -1,127 +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.spawning.influence
import com.cobblemon.mod.common.Cobblemon.LOGGER
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.fishing.SpawnBait.Effects
import com.cobblemon.mod.common.api.fishing.SpawnBaitUtils
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
import com.cobblemon.mod.common.api.pokemon.stats.Stats
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.types.ElementalTypes
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.Entity
/**
* A [SpawningInfluence] that applies some number of SpawnBait effects.
*
* @author Hiroku, Plastered_Crab
* @since March 18th, 2025
*/
class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val baitPos: BlockPos? = null) : SpawningInfluence {
var used: Boolean = false
private fun markUsed() {
used = true
}
override fun affectSpawn(entity: Entity) {
super.affectSpawn(entity)
if (entity is PokemonEntity) {
val merged = SpawnBaitUtils.mergeEffects(effects)
merged.forEach { effect ->
if (Math.random() <= effect.chance) {
markUsed()
Effects.getEffectFunction(effect.type)?.invoke(entity, effect)
}
}
}
}
// EV related bait effects
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
val merged = SpawnBaitUtils.mergeEffects(effects)
// if bait exists and any effects are related to EV yields
if (merged.any { it.type == Effects.EV }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
if (detailSpecies != null && baitEVStat != null) {
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
return when {
evYieldValue > 0 -> {
markUsed()
super.affectWeight(detail, ctx, weight)
}
else -> {
markUsed()
super.affectWeight(detail, ctx, 0f)
}
}
}
}
}
// if bait exists and any effects are related to Typing
if (merged.any { it.type == Effects.TYPING }){
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
if (detailSpecies != null && baitTypingEffect != null) {
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
return when {
isMatchingType -> {
markUsed()
super.affectWeight(detail, ctx, weight * baitEffect.value.toFloat())
}
else -> super.affectWeight(detail, ctx, weight)
}
}
}
}
// if bait exists and any effects are related to Egg Groups
if (merged.any { it.type == Effects.EGG_GROUP }) {
if (detail is PokemonSpawnDetail) {
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
if (detailSpecies != null) {
// Collect all the egg group effects
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
// Check if any of the egg group effects match the species' egg groups
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
if (eggGroup == null) {
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
return@firstOrNull false
}
detailSpecies.eggGroups.contains(eggGroup)
}
if (matchingEffect != null) {
markUsed()
val multiplier = matchingEffect.value
return super.affectWeight(detail, ctx, (weight * multiplier).toFloat())
}
}
}
}
return super.affectWeight(detail, ctx, weight)
}
}
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import kotlin.math.sqrt
import net.minecraft.core.BlockPos
/**
* A type of [WorldSlicedSpawningInfluence] that is only applied to contexts within a particular radius
* of a position.
*
* @author Hiroku
* @since March 9th, 2025
*/
class WorldSlicedSpatialSpawningInfluence(
val pos: BlockPos,
val radius: Float,
influence: SpawningInfluence
) : WorldSlicedSpawningInfluence(influence) {
override fun appliesTo(context: SpawningContext): Boolean {
return sqrt(context.position.distSqr(pos)) <= radius
}
}
@@ -1,24 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.influence
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
/**
* A wrapping around a [SpawningInfluence] that was produced for a [WorldSlice]. This is wrapped
* to provide a filtration mechanism on which of these can be applied to a [SpawningContext].
*
* @author Hiroku
* @since March 9th, 2025
*/
open class WorldSlicedSpawningInfluence(val influence: SpawningInfluence) {
/** Whether this influence will apply to */
open fun appliesTo(context: SpawningContext): Boolean = true
}
@@ -38,10 +38,10 @@ class BestSpawnerConfig {
"seafloor" to 1F
)
val buckets = mutableListOf(
SpawnBucket("common", 91.6F),
SpawnBucket("uncommon", 7F),
SpawnBucket("common", 93.8F),
SpawnBucket("uncommon", 5F),
SpawnBucket("rare", 1.0F),
SpawnBucket("ultra-rare", 0.4F)
SpawnBucket("ultra-rare", 0.2F)
)
companion object {
@@ -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.api.spawning.prospecting
import com.cobblemon.mod.common.CobblemonPoiTypes
import com.cobblemon.mod.common.api.spawning.influence.IncenseSweetInfluence
import com.cobblemon.mod.common.api.spawning.influence.SaccharineHoneyLogInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.util.math.pow
import com.cobblemon.mod.common.util.toBlockPos
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.ai.village.poi.PoiManager
import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
import kotlin.math.ceil
import kotlin.math.sqrt
object IncenseSweetProspector : SpawningInfluenceProspector {
@JvmField
val RANGE: Int = 32
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
val world = area.world
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
val centerPos = area.getCenter().toBlockPos()
val sweetIncensePositions = world.poiManager.findAll(
{ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.INCENSE_SWEET_KEY) },
{ true },
centerPos,
searchRange,
PoiManager.Occupancy.ANY
).toList()
for (pos in sweetIncensePositions) {
val influence = WorldSlicedSpatialSpawningInfluence(pos, RANGE.toFloat(), IncenseSweetInfluence(pos))
listOfInfluences.add(influence)
}
return listOfInfluences
}
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
}
@@ -1,55 +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.spawning.prospecting
import com.cobblemon.mod.common.CobblemonPoiTypes
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.block.LureCakeBlock
import com.cobblemon.mod.common.block.entity.LureCakeBlockEntity
import com.cobblemon.mod.common.util.math.pow
import com.cobblemon.mod.common.util.toBlockPos
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.ai.village.poi.PoiManager
import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.level.block.state.BlockState
import kotlin.math.ceil
import kotlin.math.sqrt
object LureCakeProspector : SpawningInfluenceProspector {
@JvmField
val RANGE: Int = 48
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
val world = area.world
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
val lureCakePositions = world.poiManager.findAll({ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.LURE_CAKE_KEY) },{ true },area.getCenter().toBlockPos(),searchRange, PoiManager.Occupancy.ANY).toList()
for (lureCakePos in lureCakePositions) {
val blockState = world.getBlockState(lureCakePos)
if (blockState.block !is LureCakeBlock) continue
val blockEntity = world.getBlockEntity(lureCakePos) as? LureCakeBlockEntity ?: continue
val baitEffects = blockEntity.getBaitEffectsFromLureCake()
listOfInfluences.add(WorldSlicedSpatialSpawningInfluence(lureCakePos, RANGE.toFloat(), influence = SpawnBaitInfluence(baitEffects, lureCakePos)))
}
return listOfInfluences
}
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
}
@@ -1,57 +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.spawning.prospecting
import com.cobblemon.mod.common.CobblemonPoiTypes
import com.cobblemon.mod.common.api.spawning.influence.SaccharineHoneyLogInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
import com.cobblemon.mod.common.util.math.pow
import com.cobblemon.mod.common.util.toBlockPos
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.ai.village.poi.PoiManager
import net.minecraft.world.entity.ai.village.poi.PoiType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
import kotlin.math.ceil
import kotlin.math.sqrt
object SaccharineHoneyLogProspector : SpawningInfluenceProspector {
@JvmField
val RANGE: Int = 32
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
val world = area.world
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
val centerPos = area.getCenter().toBlockPos()
val honeyLogPositions = world.poiManager.findAll(
{ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.SACCHARINE_HONEY_LOG_KEY) },
{ true },
centerPos,
searchRange,
PoiManager.Occupancy.ANY
).toList()
for (pos in honeyLogPositions) {
val influence = WorldSlicedSpatialSpawningInfluence(pos, RANGE.toFloat(), SaccharineHoneyLogInfluence(pos))
listOfInfluences.add(influence)
}
return listOfInfluences
}
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.spawning.prospecting
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.block.state.BlockState
import com.cobblemon.mod.common.api.spawning.WorldSlice
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
/**
* Prospects for [WorldSlicedSpawningInfluence] in a world at a given position. Occurs as part of a
* [SpawningProspector] scanning a part of the world while formulating a [WorldSlice].
*
* @author Hiroku
* @since March 9th, 2025
*/
interface SpawningInfluenceProspector {
companion object {
@JvmStatic
val prospectors = mutableSetOf<SpawningInfluenceProspector>(
LureCakeProspector,
SaccharineHoneyLogProspector,
IncenseSweetProspector
)
}
fun prospect(spawner: Spawner, area: SpawningArea) : MutableList<WorldSlicedSpawningInfluence>
fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpawningInfluence?
}
@@ -145,16 +145,9 @@ open class FlatContextWeightedSelector : SpawningSelector {
}
}
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.value.highestWeight }
// TODO clean this up later once we know the crash that happens is fixed
if (selectedSpawn == null) {
LOGGER.warn("FlatContextWeightedSelector failed: No spawn detail with positive weight was found for ${spawner.name}.")
return null
}
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.value.highestWeight }!!
return selectedSpawn.value.chooseContext() to selectedSpawn.key
}
protected fun getProbabilitiesFromContextType(spawner: Spawner, contextSelectionData: ContextSelectionData): Map<SpawnDetail, Float> {
@@ -8,29 +8,17 @@
package com.cobblemon.mod.common.api.spawning.spawner
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.CobblemonBlocks
import com.cobblemon.mod.common.api.fishing.SpawnBait
import com.cobblemon.mod.common.api.spawning.SpawnBucket
import com.cobblemon.mod.common.api.spawning.SpawnBucketUtils
import com.cobblemon.mod.common.api.spawning.SpawnCause
import com.cobblemon.mod.common.api.spawning.SpawnerManager
import com.cobblemon.mod.common.api.spawning.context.AreaSpawningContext
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
import com.cobblemon.mod.common.api.spawning.context.SubmergedSpawningContext
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
import com.cobblemon.mod.common.api.spawning.influence.SaccharineHoneyLogInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
import com.cobblemon.mod.common.api.spawning.selection.FlatContextWeightedSelector
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
import com.cobblemon.mod.common.block.entity.CakeBlockEntity
import com.cobblemon.mod.common.block.entity.LureCakeBlockEntity
import net.minecraft.world.entity.Entity
import net.minecraft.world.level.block.RotatedPillarBlock
/**
* A spawner that regularly attempts spawning entities. It has timing utilities,
@@ -80,117 +68,14 @@ abstract class TickingSpawner(
ticksUntilNextSpawn -= tickTimerMultiplier
if (ticksUntilNextSpawn <= 0) {
val defaultBucket = chooseBucket()
val defaultCause = SpawnCause(spawner = this, bucket = defaultBucket, entity = getCauseEntity())
// Try getting spawn with a dummy cause first
val preSpawn = run(defaultCause)
if (preSpawn != null) {
val (ctx, detail) = preSpawn
val spawnBaitInfluence = ctx.influences.filterIsInstance<SpawnBaitInfluence>().firstOrNull()
val saccharineInfluence = ctx.influences.filterIsInstance<SaccharineHoneyLogInfluence>().firstOrNull()
val rarityInfluenceValue = spawnBaitInfluence?.effects?.firstOrNull { it.type == SpawnBait.Effects.RARITY_BUCKET}
val bucket = if (spawnBaitInfluence != null && spawnBaitInfluence.used && rarityInfluenceValue != null) {
// todo if we want fishing and lure cakes to default to having better rates we can maybe call a new bucket value of SpawnBucketUtils.chooseAdjustedSpawnBucket but with a value of 0
// todo Get bucket effect from bait influence and use it in the new method
val baitRarityLevel = rarityInfluenceValue.value.toInt()
SpawnBucketUtils.chooseAdjustedSpawnBucket(Cobblemon.bestSpawner.config.buckets, baitRarityLevel)
} else {
defaultBucket // todo Maybe end it quicker if it is this
}
// todo maybe only do this stuff if there is a rarity bucket bait effect present in the influence
// Rerun with the new bucket
val (finalCtx, finalDetail) = if (spawnBaitInfluence != null) {
val cause = SpawnCause(spawner = this, bucket = bucket, entity = getCauseEntity())
run(cause) ?: return
} else {
preSpawn
}
val spawnAction = finalDetail.doSpawn(ctx = finalCtx)
if (finalCtx is AreaSpawningContext && spawnBaitInfluence != null && spawnBaitInfluence.used) {
val baitPos = spawnBaitInfluence.baitPos
val level = finalCtx.world.level
val blockEntity = baitPos?.let { level.getBlockEntity(it) }
if (blockEntity is LureCakeBlockEntity) {
blockEntity.bites++
if (blockEntity.bites >= blockEntity.maxBites) {
level.removeBlock(baitPos, false)
} else {
blockEntity.setChanged()
level.sendBlockUpdated(baitPos, blockEntity.blockState, blockEntity.blockState, 3)
}
}
} else if (saccharineInfluence != null) { /*saccharineInfluence.wasUsed()*/ // todo for some reason used is never true.... even though it works for the Lure Cakes)
val logPos = saccharineInfluence.pos
val level = finalCtx.world.level
if (logPos != null) {
val blockState = level.getBlockState(logPos)
if (blockState.block == CobblemonBlocks.SACCHARINE_HONEY_LOG) {
val axis = blockState.getValue(RotatedPillarBlock.AXIS)
val newState = CobblemonBlocks.SACCHARINE_LOG.defaultBlockState().setValue(RotatedPillarBlock.AXIS, axis)
level.setBlock(logPos, newState, 3)
}
}
}
spawnAction.complete()
finalCtx.influences.filterIsInstance<SpawnBaitInfluence>().forEach {
it.used = false
}
}
/*
// TODO maybe around here we would check for a way to check for a SpawnBaitInfluence so we could increase odds of a different rarity bucket?
// Although you need to have a spawn to get a context to then have an influence..... Not sure the best way to go about this
val spawn = run(SpawnCause(spawner = this, bucket = chooseBucket(), entity = getCauseEntity()))
ticksUntilNextSpawn = ticksBetweenSpawns
if (spawn != null) {
val ctx = spawn.first
val detail = spawn.second
val spawnAction = detail.doSpawn(ctx = ctx)
if (ctx is AreaSpawningContext) {
val influence = ctx.influences.filter { it is SpawnBaitInfluence }.firstOrNull()
// this is where we try to grab a possible SpawnBaitInfluence
if (influence is SpawnBaitInfluence && influence.used) {
val baitPos = influence.baitPos
val level = ctx.world.level
val blockEntity = baitPos?.let { level.getBlockEntity(it) }
if (blockEntity is LureCakeBlockEntity) {
blockEntity.bites++
if (blockEntity.bites >= CakeBlockEntity.MAX_NUMBER_OF_BITES) {
level.removeBlock(baitPos, false)
} else {
blockEntity.setChanged()
level.sendBlockUpdated(baitPos, blockEntity.blockState, blockEntity.blockState, 3)
}
}
}
}
spawnAction.complete()
// TODO reset the Influence (Not sure if we need to do this, but in case it persists by next time I am adding this)
ctx.influences.filterIsInstance<SpawnBaitInfluence>().forEach {
it.used = false
}
}*/
}
}
}
@@ -22,7 +22,6 @@ import net.minecraft.tags.TagKey
object CobblemonBlockTags {
@JvmField val ALL_HANGING_SIGNS = createTag("all_hanging_signs")
@JvmField val ALL_SAPLINGS = createTag("all_saplings")
@JvmField val ALL_SIGNS = createTag("all_signs")
@JvmField val ANCIENT_CITY_BLOCKS = createTag("ancient_city_blocks")
@JvmField val APRICORN_LEAVES = createTag("apricorn_leaves")
@@ -57,7 +56,6 @@ object CobblemonBlockTags {
@JvmField val MACHINES = createTag("machines")
@JvmField val MANSION_BLOCKS = createTag("mansion_blocks")
@JvmField val MEDICINAL_LEEK_PLANTABLE = createTag("medicinal_leek_plantable")
@JvmField val HEARTY_GRAINS_PLANTABLE = createTag("hearty_grains_plantable")
@JvmField val MINTS = createTag("mints")
@JvmField val MOON_STONE_ORES = createTag("moon_stone_ores")
@JvmField val NATURAL = createTag("natural")
@@ -69,9 +67,6 @@ object CobblemonBlockTags {
@JvmField val REDSTONE_BLOCKS = createTag("redstone_blocks")
@JvmField val ROOTS = createTag("roots")
@JvmField val ROOTS_SPREADABLE = createTag("roots_spreadable")
@JvmField val SACCHARINE_LEAVES = createTag("saccharine_leaves")
@JvmField val SACCHARINE_LOGS = createTag("saccharine_logs")
@JvmField val SACCHARINE_SAPLING = createTag("saccharine_sapling")
@JvmField val RUINED_PORTAL_BLOCKS = createTag("ruined_portal_blocks")
@JvmField val SEES_SKY = createTag("sees_sky")
@JvmField val SHINY_STONE_ORES = createTag("shiny_stone_ores")

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