forked from mirrors/cobblemon
Compare commits
120
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d11ef0411a | ||
|
|
c41b0cdca2 | ||
|
|
88f743ee48 | ||
|
|
15b9afacf8 | ||
|
|
babcf7430b | ||
|
|
3439ca2011 | ||
|
|
6539f3dea1 | ||
|
|
fcde1eb171 | ||
|
|
a30a5644df | ||
|
|
a5672a38b9 | ||
|
|
3b14ea319b | ||
|
|
a090c90831 | ||
|
|
5dcc9ba46d | ||
|
|
f8e4ea70df | ||
|
|
5dc1c749f3 | ||
|
|
3accfa29b7 | ||
|
|
1af1569f63 | ||
|
|
dbd2f5d340 | ||
|
|
86bf413f00 | ||
|
|
f13e7d03a1 | ||
|
|
4a025ac65e | ||
|
|
8a0c98c9ab | ||
|
|
36c5fe2419 | ||
|
|
0c79d102cf | ||
|
|
b14b25ae19 | ||
|
|
bd8f644b9a | ||
|
|
7c84cdb05d | ||
|
|
125975e25f | ||
|
|
baf766298a | ||
|
|
83580e7e8b | ||
|
|
90335ccb2d | ||
|
|
9679929694 | ||
|
|
fd6fb5db47 | ||
|
|
a80ada8590 | ||
|
|
c4a4b9cb86 | ||
|
|
5af96e75eb | ||
|
|
023a01befd | ||
|
|
4912a89e6e | ||
|
|
f2e10d1b01 | ||
|
|
25eb197491 | ||
|
|
8de233b572 | ||
|
|
83972ca9e6 | ||
|
|
35e2190cae | ||
|
|
b966cd2db0 | ||
|
|
3e492541cc | ||
|
|
cc2022ed59 | ||
|
|
298fdf45d5 | ||
|
|
4e9541d7f5 | ||
|
|
1dab5b8c7c | ||
|
|
2875e9efa9 | ||
|
|
2b42fff66b | ||
|
|
643a33a643 | ||
|
|
e348c48eff | ||
|
|
473f58cab9 | ||
|
|
987b8619a3 | ||
|
|
87632941e8 | ||
|
|
041acab7ca | ||
|
|
b3de7d1c1a | ||
|
|
afcb2dd77c | ||
|
|
a7bd6d2bf4 | ||
|
|
b096cb60a3 | ||
|
|
7f1c0c3d4c | ||
|
|
a4f0bf9d2f | ||
|
|
f46c748e9f | ||
|
|
065479c58c | ||
|
|
eee3d46a2d | ||
|
|
d7b43fcbfc | ||
|
|
c82e011f73 | ||
|
|
bf1b996962 | ||
|
|
fc46cdcda0 | ||
|
|
4e7b029afb | ||
|
|
5430f02770 | ||
|
|
6a51abe3ee | ||
|
|
008652b442 | ||
|
|
c1e088eb33 | ||
|
|
1669a2f428 | ||
|
|
2ba63f4641 | ||
|
|
41b9e9001d | ||
|
|
679920b786 | ||
|
|
f058d6e635 | ||
|
|
f9377b7489 | ||
|
|
e59b5094ad | ||
|
|
c8ec4e6f1f | ||
|
|
a2fef9f1be | ||
|
|
3d4df2c098 | ||
|
|
7557cab03d | ||
|
|
f1018b1da9 | ||
|
|
cbcc6abe40 | ||
|
|
5af4e3bddb | ||
|
|
64c9d47b0f | ||
|
|
1f519cae50 | ||
|
|
c0d2803f61 | ||
|
|
e249d5238f | ||
|
|
e32e505e95 | ||
|
|
7642a84108 | ||
|
|
b6e20d69cc | ||
|
|
9d04e20a30 | ||
|
|
d2624813f7 | ||
|
|
f6f607904e | ||
|
|
9284497cec | ||
|
|
36cb12952a | ||
|
|
2700dc7f39 | ||
|
|
91864b13d0 | ||
|
|
adc8e9921a | ||
|
|
5e5473acae | ||
|
|
3509944f1a | ||
|
|
8a5489f805 | ||
|
|
922ee95fd2 | ||
|
|
3b7d56ff45 | ||
|
|
50c567d264 | ||
|
|
d4964e41d3 | ||
|
|
41b1c169c3 | ||
|
|
49e2001004 | ||
|
|
66393f9293 | ||
|
|
7b3b6146a1 | ||
|
|
e1452244c2 | ||
|
|
5358414a0c | ||
|
|
d691373919 | ||
|
|
038f13e6fa | ||
|
|
dd288a3b0c |
@@ -0,0 +1,12 @@
|
||||
### Additions
|
||||
- Added functionality for marks.
|
||||
- Added data for all marks and all title ribbons from Pokémon.
|
||||
- Added marks screen within the summary UI.
|
||||
- Added `/givemark <player> <partySlot> <mark>` command to give a mark to a Pokémon.
|
||||
- Added `/takemark <player> <partySlot> <mark>` command to remove a mark from a Pokémon.
|
||||
- Added `/giveallmarks <player> <partySlot>` command to give all available marks to a Pokémon.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added Flows for `bobber_spawn_pokemon_post`, `pokemon_entity_spawn`, and `fossil_revived`.
|
||||
- Added `marks` datapack folder.
|
||||
- Added MoLang functions `entity.is_in_rain`, `pokemon.add_marks(Mark...)`, `pokemon.add_potential_marks(Mark...)`, `pokemon.add_marks_with_chance(Mark...)`, `pokemon.apply_potential_marks`, and `world.is_snowing_at(x, y, z)`.
|
||||
@@ -11,7 +11,84 @@
|
||||
- Added cosmetic item functionality for Pokémon. Certain cosmetic items can be given to applicable Pokémon via the interact menu.
|
||||
- Added the various log blocks as cosmetic items for Timburr and Komala.
|
||||
- Added `visibility/hidden`, `visibility/hat` and `visibility/face` tags to control where and how certain items are rendered.
|
||||
- Added Pokémon markings, toggleable within the summary.
|
||||
- Added `/boxcount` command to change PC boxes amount
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
#### Gen 2
|
||||
- Dunsparce
|
||||
|
||||
#### Gen 3
|
||||
- Spoink
|
||||
- Grumpig
|
||||
- Snorunt
|
||||
- Glalie
|
||||
|
||||
#### Gen 4
|
||||
- Bronzor
|
||||
- Bronzong
|
||||
- Croagunk
|
||||
- Froslass
|
||||
|
||||
#### Gen 5
|
||||
- Pansage
|
||||
- Simisage
|
||||
- Pansear
|
||||
- Simisear
|
||||
- Panpour
|
||||
- Simipour
|
||||
- Munna
|
||||
- Musharna
|
||||
- Blitzle
|
||||
- Zebstrika
|
||||
- Trubbish
|
||||
- Garbodor
|
||||
|
||||
#### Gen 6
|
||||
- Noibat
|
||||
- Noivern
|
||||
|
||||
#### Gen 7
|
||||
- Drampa
|
||||
|
||||
#### Gen 8
|
||||
- Silicobra
|
||||
- Sandaconda
|
||||
|
||||
#### Gen 9
|
||||
- Smoliv
|
||||
- Dolliv
|
||||
- Arboliva
|
||||
- Orthworm
|
||||
- Dudunsparce
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Garchomp
|
||||
- Torpius
|
||||
- Nosepass
|
||||
- Probopass
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
- Dragonite
|
||||
- Eevee
|
||||
- Vaporeon
|
||||
- Jolteon
|
||||
- Flareon
|
||||
- Espeon
|
||||
- Umbreon
|
||||
- Leafeon
|
||||
- Glaceon
|
||||
- Sylveon
|
||||
- Honchkrow
|
||||
- Garchomp
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
|
||||
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
@@ -20,6 +97,8 @@
|
||||
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
|
||||
- Improved the performance of saving Pokédex and player data.
|
||||
- Pokémon hitbox now scales with entity attribute `generic.scale`.
|
||||
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
|
||||
- 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.
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -42,11 +121,13 @@
|
||||
- Fixed field name in evolution requirements for Spewpa Pokeball.
|
||||
- Fixed LevelUpCriterion logic to correctly check that the Pokémon is a preEvo.
|
||||
- Fixed `hide_additional_tooltip` vanilla flag not properly hiding tooltips on pokerod and bait items
|
||||
- Removed a number of scenarios in which a Pokémon battle may send out a Pokémon into collision geometry.
|
||||
- Fixed NPCs using Pokémon outside of their pool when a Pokémon name had a typo.
|
||||
- Fixed an issue with datapacked species features not being applied properly when relogging.
|
||||
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
|
||||
- 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 swapping held items with wild Pokémon under certain circumstances causing duplicate items
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -64,6 +145,7 @@
|
||||
- Updated NPCEntity beam positioning to properly account for the baseScale property.
|
||||
- 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`.
|
||||
|
||||
### 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)
|
||||
@@ -75,6 +157,10 @@
|
||||
- Fixed species additions not being capable of changing implemented status.
|
||||
- Added support for action effects that are triggered by `|-activate|` Showdown instructions. `activate_{effect_id}` is the syntax.
|
||||
- Added Molang functions for rendering items `render_item(item_id, locator_name)` and `clear_items()`.
|
||||
- Fixed location spawn filter components causing crashes
|
||||
- Added `pokemon` as an available Molang function for the `battleActor` functions.
|
||||
- Fixed `heldItem` property inside spawn files not working and causing crashes
|
||||
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface OrientationControllable {
|
||||
OrientationController getOrientationController();
|
||||
}
|
||||
@@ -1,143 +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.util.Mth;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface Rollable {
|
||||
|
||||
// From Minecraft's Camera
|
||||
Vector3f FORWARDS = new Vector3f(0.0F, 0.0F, -1.0F);
|
||||
Vector3f UP = new Vector3f(0.0F, 1.0F, 0.0F);
|
||||
Vector3f LEFT = new Vector3f(-1.0F, 0.0F, 0.0F);
|
||||
|
||||
@Nullable Matrix3f getOrientation();
|
||||
|
||||
Rollable updateOrientation(Function<Matrix3f, Matrix3f> update);
|
||||
|
||||
/**
|
||||
* @return The forward vector (0, 0, -1) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getForwardVector() {
|
||||
if (getOrientation() == null) return new Vector3f(FORWARDS);
|
||||
return getOrientation().transform(FORWARDS, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The left vector (-1, 0, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getLeftVector() {
|
||||
if (getOrientation() == null) return new Vector3f(LEFT);
|
||||
return getOrientation().transform(LEFT, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The up vector (0, 1, 0) after the rotation matrix is applied.
|
||||
*/
|
||||
default Vector3f getUpVector() {
|
||||
if (getOrientation() == null) return new Vector3f(UP);
|
||||
return getOrientation().transform(UP, new Vector3f());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotateYaw(float yaw) {
|
||||
return updateOrientation(prev -> prev.rotateY((float) Math.toRadians(-yaw)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pitch change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
|
||||
default Rollable rotatePitch(float pitch) {
|
||||
return updateOrientation(prev -> prev.rotateX((float) Math.toRadians(-pitch)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotateRoll(float roll) {
|
||||
return updateOrientation(prev -> prev.rotateZ((float) Math.toRadians(-roll)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Order matters when rotating an object. If you need a different order, individually call rotateYaw, rotatePitch, and rotateRoll
|
||||
*
|
||||
* @param yaw change in degrees
|
||||
* @param pitch change in degrees
|
||||
* @param roll change in degrees
|
||||
* @return The Rollable object this method was called on
|
||||
*/
|
||||
default Rollable rotate(float yaw, float pitch, float roll) {
|
||||
return rotateYaw(yaw).rotatePitch(pitch).rotateRoll(roll);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pitch angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being South, 90 being West, 180/-180 being North, and -90 being East
|
||||
*/
|
||||
default float getYaw() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(FORWARDS.angleSigned(getForwardVector(), UP)) + 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The yaw angle in degrees as a float.
|
||||
* Value is between [-90, 90] with 0 being straight forward, 90 being straight down, and -90 being straight up
|
||||
*/
|
||||
default float getPitch() {
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(Math.asin(getForwardVector().y)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The roll angle in degrees as a float.
|
||||
* Value is between [-180, 180] with 0 being no roll (normal), 90 being 90 degrees CW, 180/-180 being 180 degrees CW/CCW, and -90 being 90 degrees CCW
|
||||
*/
|
||||
default float getRoll() {
|
||||
//Cobblemon.LOGGER.info("{}", (float) Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
return (float) Mth.wrapDegrees(-Math.toDegrees(getUpVector().angleSigned(UP, getForwardVector())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the angular velocity in degrees per second as a Vec3
|
||||
*/
|
||||
Vec3 angRollVel( double deltaTime );
|
||||
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
);
|
||||
|
||||
boolean shouldRoll();
|
||||
|
||||
boolean useAngVelSmoothing();
|
||||
|
||||
void clearRotation();
|
||||
|
||||
}
|
||||
@@ -23,16 +23,15 @@ public abstract class LocalPlayerMixin {
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
//Use custom jump bar logic if the current ride does not jump using it.
|
||||
if( !ride.getRiding().canJump(ride, player))
|
||||
{
|
||||
cir.setReturnValue(ride.setRideBar());
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,17 @@ package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
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.Rideable;
|
||||
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;
|
||||
@@ -31,45 +34,39 @@ import com.cobblemon.mod.common.util.DataKeys;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.SmoothDouble;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
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.item.Items;
|
||||
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;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements Rollable, ScannableEntity {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable {
|
||||
|
||||
@Shadow public abstract CompoundTag getShoulderEntityLeft();
|
||||
|
||||
@@ -87,7 +84,10 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Unique private Matrix3f orientation = null;
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Unique
|
||||
private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
@@ -115,6 +115,19 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
return STANDING_DIMENSIONS;
|
||||
}
|
||||
return POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
@@ -241,7 +254,7 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
|
||||
@Override
|
||||
public void absMoveTo(double x, double y, double z, float yaw, float pitch) {
|
||||
if (shouldRoll()) {
|
||||
if (cobblemon$orientationController.getActive()) {
|
||||
this.absMoveTo(x, y, z);
|
||||
this.setYRot(yaw % 360.0f);
|
||||
this.setXRot(pitch % 360.0f);
|
||||
@@ -254,120 +267,58 @@ public abstract class PlayerMixin extends LivingEntity implements Rollable, Scan
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
public void tick(CallbackInfo ci) {
|
||||
if (this.shouldRoll()) {
|
||||
// Proof of concept for yaw movement
|
||||
if (this.getMainHandItem().is(Items.STICK)) {
|
||||
this.rotateYaw(2);
|
||||
}
|
||||
else if (this.getMainHandItem().is(Items.BLAZE_ROD)) {
|
||||
this.rotateYaw(-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix3f getOrientation() {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rollable updateOrientation(Function<Matrix3f, Matrix3f> update) {
|
||||
//Disabled to allow non mouse inputs to modify roll
|
||||
if (!shouldRoll()) return this;
|
||||
|
||||
if (this.orientation == null) {
|
||||
this.orientation = new Matrix3f();
|
||||
this.rotate(getYRot() - 180, getXRot(), 0);
|
||||
}
|
||||
this.orientation = update.apply(this.orientation);
|
||||
setYRot(this.getYaw());
|
||||
setXRot(this.getPitch());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRoll() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return false;
|
||||
if (player.isHolding(Items.DIAMOND)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 rotationOnMouseXY(
|
||||
double yMouse,
|
||||
double xMouse,
|
||||
SmoothDouble yMouseSmoother,
|
||||
SmoothDouble xMouseSmoother,
|
||||
double sensitivity,
|
||||
double deltaTime
|
||||
) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
return pokemonEntity.getRiding().rotationOnMouseXY(
|
||||
pokemonEntity,
|
||||
player,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAngVelSmoothing() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
|
||||
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 angRollVel( double deltaTime ) {
|
||||
var ret = new Vec3(0.0, 0.0, 0.0);
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (!this.equals(player)) return ret;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return ret;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return ret;
|
||||
|
||||
return pokemonEntity.getRiding().angRollVel( pokemonEntity, player, deltaTime );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clearRotation() {
|
||||
this.orientation = null;
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "rideTick()V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;wantsToStopRiding()Z")
|
||||
)
|
||||
public boolean delegateDismountToController(Player instance, Operation<Boolean> original) {
|
||||
if (this.getVehicle() instanceof Rideable vehicle) {
|
||||
return vehicle.getRiding().dismountOnShift() && original.call(instance);
|
||||
if (this.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.dismountOnShift(settings, state, pokemonEntity) && original.call(instance);
|
||||
});
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor;
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.joml.Matrix3f;
|
||||
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;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Consumer<Packet<?>> broadcast;
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
@Unique
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
if (!(this.entity instanceof PokemonEntity pokemonEntity)) return;
|
||||
if (pokemonEntity.getRidingState() == null) return;
|
||||
if (pokemonEntity.getRiding() == null) return;
|
||||
var ridingBehaviour = pokemonEntity.getRiding();
|
||||
var ridingState = pokemonEntity.getRidingState();
|
||||
var previousRidingState = pokemonEntity.getPreviousRidingState();
|
||||
if (previousRidingState != null && !ridingState.shouldSync(previousRidingState)) return;
|
||||
cobblemon$broadcast(new ClientboundUpdateRidingStatePacket(pokemonEntity.getId(), ridingBehaviour.getKey(), pokemonEntity.getRidingState(), null));
|
||||
}
|
||||
|
||||
private void cobblemon$sendOrientationChanges() {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
OrientationController controller = controllable.getOrientationController();
|
||||
Matrix3f currOrientation = controller.getOrientation();
|
||||
boolean currActive = controller.getActive();
|
||||
|
||||
if (currOrientation == null || currOrientation.equals(cobblemon$lastSentOrientation) && (currActive == cobblemon$lastSentActive))
|
||||
return;
|
||||
cobblemon$lastSentOrientation = new Matrix3f(currOrientation);
|
||||
cobblemon$lastSentActive = currActive;
|
||||
|
||||
cobblemon$broadcast(new ClientboundUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Int2ObjectMap<?> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
Object tracked = entityMap.get(entity.getId());
|
||||
if (!(tracked instanceof TrackedEntityAccessor tracker)) return;
|
||||
|
||||
Set<ServerPlayerConnection> seenBy = tracker.getSeenBy();
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public interface ChunkMapAccessor {
|
||||
@Accessor("entityMap")
|
||||
Int2ObjectMap<?> getEntityMap();
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(targets = "net.minecraft.server.level.ChunkMap$TrackedEntity")
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
}
|
||||
@@ -8,10 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
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.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;
|
||||
import org.joml.Vector3f;
|
||||
@@ -23,10 +41,10 @@ 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 @Final private static float DEFAULT_CAMERA_DISTANCE;
|
||||
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@@ -35,10 +53,13 @@ public abstract class CameraMixin {
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
@Shadow public abstract float getXRot();
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow public abstract float getYRot();
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Shadow
|
||||
private BlockGetter level;
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@@ -47,51 +68,161 @@ public abstract class CameraMixin {
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
public void open_camera$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof Rollable rollable) || disableRollableCameraDebug) return;
|
||||
if (!rollable.shouldRoll() && rollable.getOrientation() != null) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || disableRollableCameraDebug) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
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.
|
||||
rollable.getOrientation().set(
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
rollable.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
rollable.clearRotation();
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rollable.getOrientation() == null) return;
|
||||
if (controller.getOrientation() == null) return;
|
||||
applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = rollable.getRoll();
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
//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 positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
//RidingCameraDelagate.INSTANCE.positionCamera(instance, x, y, z, original);
|
||||
if (!(vehicle instanceof PokemonEntity pokemon)) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
int seatIndex = pokemon.getPassengers().indexOf(entity);
|
||||
Seat seat = pokemon.getSeats().get(seatIndex);
|
||||
|
||||
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())
|
||||
);
|
||||
|
||||
OrientationControllable rollable = (OrientationControllable) entity;
|
||||
OrientationController controller = rollable.getOrientationController();
|
||||
|
||||
if (!instance.isDetached() || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemon.getDelegate();
|
||||
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);
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (entity.getBbHeight() / 2), 0f)));
|
||||
|
||||
Vec3 position = locatorOffset.add(entityPos).add(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);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void applyRotation(){
|
||||
if (!(this.entity instanceof Rollable rollable) || rollable.getOrientation() == null) return;
|
||||
var newRotation = rollable.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
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));
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = rollable.getPitch();
|
||||
this.yRot = rollable.getYaw();
|
||||
this.forwards.set(rollable.getForwardVector());
|
||||
this.up.set(rollable.getUpVector());
|
||||
this.left.set(rollable.getLeftVector());
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
this.forwards.set(controller.getForwardVector());
|
||||
this.up.set(controller.getUpVector());
|
||||
this.left.set(controller.getLeftVector());
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -31,14 +31,14 @@ public class ItemInHandRendererMixin {
|
||||
if (abstractClientPlayer.isUsingItem() && abstractClientPlayer.getUseItem().getItem() instanceof PokedexItem) {
|
||||
ci.cancel();
|
||||
}
|
||||
else if (abstractClientPlayer instanceof Rollable rollable && rollable.shouldRoll()) {
|
||||
else if (abstractClientPlayer instanceof OrientationControllable controllable && controllable.getOrientationController().isActive()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof Rollable rollable && rollable.shouldRoll())) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.ModAPI;
|
||||
import com.cobblemon.mod.common.item.PokeBallItem;
|
||||
import com.cobblemon.mod.common.item.PokedexItem;
|
||||
import com.cobblemon.mod.common.item.WearableItem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.ItemModelShaper;
|
||||
@@ -54,17 +55,18 @@ public abstract class ItemRendererMixin {
|
||||
)
|
||||
private void cobblemon$overrideItemModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int light, int overlay, BakedModel model, CallbackInfo ci) {
|
||||
boolean shouldBe2d = renderMode == ItemDisplayContext.GUI || renderMode == ItemDisplayContext.FIXED;
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (shouldBe2d) {
|
||||
ResourceLocation resourceLocation = null;
|
||||
if (stack.getItem() instanceof PokeBallItem pokeBallItem) resourceLocation = pokeBallItem.getPokeBall().getModel2d();
|
||||
else if (stack.getItem() instanceof PokedexItem pokedexItem) resourceLocation = pokedexItem.getType().getItemSpritePath();
|
||||
}
|
||||
if (renderMode != ItemDisplayContext.HEAD && stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel2d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
if (resourceLocation != null) {
|
||||
BakedModel replacementModel = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
|
||||
if (!cobblemon$isSameModel(model, replacementModel)) {
|
||||
ci.cancel();
|
||||
render(stack, renderMode, leftHanded, matrices, multiBufferSource, light, overlay, replacementModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +80,7 @@ public abstract class ItemRendererMixin {
|
||||
boolean canOpenScreen = entity != null && ((entity.getOffhandItem() == stack && !(entity.getMainHandItem().getItem() instanceof PokedexItem)) || entity.getMainHandItem() == stack);
|
||||
resourceLocation = pokedexItem.getType().getItemModelPath(isScanModel ? "scanning" : (canOpenScreen ? null : "off"));
|
||||
}
|
||||
else if (stack.getItem() instanceof WearableItem wearableItem) resourceLocation = wearableItem.getModel3d();
|
||||
|
||||
if (resourceLocation != null) {
|
||||
BakedModel model = this.itemModelShaper.getModelManager().getModel(new ModelResourceLocation(resourceLocation, MODEL_PATH));
|
||||
|
||||
@@ -9,9 +9,14 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.joml.Matrix3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -20,24 +25,55 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public class LocalPlayerMixin {
|
||||
public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
private void cobblemon_updateRotationMatrix(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
protected LocalPlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
// if (!(this instanceof OrientationControllable controllable)) return;
|
||||
// var controller = controllable.getOrientationController();
|
||||
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
// }
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon_updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof Rollable rollable)) return;
|
||||
if (rollable.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = rollable.getOrientation() != null ? new Matrix3f(rollable.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new C2SUpdateOrientationPacket(rollable.getOrientation()));
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Rollable;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -49,8 +49,6 @@ public class MouseHandlerMixin {
|
||||
|
||||
@Shadow private double accumulatedDY;
|
||||
|
||||
@Shadow private double accumulatedScrollX;
|
||||
|
||||
@Inject(
|
||||
method = "onScroll",
|
||||
at = @At(
|
||||
@@ -121,9 +119,9 @@ public class MouseHandlerMixin {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(player instanceof Rollable rollable)) return true;
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!rollable.shouldRoll()) {
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
@@ -132,68 +130,105 @@ public class MouseHandlerMixin {
|
||||
return true;
|
||||
}
|
||||
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
var ridingSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
|
||||
//Send mouse input to be interpreted into rotation
|
||||
//deltas by the ride controller
|
||||
Vec3 angVecMouse = rollable.rotationOnMouseXY(
|
||||
cursorDeltaY,
|
||||
cursorDeltaX ,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
ridingSensitivity,
|
||||
movementTime
|
||||
);
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
//Perform Rotation using mouse influenced rotation deltas.
|
||||
rollable.rotate(
|
||||
controllable.getOrientationController().rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
);
|
||||
|
||||
|
||||
//Gather and apply the current rotation deltas
|
||||
var angRot = rollable.angRollVel(movementTime);
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
//Apply smoothing if requested by the controller.
|
||||
//This Might be best if done by the controller itself?
|
||||
if( rollable.useAngVelSmoothing() )
|
||||
if(cobblemon$shouldUseAngVelSmoothing())
|
||||
{
|
||||
if( angRot != null ) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
rollable.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
//Otherwise simply apply the smoothing
|
||||
else
|
||||
{
|
||||
if( angRot != null ) {
|
||||
rollable.rotate((float) (
|
||||
angRot.x * 10 * d),
|
||||
(float) (angRot.y * 10 * d),
|
||||
(float) (angRot.z * 10 * d)
|
||||
);
|
||||
}
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;isMouseGrabbed()Z", ordinal = 0))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci, @Local(ordinal = 1) double e) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof Rollable rollable)) return;
|
||||
if (!rollable.shouldRoll()) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
|
||||
var pitch = pitchSmoother.getNewDeltaValue(0, e);
|
||||
var roll = rollSmoother.getNewDeltaValue(0, e);
|
||||
rollable.rotate(0.0F, (float)pitch, (float)roll);
|
||||
controllable.getOrientationController().rotate(0.0F, (float)pitch, (float)roll);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getAngularVelocity(double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
if (!(player instanceof OrientationControllable)) return Vec3.ZERO;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.angRollVel(settings, state, pokemonEntity, player, deltaTime);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Vec3 cobblemon$getRideMouseRotation(double mouseX, double mouseY, double deltaTime) {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return Vec3.ZERO;
|
||||
var vehicle = player.getVehicle();
|
||||
if (vehicle == null) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
var sensitivity = cobblemon$getRidingSensitivity();
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
pokemonEntity,
|
||||
player,
|
||||
mouseY,
|
||||
mouseX,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
private double cobblemon$getRidingSensitivity() {
|
||||
var sensitivity = this.minecraft.options.sensitivity().get() * 0.6000000238418579 + 0.20000000298023224;
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
if (player == null) return true;
|
||||
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
return pokemonEntity.ifRidingAvailableSupply(true, (behaviour, settings, state) -> {
|
||||
return behaviour.useAngVelSmoothing(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.api.riding.RidingManager;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -22,13 +21,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(PlayerModel.class)
|
||||
public class PlayerModelMixin {
|
||||
@Inject(method = "setupAnim(Lnet/minecraft/world/entity/LivingEntity;FFFFF)V", at = @At(value = "HEAD"))
|
||||
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci){
|
||||
private void cobblemon$setHeadRotation(LivingEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci) {
|
||||
if (!(entity instanceof Player)) return;
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity)) return;
|
||||
RidingManager ridingManager = ((Rideable) vehicle).getRiding();
|
||||
if (ridingManager.shouldRotatePlayerHead((PokemonEntity) vehicle)) return;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
var shouldRotatePlayerHead = pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, pokemonEntity);
|
||||
});
|
||||
if (shouldRotatePlayerHead) return;
|
||||
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
|
||||
+28
-1
@@ -11,9 +11,15 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.client.render.ClientPlayerIcon;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -23,12 +29,33 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public class PlayerRendererMixin {
|
||||
public abstract class PlayerRendererMixin extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {
|
||||
|
||||
public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel<AbstractClientPlayer> model, float shadowRadius) {
|
||||
super(context, model, shadowRadius);
|
||||
}
|
||||
|
||||
@Inject(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "TAIL"))
|
||||
public void cobblemon$clientPlayerIcon(LivingEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight, CallbackInfo ci) {
|
||||
ClientPlayerIcon.Companion.onRenderPlayer((Player) entity);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "getRenderOffset(Lnet/minecraft/client/player/AbstractClientPlayer;F)Lnet/minecraft/world/phys/Vec3;", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;isCrouching()Z"))
|
||||
private boolean cobblemon$disableCrouchOffset(AbstractClientPlayer instance, Operation<Boolean> original) {
|
||||
if (instance.isPassenger() && instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Inject(method = "setModelProperties", at = @At("TAIL"))
|
||||
private void cobblemon$setModelProperties(AbstractClientPlayer player, CallbackInfo ci) {
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
PlayerModel<AbstractClientPlayer> playerModel = this.getModel();
|
||||
playerModel.crouching = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "setupRotations(Lnet/minecraft/client/player/AbstractClientPlayer;Lcom/mojang/blaze3d/vertex/PoseStack;FFFF)V",
|
||||
at = @At("HEAD")
|
||||
|
||||
@@ -562,6 +562,9 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("dex"), DexArgumentType::class, SingletonArgumentInfo.contextFree (DexArgumentType::dex))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("npc_class"), NPCClassArgumentType::class, SingletonArgumentInfo.contextFree(NPCClassArgumentType::npcClass))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("wallpaper"), UnlockablePCBoxWallpaperArgumentType::class, SingletonArgumentInfo.contextFree(UnlockablePCBoxWallpaperArgumentType::wallpaper))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("mark"), MarkArgumentType::class, SingletonArgumentInfo.contextFree(MarkArgumentType::mark))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("transform_type"), TransformTypeArgumentType::class, SingletonArgumentInfo.contextFree(TransformTypeArgumentType::transformType))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("model_part"), ModelPartArgumentType::class, SingletonArgumentInfo.contextFree(ModelPartArgumentType::modelPart))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ object CobblemonCommands {
|
||||
ChangeEyeHeight.register(dispatcher)
|
||||
ChangeScaleAndSize.register(dispatcher)
|
||||
ChangeWalkSpeed.register(dispatcher)
|
||||
ChangeJointScaleCommand.register(dispatcher)
|
||||
TransformModelPartCommand.register(dispatcher)
|
||||
TestCommand.register(dispatcher)
|
||||
ReloadShowdownCommand.register(dispatcher)
|
||||
ClickTextCommand.register(dispatcher)
|
||||
@@ -64,6 +64,9 @@ object CobblemonCommands {
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
MarkGiveCommand.register(dispatcher)
|
||||
MarkTakeCommand.register(dispatcher)
|
||||
MarkGiveAllCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -281,7 +281,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@JvmField val DRAGON_SCALE = noSettingsItem("dragon_scale")
|
||||
@JvmField val KINGS_ROCK = noSettingsItem("kings_rock")
|
||||
@JvmField val METAL_COAT = noSettingsItem("metal_coat")
|
||||
@JvmField val UPGRADE = noSettingsItem("upgrade")
|
||||
@JvmField val DUBIOUS_DISC = noSettingsItem("dubious_disc")
|
||||
@@ -660,6 +659,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WATER_STONE = noSettingsItem("water_stone")
|
||||
|
||||
val wearables = mutableListOf<WearableItem>()
|
||||
//Wearable items (these items should have a corresponding 3D model)
|
||||
@JvmField val BLACK_GLASSES = wearableItem("black_glasses")
|
||||
@JvmField val CHOICE_BAND = wearableItem("choice_band")
|
||||
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
|
||||
@JvmField val EXP_SHARE = wearableItem("exp_share")
|
||||
@JvmField val FOCUS_BAND = wearableItem("focus_band")
|
||||
@JvmField val KINGS_ROCK = wearableItem("kings_rock")
|
||||
@JvmField val MUSCLE_BAND = wearableItem("muscle_band")
|
||||
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
|
||||
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
|
||||
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
val ABILITY_SHIELD = heldItem("ability_shield")
|
||||
@@ -676,8 +688,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_GLASSES = heldItem("black_glasses")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@@ -686,12 +696,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
|
||||
@JvmField
|
||||
val CHOICE_BAND = heldItem("choice_band")
|
||||
@JvmField
|
||||
val CHOICE_SCARF = heldItem("choice_scarf")
|
||||
@JvmField
|
||||
val CHOICE_SPECS = heldItem("choice_specs")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
// @JvmField
|
||||
// val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@@ -712,8 +718,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val EVIOLITE = heldItem("eviolite")
|
||||
@JvmField
|
||||
val EXP_SHARE = heldItem("exp_share")
|
||||
@JvmField
|
||||
val EXPERT_BELT = heldItem("expert_belt")
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@@ -722,8 +726,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRASSY_SEED = heldItem("grassy_seed")
|
||||
@@ -758,8 +760,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MUSCLE_BAND = heldItem("muscle_band")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = heldItem("mystic_water")
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = heldItem("never_melt_ice")
|
||||
@@ -790,12 +790,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@@ -832,8 +828,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@@ -1263,6 +1257,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
WearableItem(name).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
|
||||
@@ -29,11 +29,13 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedRegisterHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.ClientboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.OpenCobblemonConfigEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
@@ -73,6 +75,7 @@ import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityP
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.CloseNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.npc.OpenNPCEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -142,7 +145,7 @@ import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPoke
|
||||
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
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -151,6 +154,9 @@ import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScannin
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
@@ -193,6 +199,9 @@ import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanning
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -265,6 +274,13 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(DmaxLevelUpdatePacket.ID, DmaxLevelUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(GmaxFactorUpdatePacket.ID, GmaxFactorUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemUpdatePacket.ID, CosmeticItemUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ActiveMarkUpdatePacket.ID, ActiveMarkUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkAddUpdatePacket.ID, MarkAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRemoveUpdatePacket.ID, MarkRemoveUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkPotentialAddUpdatePacket.ID, MarkPotentialAddUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksUpdatePacket.ID, MarksUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -357,6 +373,7 @@ object CobblemonNetwork {
|
||||
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()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
@@ -387,6 +404,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokemonPasturedPacket.ID, PokemonPasturedPacket::decode, PokemonPasturedHandler))
|
||||
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
|
||||
@@ -413,6 +433,9 @@ object CobblemonNetwork {
|
||||
// Debug / cheats
|
||||
list.add(PacketRegisterInfo(CalculateSeatPositionsPacket.ID, CalculateSeatPositionsPacket::decode, CalculateSeatPositionsHandler))
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -421,6 +444,8 @@ object CobblemonNetwork {
|
||||
// Pokemon Update Packets
|
||||
list.add(PacketRegisterInfo(SetNicknamePacket.ID, SetNicknamePacket::decode, SetNicknameHandler))
|
||||
list.add(PacketRegisterInfo(SetItemHiddenPacket.ID, SetItemHiddenPacket::decode, SetItemHiddenHandler))
|
||||
list.add(PacketRegisterInfo(SetActiveMarkPacket.ID, SetActiveMarkPacket::decode, SetActiveMarkHandler))
|
||||
list.add(PacketRegisterInfo(SetMarkingsPacket.ID, SetMarkingsPacket::decode, SetMarkingsHandler))
|
||||
|
||||
// Evolution Packets
|
||||
list.add(PacketRegisterInfo(AcceptEvolutionPacket.ID, AcceptEvolutionPacket::decode, AcceptEvolutionHandler))
|
||||
@@ -508,8 +533,9 @@ object CobblemonNetwork {
|
||||
// NPC packets
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Orientation packet(s)
|
||||
list.add(PacketRegisterInfo(C2SUpdateOrientationPacket.ID, C2SUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
@@ -21,4 +21,5 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
|
||||
fun updatePostDeath() {}
|
||||
fun handleStatus(status: Byte) {}
|
||||
fun spawnShinyParticle(player: Player) {}
|
||||
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
|
||||
}
|
||||
+13
-1
@@ -8,10 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.fishing
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
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 com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
/**
|
||||
@@ -55,5 +61,11 @@ interface BobberSpawnPokemonEvent {
|
||||
val chosenBucket: SpawnBucket,
|
||||
val bait: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
) : BobberSpawnPokemonEvent {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"chosen_bucket" to ObjectValue(chosenBucket, { it.name }),
|
||||
"bait" to pokemon.level().itemRegistry.wrapAsHolder(bait.item).asMoLangValue(Registries.ITEM),
|
||||
"pokemon_entity" to pokemon.asMoLangValue()
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -8,10 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
data class FossilRevivedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayer?
|
||||
)
|
||||
) {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"pokemon" to pokemon.struct,
|
||||
"player" to (player?.asMoLangValue() ?: DoubleValue.ZERO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.mark
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
class Mark(
|
||||
identifier: ResourceLocation,
|
||||
val name: String,
|
||||
val description: String,
|
||||
val title: String?,
|
||||
@SerializedName(value = "titleColor", alternate = ["titleColour"])
|
||||
val titleColour: String?,
|
||||
val texture: ResourceLocation,
|
||||
val replace: List<ResourceLocation>?,
|
||||
val group: String?,
|
||||
val chance: Float = 0F,
|
||||
val indexNumber: Int?
|
||||
): StringRepresentable {
|
||||
|
||||
companion object {
|
||||
internal fun decode(buffer: RegistryFriendlyByteBuf): Mark {
|
||||
return Mark(
|
||||
buffer.readIdentifier(),
|
||||
buffer.readString(),
|
||||
buffer.readString(),
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readResourceLocation(),
|
||||
buffer.readNullable { buffer.readList { buffer.readResourceLocation() } },
|
||||
buffer.readNullable { buffer.readString() },
|
||||
buffer.readFloat(),
|
||||
buffer.readNullable { buffer.readInt() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Transient
|
||||
var identifier: ResourceLocation = identifier
|
||||
internal set
|
||||
|
||||
override fun getSerializedName(): String = identifier.toString()
|
||||
|
||||
fun getName(): MutableComponent = name.asTranslated()
|
||||
|
||||
fun getDescription(): MutableComponent = description.asTranslated()
|
||||
|
||||
fun getTitle(name: MutableComponent): MutableComponent {
|
||||
title?.let {
|
||||
try {
|
||||
return if (titleColour != null) it.asTranslated(name.withColor(-1)).withColor(titleColour.toInt(16))
|
||||
else it.asTranslated(name)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Error parsing titleColor hexadecimal color code for {}", identifier, e)
|
||||
return it.asTranslated(name)
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fun getChanceGroup(): Pair<String, Float> = Pair(group ?: chance.toString(), chance)
|
||||
|
||||
internal fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeIdentifier(identifier)
|
||||
buffer.writeString(name)
|
||||
buffer.writeString(description)
|
||||
buffer.writeNullable(title) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeNullable(titleColour) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeResourceLocation(texture)
|
||||
buffer.writeNullable(replace) { _, v -> buffer.writeCollection(v) { _, resource -> buffer.writeResourceLocation(resource) } }
|
||||
buffer.writeNullable(group) { _, v -> buffer.writeString(v) }
|
||||
buffer.writeFloat(chance)
|
||||
buffer.writeNullable(indexNumber) { _, v -> buffer.writeInt(v) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.mark
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
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.MarkRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
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
|
||||
|
||||
object Marks: JsonDataRegistry<Mark> {
|
||||
|
||||
override val id: ResourceLocation = cobblemonResource("marks")
|
||||
override val type: PackType = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Marks>()
|
||||
override val typeToken: TypeToken<Mark> = TypeToken.get(Mark::class.java)
|
||||
override val resourcePath: String = "marks"
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
private val marks = hashMapOf<ResourceLocation, Mark>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Mark>) {
|
||||
this.marks.clear()
|
||||
data.forEach { (identifier, mark) ->
|
||||
try {
|
||||
mark.identifier = identifier
|
||||
this.marks[identifier] = mark
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Skipped loading the {} mark", identifier, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} marks", this.marks.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
MarkRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all loaded [Mark]s.
|
||||
*/
|
||||
fun all() = this.marks.values.toList()
|
||||
fun identifiers(): Collection<String> = marks.keys.toSet().map { it.toString() }
|
||||
|
||||
/**
|
||||
* Gets a [Mark] by its [ResourceLocation].
|
||||
* @param identifier The identifier of the mark.
|
||||
* @return The [Mark] if loaded, otherwise null.
|
||||
*/
|
||||
fun getByIdentifier(identifier: ResourceLocation): Mark? = this.marks[identifier]
|
||||
}
|
||||
@@ -17,31 +17,20 @@ import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.dialogue.ReferenceDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
|
||||
import com.cobblemon.mod.common.api.pokedex.AbstractPokedexManager
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtCount
|
||||
import com.cobblemon.mod.common.api.pokedex.CaughtPercent
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexManager
|
||||
import com.cobblemon.mod.common.api.pokedex.SeenCount
|
||||
import com.cobblemon.mod.common.api.pokedex.SeenPercent
|
||||
import com.cobblemon.mod.common.api.pokedex.*
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
@@ -52,8 +41,7 @@ import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCBattleActor
|
||||
@@ -71,13 +59,8 @@ import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
|
||||
import com.cobblemon.mod.common.pokemon.riding.controllers.BirdAirController
|
||||
import com.cobblemon.mod.common.pokemon.riding.states.BirdAirState
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.util.UUID
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.commands.arguments.EntityAnchorArgument
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
@@ -85,11 +68,7 @@ import net.minecraft.core.Registry
|
||||
import net.minecraft.core.RegistryAccess
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.DoubleTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.nbt.*
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.MinecraftServer
|
||||
@@ -98,11 +77,7 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.damagesource.DamageTypes
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.*
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
@@ -114,8 +89,12 @@ import net.minecraft.world.level.Level.ExplosionInteraction
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.dimension.DimensionType
|
||||
import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.*
|
||||
import kotlin.math.sqrt
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -236,6 +215,22 @@ object MoLangFunctions {
|
||||
val z = params.getInt(2)
|
||||
return@put DoubleValue(world.isRainingAt(BlockPos(x, y, z)))
|
||||
}
|
||||
map.put("is_snowing_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
val z = params.getInt(2)
|
||||
val blockPos = BlockPos(x, y, z)
|
||||
if (!world.isRaining()) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else if (!world.canSeeSky(blockPos)) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else if (world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, blockPos).getY() > blockPos.getY()) {
|
||||
return@put DoubleValue.ZERO
|
||||
} else {
|
||||
val biome = world.getBiome(blockPos).value() as Biome
|
||||
return@put DoubleValue(biome.getPrecipitationAt(blockPos) == Biome.Precipitation.SNOW)
|
||||
}
|
||||
}
|
||||
map.put("is_chunk_loaded_at") { params ->
|
||||
val x = params.getInt(0)
|
||||
val y = params.getInt(1)
|
||||
@@ -291,16 +286,11 @@ object MoLangFunctions {
|
||||
} as? ServerPlayer
|
||||
val pos = Vec3(x, y, z)
|
||||
|
||||
if (world !is ClientLevel) {
|
||||
val packet = SpawnSnowstormParticlePacket(particle, pos)
|
||||
if (player != null) {
|
||||
packet.sendToPlayer(player)
|
||||
} else {
|
||||
packet.sendToPlayersAround(x, y, z, 64.0, world.dimension())
|
||||
}
|
||||
val packet = SpawnSnowstormParticlePacket(particle, pos)
|
||||
if (player != null) {
|
||||
packet.sendToPlayer(player)
|
||||
} else {
|
||||
val effect = BedrockParticleOptionsRepository.getEffect(particle) ?: return@put DoubleValue.ZERO
|
||||
ParticleStorm.createAtPosition(world, effect, pos).spawn()
|
||||
packet.sendToPlayersAround(x, y, z, 64.0, world.dimension())
|
||||
}
|
||||
}
|
||||
map.put("get_entities_around") { params ->
|
||||
@@ -469,6 +459,7 @@ object MoLangFunctions {
|
||||
map.put("is_sneaking") { _ -> DoubleValue(entity.isShiftKeyDown) }
|
||||
map.put("is_sprinting") { _ -> DoubleValue(entity.isSprinting) }
|
||||
map.put("is_in_water") { _ -> DoubleValue(entity.isUnderWater) }
|
||||
map.put("is_in_rain") { _ -> DoubleValue(entity.isInWaterOrRain && !entity.isInWater) }
|
||||
map.put("is_touching_water_or_rain") { _ -> DoubleValue(entity.isInWaterRainOrBubble) }
|
||||
map.put("is_touching_water") { _ -> DoubleValue(entity.isInWater) }
|
||||
map.put("is_underwater") { DoubleValue(entity.getIsSubmerged()) }
|
||||
@@ -740,6 +731,8 @@ object MoLangFunctions {
|
||||
map.put("npc") { battleActor.entity.struct }
|
||||
} else if (battleActor is PlayerBattleActor) {
|
||||
map.put("player") { battleActor.entity?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
} else if (battleActor is PokemonBattleActor) {
|
||||
map.put("pokemon") { battleActor.entity?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
}
|
||||
return@mutableListOf map
|
||||
}
|
||||
@@ -778,6 +771,34 @@ object MoLangFunctions {
|
||||
DoubleValue.ONE
|
||||
}
|
||||
map.put("owner") { pokemon.getOwnerPlayer()?.asMoLangValue() ?: DoubleValue.ZERO }
|
||||
map.put("add_marks") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) pokemon.exchangeMark(mark, true)
|
||||
}
|
||||
}
|
||||
map.put("add_marks_with_chance") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
mark?.let {
|
||||
val probability = it.chance.coerceIn(0F, 1F) * 100
|
||||
val randomValue = Random.nextDouble(0.0, 100.0)
|
||||
if (randomValue < probability) pokemon.exchangeMark(it, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
map.put("add_potential_marks") { params ->
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) pokemon.addPotentialMark(mark)
|
||||
}
|
||||
}
|
||||
map.put("apply_potential_marks") {
|
||||
return@put DoubleValue(pokemon.applyPotentialMarks())
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
@@ -1438,4 +1459,4 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
|
||||
+5
-5
@@ -6,10 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.states
|
||||
package com.cobblemon.mod.common.api.net.serializers
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
object RidingStateSerializer {
|
||||
|
||||
class RunUpToFlightCompositeState(pokemonEntity: PokemonEntity) : CompositeState(pokemonEntity) {
|
||||
var currSpeed: Double = 0.0
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.orientation
|
||||
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.asin
|
||||
|
||||
open class OrientationController(val entity: LivingEntity) {
|
||||
|
||||
companion object {
|
||||
val FORWARDS: Vector3f = Vector3f(0.0f, 0.0f, -1.0f)
|
||||
val UP: Vector3f = Vector3f(0.0f, 1.0f, 0.0f)
|
||||
val LEFT: Vector3f = Vector3f(-1.0f, 0.0f, 0.0f)
|
||||
}
|
||||
|
||||
open var active: Boolean = false
|
||||
|
||||
var orientation: Matrix3f? = null
|
||||
private set
|
||||
|
||||
private var renderOrientationO: Matrix3f? = null
|
||||
private var renderOrientation: Matrix3f? = null
|
||||
|
||||
/** Adding this simply because it irritates me seeing `getActive` when most of this is Java. */
|
||||
fun isActive() = active
|
||||
|
||||
fun updateOrientation(fn: (Matrix3f) -> Matrix3f?) {
|
||||
if (!active) return
|
||||
if (orientation == null) {
|
||||
orientation = Matrix3f()
|
||||
rotate(entity.yRot - 180, entity.xRot, 0f)
|
||||
}
|
||||
orientation = fn(orientation!!)
|
||||
entity.yRot = yaw
|
||||
entity.xRot = pitch
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
orientation = null
|
||||
renderOrientationO = null
|
||||
renderOrientation = null
|
||||
active = false
|
||||
}
|
||||
|
||||
fun rotate(yaw: Float, pitch: Float, roll: Float) {
|
||||
rotateYaw(yaw)
|
||||
rotatePitch(pitch)
|
||||
rotateRoll(roll)
|
||||
}
|
||||
|
||||
fun getRenderOrientation(delta: Float): Quaternionf {
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation
|
||||
val new = renderOrientation ?: old
|
||||
val oldQuat = Quaternionf().setFromUnnormalized(old)
|
||||
val newQuat = Quaternionf().setFromUnnormalized(new)
|
||||
oldQuat.slerp(newQuat, delta)
|
||||
return oldQuat
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!active || orientation == null) return
|
||||
renderOrientationO = renderOrientation
|
||||
val current = orientation
|
||||
val renderMatrix = this.renderOrientation ?: current
|
||||
val renderQuat = Quaternionf().setFromUnnormalized(renderMatrix)
|
||||
val targetQuat = Quaternionf().setFromUnnormalized(current)
|
||||
val dampingFactor = 0.66f // We can change this factor for faster transitions
|
||||
renderQuat.slerp(targetQuat, dampingFactor)
|
||||
|
||||
val newRenderOrientation = Matrix3f()
|
||||
renderQuat.get(newRenderOrientation)
|
||||
renderOrientation = newRenderOrientation
|
||||
}
|
||||
|
||||
val forwardVector: Vector3f
|
||||
get() = orientation?.transform(FORWARDS, Vector3f()) ?: Vector3f(FORWARDS)
|
||||
|
||||
val leftVector: Vector3f
|
||||
get() = orientation?.transform(LEFT, Vector3f()) ?: Vector3f(LEFT)
|
||||
|
||||
val upVector : Vector3f
|
||||
get() = orientation?.transform(UP, Vector3f()) ?: Vector3f(UP)
|
||||
|
||||
fun rotateYaw(yaw: Float) = updateOrientation { it.rotateY(-yaw.toRadians()) }
|
||||
fun rotatePitch(pitch: Float) = updateOrientation { it.rotateX(-pitch.toRadians()) }
|
||||
fun rotateRoll(roll: Float) = updateOrientation { it.rotateZ(-roll.toRadians()) }
|
||||
|
||||
val yaw: Float
|
||||
get() = Mth.wrapDegrees(-FORWARDS.angleSigned(forwardVector, UP).toDegrees() + 180)
|
||||
|
||||
val pitch: Float
|
||||
get() = Mth.wrapDegrees(-asin(forwardVector.y).toDegrees())
|
||||
|
||||
val roll: Float
|
||||
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
|
||||
|
||||
}
|
||||
+4
-1
@@ -20,7 +20,7 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val CHANGE_WALK_SPEED = this.create("${COMMAND_PREFIX}changewalkspeed", PermissionLevel.ALL_COMMANDS)
|
||||
@JvmStatic
|
||||
val CHANGE_JOINT_SCALE = this.create("${COMMAND_PREFIX}changejointscale", PermissionLevel.ALL_COMMANDS)
|
||||
val TRANSFORM_MODEL_PART = this.create("${COMMAND_PREFIX}transformmodelpart", PermissionLevel.ALL_COMMANDS)
|
||||
@JvmStatic
|
||||
val CHECKSPAWNS = this.create("${COMMAND_PREFIX}checkspawns", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
@@ -90,6 +90,9 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val HELD_ITEM = this.create("${COMMAND_PREFIX}helditem", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val CHANGE_MARK = this.create("${COMMAND_PREFIX}changemark", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
val PC = this.create("${COMMAND_PREFIX}pc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.cobblemon.mod.common.api.pokemon.moves.Learnset
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
@@ -48,7 +48,7 @@ import com.cobblemon.mod.common.pokemon.evolution.adapters.CobblemonRequirementA
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.google.common.collect.HashBasedTable
|
||||
@@ -107,7 +107,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(EggGroup::class.java, EggGroupAdapter)
|
||||
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(RideController::class.java, RideControllerAdapter)
|
||||
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
|
||||
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.disableHtmlEscaping()
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import net.minecraft.world.entity.PlayerRideableJumping
|
||||
|
||||
/**
|
||||
@@ -20,6 +23,6 @@ interface Rideable : PlayerRideableJumping {
|
||||
/**
|
||||
* Denotes the manager responsible for handling any instance of riding taking place on an entity
|
||||
*/
|
||||
val riding: RidingManager
|
||||
val riding: RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.controller
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
@@ -29,4 +29,4 @@ class RidingAnimation(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,220 +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.riding
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.toProperties
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
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 kotlin.math.sin
|
||||
import kotlin.math.sin
|
||||
|
||||
data class RidingManager(val entity: PokemonEntity) {
|
||||
var lastSpeed = 0F
|
||||
var states: MutableMap<ResourceLocation, RidingState> = mutableMapOf()
|
||||
var deltaRotation = Vec2.ZERO
|
||||
|
||||
val runtime: MoLangRuntime by lazy {
|
||||
MoLangRuntime()
|
||||
.setup()
|
||||
.withQueryValue("entity", entity.struct)
|
||||
.also {
|
||||
it.environment.query.addFunction("passenger_count") { DoubleValue(entity.passengers.size.toDouble()) }
|
||||
it.environment.query.addFunction("get_ride_stats") { params ->
|
||||
val rideStat = RidingStat.valueOf(params.getString(0).uppercase())
|
||||
val rideStyle = RidingStyle.valueOf(params.getString(1).uppercase())
|
||||
val maxVal = params.getDouble(2)
|
||||
val minVal = params.getDouble(3)
|
||||
//TODO: Use the mons actual boost once implemented
|
||||
val normalizedStat = entity.rideProp.calculate(rideStat, rideStyle, 0) / 100.0f
|
||||
val trueStatVal = (normalizedStat * (maxVal - minVal)) + minVal
|
||||
|
||||
DoubleValue(trueStatVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : RidingState> getState(id: ResourceLocation, constructor: (PokemonEntity) -> T): T {
|
||||
val storedState = states[id]
|
||||
if (storedState == null) {
|
||||
val newState = constructor(entity)
|
||||
states[id] = newState
|
||||
return newState
|
||||
}
|
||||
|
||||
return storedState as T
|
||||
}
|
||||
|
||||
fun getController(entity: PokemonEntity): RideController? {
|
||||
return entity.pokemon.riding.controller?.takeIf { it.condition.invoke(entity) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for handling riding conditions and transitions amongst controllers. This will tick
|
||||
* whenever the entity receives a tickControlled interaction.
|
||||
*/
|
||||
fun tick(entity: PokemonEntity, driver: Player, input: Vec3) {
|
||||
val controller = getController(entity) ?: return
|
||||
|
||||
val pose = controller.pose(entity)
|
||||
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
|
||||
//val speedPlayer = driver.deltaMovement.horizontalDistance()
|
||||
//driver.displayClientMessage(Component.literal("Speed player: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("$speedPlayer b/t")), true)
|
||||
//val speedEntity = entity.deltaMovement.length() //* 20 * 60 * 60) / ( 1000 )
|
||||
//println(speedEntity)
|
||||
//driver.displayClientMessage(Component.literal("Speed: ").withStyle { it.withColor(ChatFormatting.GREEN) }.append(Component.literal("${String.format("%.2f", speedEntity)} km/h")), true)
|
||||
|
||||
}
|
||||
|
||||
fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 0.05F
|
||||
this.lastSpeed = controller.speed(entity, driver)
|
||||
return this.lastSpeed
|
||||
}
|
||||
|
||||
fun controlledRotation(entity: PokemonEntity, driver: Player): Vec2 {
|
||||
val controller = getController(entity) ?: return entity.rotationVector
|
||||
val previousRotation = entity.rotationVector
|
||||
val rotation = controller.rotation(entity, driver)
|
||||
this.deltaRotation = Vec2(rotation.x - previousRotation.x, rotation.y - previousRotation.y)
|
||||
return rotation
|
||||
}
|
||||
|
||||
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
val controller = getController(entity) ?: return
|
||||
return controller.clampPassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
val controller = getController(entity) ?: return
|
||||
return controller.updatePassengerRotation(entity, driver)
|
||||
}
|
||||
|
||||
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.velocity(entity, driver, input)
|
||||
}
|
||||
|
||||
fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 0.0f
|
||||
return controller.setRideBar(entity, driver)
|
||||
}
|
||||
|
||||
fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val controller = getController(entity) ?: return 1.0f
|
||||
return controller.rideFovMult(entity, driver)
|
||||
}
|
||||
|
||||
fun canJump(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.canJump(entity, driver)
|
||||
}
|
||||
|
||||
fun jumpVelocity(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.jumpForce(entity, driver, jumpStrength)
|
||||
}
|
||||
|
||||
fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.useRidingAltPose(entity, driver)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to supply the delta for the lerp() between velocity
|
||||
* vectors. Called inertia for now as the way it feels when
|
||||
* affecting the ride is somewhat akin to inertia.
|
||||
*/
|
||||
fun inertia(entity: PokemonEntity): Double {
|
||||
val controller = getController(entity) ?: return 0.5
|
||||
return controller.inertia(entity)
|
||||
}
|
||||
|
||||
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? {
|
||||
val controller = getController(entity) ?: return null
|
||||
return controller.gravity(entity, regularGravity)
|
||||
}
|
||||
|
||||
//Maybe should be changed to be a function that conveys:
|
||||
// "turn on use our camera system function"
|
||||
fun shouldRoll(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRoll(entity)
|
||||
}
|
||||
|
||||
fun shouldRotatePlayerHead(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRotatePlayerHead()
|
||||
}
|
||||
|
||||
fun shouldRotatePokemonHead(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.shouldRotatePokemonHead()
|
||||
}
|
||||
|
||||
fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3.ZERO
|
||||
return controller.rotationOnMouseXY(
|
||||
entity,
|
||||
driver,
|
||||
yMouse,
|
||||
xMouse,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
) }
|
||||
|
||||
/**
|
||||
* Determines whether mouse input will affect the rotation of
|
||||
* the rollable object. Need to remove this as it's not used anymore
|
||||
*/
|
||||
//I think this might better serve as a "use smoothing on angular velocity"
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return true
|
||||
return controller.useAngVelSmoothing(entity)
|
||||
}
|
||||
|
||||
fun turnOffOnGround(entity: PokemonEntity): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.turnOffOnGround(entity)
|
||||
}
|
||||
|
||||
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
val controller = getController(entity) ?: return Vec3(0.0, 0.0, 0.0)
|
||||
return controller.angRollVel(entity, driver, deltaTime)
|
||||
}
|
||||
|
||||
fun dismountOnShift(): Boolean {
|
||||
val controller = getController(entity) ?: return false
|
||||
return controller.dismountOnShift(entity)
|
||||
}
|
||||
}
|
||||
@@ -9,44 +9,40 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.controller.RideController
|
||||
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
|
||||
import com.cobblemon.mod.common.util.adapters.RideControllerAdapter
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class RidingProperties(
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = mapOf(),
|
||||
val seats: List<Seat> = listOf(),
|
||||
val conditions: List<Expression> = listOf(),
|
||||
val controller: RideController? = null
|
||||
val behaviour: RidingBehaviourSettings? = null
|
||||
) {
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = buffer.readMap(
|
||||
{ buffer.readEnum<RidingStat>(RidingStat::class.java) },
|
||||
{ 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 controller = buffer.readNullable { _ ->
|
||||
val key = buffer.readIdentifier()
|
||||
val controller = RideControllerAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
|
||||
controller.decode(buffer)
|
||||
return@readNullable controller
|
||||
val behaviour = buffer.readNullable { _ ->
|
||||
val key = buffer.readResourceLocation()
|
||||
val settings = RidingBehaviourSettingsAdapter.types[key]?.getConstructor()?.newInstance() ?: error("Unknown controller key: $key")
|
||||
settings.decode(buffer)
|
||||
return@readNullable settings
|
||||
}
|
||||
|
||||
return RidingProperties(stats = stats, seats = seats, conditions = conditions, controller = controller)
|
||||
return RidingProperties(stats = stats, seats = seats, conditions = conditions, behaviour = behaviour)
|
||||
}
|
||||
}
|
||||
|
||||
val canRide: Boolean
|
||||
get() = seats.isNotEmpty() && controller != null
|
||||
get() = seats.isNotEmpty() && behaviour != null
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeMap(
|
||||
@@ -56,7 +52,10 @@ class RidingProperties(
|
||||
)
|
||||
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
|
||||
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
|
||||
buffer.writeNullable(controller) { _, controller -> controller.encode(buffer) }
|
||||
buffer.writeNullable(behaviour) { _, behaviour ->
|
||||
buffer.writeResourceLocation(behaviour.key)
|
||||
behaviour.encode(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
fun calculate(stat: RidingStat, style: RidingStyle, boosts: Int): Float {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
/**
|
||||
* Honestly having a base interface is probably unnecessary I'm just considering whether there's going to be some
|
||||
* kind of shared state later.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 6th, 2024
|
||||
*/
|
||||
interface RidingState
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.controller.RidingAnimation
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
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
|
||||
|
||||
/**
|
||||
* Represents the behaviour of a Pokemon when being ridden.
|
||||
* This is intended to contain the logic for how a Pokemon should behave when being ridden.
|
||||
*
|
||||
* This class should remain stateless as it is intended to be shared between multiple instances of Pokemon.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBehaviourState> {
|
||||
val key: ResourceLocation
|
||||
|
||||
fun isActive(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun tick(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, input: Vec3) {}
|
||||
|
||||
fun pose(settings: Settings, state: State, vehicle: PokemonEntity): PoseType
|
||||
|
||||
fun speed(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun clampPassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun updatePassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2
|
||||
|
||||
fun velocity(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, input: Vec3): Vec3
|
||||
|
||||
fun angRollVel(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, deltaTime: Double): Vec3
|
||||
|
||||
fun rotationOnMouseXY(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3
|
||||
|
||||
fun canJump(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
|
||||
|
||||
fun setRideBar(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun jumpForce(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, jumpStrength: Int): Vec3
|
||||
|
||||
fun gravity(settings: Settings, state: State, vehicle: PokemonEntity, regularGravity: Double): Double
|
||||
|
||||
fun rideFovMultiplier(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun useAngVelSmoothing(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
|
||||
|
||||
fun inertia(settings: Settings, state: State, vehicle: PokemonEntity): Double
|
||||
|
||||
fun shouldRoll(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun turnOffOnGround(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun dismountOnShift(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun shouldRotatePokemonHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun shouldRotatePlayerHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun createDefaultState(): State
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* Represents static settings of a riding behaviour.
|
||||
* Values in this class are intended to be constant and not change during the riding process.
|
||||
* Typically this will be initialized for each pokemon form during deserialization
|
||||
* to determine how they should ride.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviourSettings: Encodable, Decodable {
|
||||
val key: ResourceLocation
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.ifClient
|
||||
import com.cobblemon.mod.common.util.ifServer
|
||||
import net.minecraft.client.player.RemotePlayer
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* Represents the state of a Pokemon when being ridden.
|
||||
* This is intended to contain mutable state that is passed between the client and server
|
||||
* or temporary state that is used during the riding process.
|
||||
*
|
||||
* This will be destroyed when the a user dismounts the Pokemon.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
interface RidingBehaviourState : Encodable, Decodable {
|
||||
fun reset()
|
||||
fun copy(): RidingBehaviourState
|
||||
fun shouldSync(previous: RidingBehaviourState): Boolean
|
||||
}
|
||||
|
||||
object NoState : RidingBehaviourState {
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
override fun copy() = NoState
|
||||
override fun reset() = Unit
|
||||
override fun shouldSync(previous: RidingBehaviourState) = false
|
||||
}
|
||||
|
||||
fun <T> ridingState(value: T, side: Side) = SidedRidingState(value, side)
|
||||
|
||||
class SidedRidingState<T>(private var value: T, val side: Side) {
|
||||
fun get() = value
|
||||
|
||||
fun set(value: T, forced: Boolean = false) {
|
||||
if (forced) {
|
||||
this.value = value
|
||||
}
|
||||
else {
|
||||
when (side) {
|
||||
Side.BOTH -> { this.value = value }
|
||||
Side.CLIENT -> { ifClient { this.value = value } }
|
||||
Side.SERVER -> { ifServer { this.value = value } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other is SidedRidingState<*>) {
|
||||
return value == other.value
|
||||
}
|
||||
return super.equals(other)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
enum class Side {
|
||||
SERVER, CLIENT, BOTH
|
||||
}
|
||||
|
||||
enum class DriverSide {
|
||||
LOCAL, REMOTE, BOTH
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.*
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object RidingBehaviours {
|
||||
val behaviours = mutableMapOf<ResourceLocation, RidingBehaviour<*, *>>()
|
||||
|
||||
init {
|
||||
register(BirdAirBehaviour.KEY, BirdAirBehaviour())
|
||||
register(DolphinBehaviour.KEY, DolphinBehaviour())
|
||||
register(FallToGlideCompositeBehaviour.KEY, FallToGlideCompositeBehaviour())
|
||||
register(GenericLandBehaviour.KEY, GenericLandBehaviour())
|
||||
register(GenericSwimBehaviour.KEY, GenericSwimBehaviour())
|
||||
register(GliderAirBehaviour.KEY, GliderAirBehaviour())
|
||||
register(HelicopterBehaviour.KEY, HelicopterBehaviour())
|
||||
register(JetAirBehaviour.KEY, JetAirBehaviour())
|
||||
register(JumpToFlightCompositeBehaviour.KEY, JumpToFlightCompositeBehaviour())
|
||||
register(RunToJetCompositeBehaviour.KEY, RunToJetCompositeBehaviour())
|
||||
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
|
||||
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
|
||||
}
|
||||
|
||||
fun register(key: ResourceLocation, behaviour: RidingBehaviour<*, *>) {
|
||||
if (behaviours.contains(key)) error("Behaviour already registered to key $key")
|
||||
behaviours[key] = RidingController(behaviour)
|
||||
}
|
||||
|
||||
fun get(key: ResourceLocation): RidingBehaviour<*, *> {
|
||||
if (!behaviours.contains(key)) error("Behaviour not registered to key $key")
|
||||
return behaviours[key]!!
|
||||
}
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
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
|
||||
|
||||
/**
|
||||
* Small wrapper around a RidingBehaviour to provide sane defaults in the event that the behaviour is not active.
|
||||
*
|
||||
* @author landonjw
|
||||
*/
|
||||
class RidingController<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(val behaviour: RidingBehaviour<Settings, State>) : RidingBehaviour<Settings, State> {
|
||||
|
||||
override val key = behaviour.key
|
||||
|
||||
override fun isActive(settings: Settings, state: State, vehicle: PokemonEntity) =
|
||||
behaviour.isActive(settings, state, vehicle)
|
||||
|
||||
override fun tick(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player, input: Vec3) =
|
||||
behaviour.tick(settings, state, vehicle, driver, input)
|
||||
|
||||
override fun pose(settings: Settings, state: State, vehicle: PokemonEntity) =
|
||||
behaviour.pose(settings, state, vehicle)
|
||||
|
||||
override fun speed(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float {
|
||||
if (!isActive(settings, state, vehicle)) return 0.0F
|
||||
return behaviour.speed(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
if (!isActive(settings, state, vehicle)) return vehicle.rotationVector
|
||||
return behaviour.rotation(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
if (!isActive(settings, state, vehicle)) return Vec3.ZERO
|
||||
return behaviour.velocity(settings, state, vehicle, driver, input)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (!isActive(settings, state, vehicle)) return Vec3.ZERO
|
||||
return behaviour.angRollVel(settings, state, vehicle, driver, deltaTime)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (!isActive(settings, state, vehicle)) return Vec3.ZERO
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
}
|
||||
|
||||
override fun canJump(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.canJump(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.shouldRotatePlayerHead(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.shouldRotatePokemonHead(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.dismountOnShift(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.turnOffOnGround(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
return behaviour.shouldRoll(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun inertia(settings: Settings, state: State, vehicle: PokemonEntity): Double {
|
||||
if (!isActive(settings, state, vehicle)) return 0.5
|
||||
return behaviour.inertia(settings, state, vehicle)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: Settings, state: State, vehicle: PokemonEntity): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return true
|
||||
return behaviour.useAngVelSmoothing(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float {
|
||||
if (!isActive(settings, state, vehicle)) return 1.0F
|
||||
return behaviour.rideFovMultiplier(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun gravity(settings: Settings, state: State, vehicle: PokemonEntity, regularGravity: Double): Double {
|
||||
if (!isActive(settings, state, vehicle)) return regularGravity
|
||||
return behaviour.gravity(settings, state, vehicle, regularGravity)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
if (!isActive(settings, state, vehicle)) return Vec3.ZERO
|
||||
return behaviour.jumpForce(settings, state, vehicle, driver, jumpStrength)
|
||||
}
|
||||
|
||||
override fun setRideBar(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float {
|
||||
if (!isActive(settings, state, vehicle)) return 0.0F
|
||||
return behaviour.setRideBar(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun createDefaultState(): State {
|
||||
return behaviour.createDefaultState()
|
||||
}
|
||||
|
||||
}
|
||||
+525
@@ -0,0 +1,525 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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.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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/bird")
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
|
||||
val poseProvider = PoseProvider<BirdAirSettings, BirdAirState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVel.get().z > 0.2 })
|
||||
|
||||
override fun isActive(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return state.rideVel.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
var yVel = 0.0
|
||||
var leftForce = 0.0
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Need to deadzone this when straight up or down
|
||||
|
||||
upForce += -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().z
|
||||
forwardForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().z
|
||||
|
||||
upForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().y
|
||||
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().y
|
||||
}
|
||||
|
||||
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina.get() <= 0.0) {
|
||||
upForce -= 0.3
|
||||
}
|
||||
|
||||
val altitudeLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (vehicle.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(state.rideVel.get().x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity, driver: Player) {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
|
||||
var glideSpeedChange = 0.0
|
||||
|
||||
val currSpeed = state.rideVel.get().length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
var newVelocity = Vec3(state.rideVel.get().x, state.rideVel.get().y, state.rideVel.get().z)
|
||||
|
||||
//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 {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null) {
|
||||
//Base glide speed change on current pitch of the ride.
|
||||
glideSpeedChange = sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
glideSpeedChange = glideSpeedChange.pow(3) * 0.5
|
||||
|
||||
//TODO: Possibly create a deadzone around parallel where glide doesn't affect speed?
|
||||
if (glideSpeedChange <= 0.0) {
|
||||
//Ensures that a propelling force is still able to be applied when
|
||||
//climbing in height
|
||||
if (driver.zza <= 0) {
|
||||
//speed decrease should be 2x speed increase?
|
||||
//state.currSpeed = max(state.currSpeed + (0.0166) * glideSpeedChange, 0.0 )
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
lerp( newVelocity.z, 0.0,glideSpeedChange * -0.0166 * 2 )
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// only add to the speed if it hasn't exceeded the current
|
||||
//glide angles maximum amount of speed that it can give.
|
||||
//state.currSpeed = min(state.currSpeed + ((0.0166 * 2) * glideSpeedChange), maxGlideSpeed)
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
min(newVelocity.z + ((0.0166 * 2) * glideSpeedChange), glideTopSpeed)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//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 {
|
||||
driver.jumping -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
if (vertInput != 0.0 && state.stamina.get() > 0.0) {
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
(newVelocity.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
newVelocity.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
lerp(newVelocity.y, 0.0, vertTopSpeed / 20.0),
|
||||
newVelocity.z)
|
||||
}
|
||||
|
||||
//Check if the ride should be gliding
|
||||
if (driver.isLocalPlayer) {
|
||||
if (activeInput && state.stamina.get() > 0.0) {
|
||||
state.gliding.set(false)
|
||||
} else {
|
||||
state.gliding.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
//Only perform stamina logic if the ride does not have infinite stamina
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
if (activeInput) {
|
||||
state.stamina.set(state.stamina.get() - (0.05 / staminaStat).toFloat())
|
||||
}
|
||||
|
||||
//Lose a base amount of stamina just for being airborne
|
||||
state.stamina.set(state.stamina.get() - (0.01 / staminaStat).toFloat())
|
||||
}
|
||||
else
|
||||
{
|
||||
state.stamina.set(1.0f)
|
||||
}
|
||||
|
||||
//air resistance
|
||||
if( abs(newVelocity.z) > 0) {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.003 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
state.rideVel.set(newVelocity)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
//TODO: Tie into handling
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val rotationChangeRate = 10.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
|
||||
|
||||
return Vec3(yawForce, pitchForce, 0.0)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
|
||||
val mouseYc = (mouseY).coerceIn(-60.0, 60.0)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
|
||||
//limit rolling based on handling and current speed.
|
||||
//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(handling * normalizeVal(state.rideVel.get().length(), 0.0, topSpeed).pow(3), rotMin)
|
||||
|
||||
//Limit roll by non linearly decreasing inputs towards
|
||||
// a rotation limit based on the current distance from
|
||||
// that rotation limit
|
||||
if (abs(controller.roll + rollForce) < rotLimit) {
|
||||
if (sign(rollForce) == sign(controller.roll).toDouble()) {
|
||||
val d = abs(abs(controller.roll) - rotLimit)
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
} 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 - normalizeVal(state.rideVel.get().length(), 0.0, topSpeed).pow(3))
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawForce, yInput, rollForce)
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the given value between a min and a max.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents x is at or below min
|
||||
* and 1.0 represents x is at or above it.
|
||||
*/
|
||||
private fun normalizeVal(x: Double, min: Double, max: Double): Double {
|
||||
require(max > min) { "max must be greater than min" }
|
||||
return ((x - min) / (max - min)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = normalizeVal(state.rideVel.get().length(), topSpeed, glideTopSpeed)
|
||||
|
||||
//Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedGlideSpeed.pow(2).toFloat() * 0.2f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return state.gliding.get()
|
||||
}
|
||||
|
||||
override fun inertia(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = BirdAirState()
|
||||
|
||||
}
|
||||
|
||||
class BirdAirSettings : RidingBehaviourSettings {
|
||||
override val key = BirdAirBehaviour.KEY
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
//max y level for the ride
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
|
||||
var glidespeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(glidespeedExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
glidespeedExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class BirdAirState : RidingBehaviourState {
|
||||
var rideVel = ridingState(Vec3.ZERO, Side.CLIENT)
|
||||
var stamina = ridingState(1.0f, Side.CLIENT)
|
||||
var gliding = ridingState(false, Side.CLIENT)
|
||||
var lastGlide = ridingState(-100L, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeVec3(rideVel.get())
|
||||
buffer.writeFloat(stamina.get())
|
||||
buffer.writeBoolean(gliding.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideVel.set(buffer.readVec3(), forced = true)
|
||||
stamina.set(buffer.readFloat(), forced = true)
|
||||
gliding.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
rideVel.set(Vec3.ZERO, forced = true)
|
||||
stamina.set(1.0f, forced = true)
|
||||
gliding.set(false, forced = true)
|
||||
lastGlide.set(-100L, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "BirdAirState(rideVel=${rideVel.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = BirdAirState().also {
|
||||
it.rideVel.set(this.rideVel.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.gliding.set(this.gliding.get(), forced = true)
|
||||
it.lastGlide.set(this.lastGlide.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is BirdAirState) return false
|
||||
if (previous.rideVel != rideVel) return true
|
||||
if (previous.stamina != stamina) return true
|
||||
if (previous.gliding != gliding) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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.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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/dolphin")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any (blockState.isAir || !blockState.fluidState.isEmpty ) ||
|
||||
(vehicle.isInWater || vehicle.isUnderWater)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
|
||||
if (!vehicle.isInWater && !vehicle.isUnderWater)
|
||||
{
|
||||
state.lastVelocity.set(Vec3(state.lastVelocity.get().x, state.lastVelocity.get().y - 0.035, state.lastVelocity.get().z))
|
||||
return state.lastVelocity.get()
|
||||
}
|
||||
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
|
||||
var yComp = 0.0
|
||||
|
||||
//Get roll to add a left and right strafe during roll
|
||||
//Not sure if this is desired? Will need to mess around with this
|
||||
//a bit more
|
||||
var zComp = 0.0
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
if (controller != null)
|
||||
{
|
||||
//Can be used again if I better figure out how to deadzone it near the tops?
|
||||
zComp = -1.0 * g.toDouble() * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
yComp = -1.0 * g.toDouble() * sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
}
|
||||
|
||||
val currVelocity = Vec3(0.0, yComp , g.toDouble())
|
||||
state.lastVelocity.set(currVelocity)
|
||||
return currVelocity
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (!vehicle.isInWater && !vehicle.isUnderWater)
|
||||
{
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
|
||||
//this should be changed to be speed maybe?
|
||||
val movingForce = driver.zza
|
||||
if (controller != null) {
|
||||
var yawAngVel = 3 * sin(Math.toRadians(controller.roll.toDouble())).toFloat()
|
||||
var pitchAngVel = -1 * Math.abs(sin(Math.toRadians(controller.roll.toDouble())).toFloat())
|
||||
|
||||
//limit rotation modulation when pitched up heavily or pitched down heavily
|
||||
yawAngVel *= (abs(cos(Math.toRadians(controller.pitch.toDouble())))).toFloat()
|
||||
pitchAngVel *= (abs(cos(Math.toRadians(controller.pitch.toDouble())))).toFloat()
|
||||
//if you are not pressing forward then don't turn
|
||||
//yawAngVel *= movingForce
|
||||
//Ignore x,y,z its angular velocity:
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawAngVel.toDouble(), pitchAngVel.toDouble(), 0.0)
|
||||
}
|
||||
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Double {
|
||||
return 0.05
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: DolphinSettings,
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = DolphinState()
|
||||
|
||||
}
|
||||
|
||||
class DolphinSettings : RidingBehaviourSettings {
|
||||
override val key = DolphinBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
|
||||
var speed = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
canJump = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
speed = buffer.readExpression()
|
||||
driveFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class DolphinState : RidingBehaviourState {
|
||||
var lastVelocity = ridingState(Vec3.ZERO, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
|
||||
override fun reset() {
|
||||
lastVelocity.set(Vec3.ZERO, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "DolphinState(lastVelocity=${lastVelocity.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = DolphinState().also {
|
||||
it.lastVelocity.set(lastVelocity.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState) = false
|
||||
}
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
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
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
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
|
||||
|
||||
class FallToGlideCompositeBehaviour : RidingBehaviour<FallToGlideCompositeSettings, FallToGlideCompositeState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("composite/fall_to_glide")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val landBehaviour: GenericLandBehaviour = GenericLandBehaviour()
|
||||
val glideBehaviour: GliderAirBehaviour = GliderAirBehaviour()
|
||||
|
||||
override fun tick(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
val shouldBeFlying = checkShouldBeFlying(settings, vehicle, state.activeController.get() == GliderAirBehaviour.KEY)
|
||||
if (state.activeController.get() == GliderAirBehaviour.KEY && !shouldBeFlying) { // && entity.onGround() && state.timeTransitioned + 20 < entity.level().gameTime) {
|
||||
state.activeController.set(GenericLandBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
} else if (state.activeController.get() == GenericLandBehaviour.KEY && shouldBeFlying) {
|
||||
state.activeController.set(GliderAirBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkShouldBeFlying(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
vehicle: PokemonEntity,
|
||||
isFlyingAlready: Boolean
|
||||
): Boolean {
|
||||
val runtime = vehicle.runtime
|
||||
val minFallingSpeed = runtime.resolveFloat(settings.minimumFallSpeed)
|
||||
val minForwardSpeed = runtime.resolveFloat(settings.minimumForwardSpeed)
|
||||
val grounded = vehicle.onGround()
|
||||
return if (isFlyingAlready) {
|
||||
!grounded
|
||||
} else {
|
||||
vehicle.deltaMovement.y <= -minFallingSpeed && vehicle.deltaMovement.horizontalDistance() >= minForwardSpeed
|
||||
}
|
||||
}
|
||||
|
||||
override fun isActive(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.pose(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.pose(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.speed(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.speed(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotation(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.rotation(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.velocity(settings.land, state.landState, vehicle, driver, input)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.velocity(settings.glide, NoState, vehicle, driver, input)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.angRollVel(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.angRollVel(settings.glide, NoState, vehicle, driver, deltaTime)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotationOnMouseXY(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.rotationOnMouseXY(
|
||||
settings.glide,
|
||||
NoState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.canJump(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.canJump(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.setRideBar(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.setRideBar(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.jumpForce(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
jumpStrength
|
||||
)
|
||||
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.jumpForce(settings.glide, NoState, vehicle, driver, jumpStrength)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.gravity(settings.land, state.landState, vehicle, regularGravity)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.gravity(settings.glide, NoState, vehicle, regularGravity)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rideFovMultiplier(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.rideFovMultiplier(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useAngVelSmoothing(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.useAngVelSmoothing(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useRidingAltPose(settings.land, state.landState, vehicle, driver)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.useRidingAltPose(settings.glide, NoState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.inertia(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.inertia(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRoll(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.shouldRoll(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.turnOffOnGround(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.turnOffOnGround(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.dismountOnShift(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.dismountOnShift(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePokemonHead(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.shouldRotatePokemonHead(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: FallToGlideCompositeSettings,
|
||||
state: FallToGlideCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePlayerHead(settings.land, state.landState, vehicle)
|
||||
GliderAirBehaviour.KEY -> glideBehaviour.shouldRotatePlayerHead(settings.glide, NoState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun createDefaultState() = FallToGlideCompositeState()
|
||||
|
||||
|
||||
}
|
||||
|
||||
class FallToGlideCompositeSettings : RidingBehaviourSettings {
|
||||
override val key = FallToGlideCompositeBehaviour.KEY
|
||||
|
||||
var glide: GliderAirSettings = GliderAirSettings()
|
||||
private set
|
||||
|
||||
var land: GenericLandSettings = GenericLandSettings()
|
||||
private set
|
||||
|
||||
var minimumForwardSpeed: Expression = "0.0".asExpression()
|
||||
private set
|
||||
|
||||
var minimumFallSpeed: Expression = "0.5".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
glide.encode(buffer)
|
||||
land.encode(buffer)
|
||||
buffer.writeExpression(minimumForwardSpeed)
|
||||
buffer.writeExpression(minimumFallSpeed)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
glide.decode(buffer)
|
||||
land.decode(buffer)
|
||||
minimumForwardSpeed = buffer.readExpression()
|
||||
minimumFallSpeed = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class FallToGlideCompositeState : RidingBehaviourState {
|
||||
var activeController = ridingState(GenericLandBehaviour.KEY, Side.CLIENT)
|
||||
var landState: GenericLandState = GenericLandState()
|
||||
var timeTransitioned = ridingState(-100L, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(activeController.get())
|
||||
landState.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
activeController.set(buffer.readResourceLocation(), forced = true)
|
||||
landState.decode(buffer)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
activeController.set(GenericLandBehaviour.KEY, forced = true)
|
||||
landState.reset()
|
||||
timeTransitioned.set(-100L, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "FallToGlideCompositeState(activeController=$activeController, landState=$landState, timeTransitioned=$timeTransitioned)"
|
||||
}
|
||||
|
||||
override fun copy() = FallToGlideCompositeState().also {
|
||||
it.activeController.set(activeController.get(), forced = true)
|
||||
it.landState = landState.copy()
|
||||
it.timeTransitioned.set(timeTransitioned.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is FallToGlideCompositeState) return false
|
||||
if (activeController != previous.activeController) return true
|
||||
if (landState.shouldSync(previous.landState)) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+425
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.util.SmoothDouble
|
||||
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 kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
|
||||
class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("land/generic")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption state.rideVel.get().z > 0.1
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any false
|
||||
}
|
||||
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any !blockState.isAir && blockState.fluidState.isEmpty
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return this.poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return state.rideVel.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
val gravity = -1.0
|
||||
|
||||
val newVelocity = calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround()) {
|
||||
state.rideVel.set(Vec3(newVelocity.x, 2.0, newVelocity.z))
|
||||
} else {
|
||||
state.rideVel.set(newVelocity)
|
||||
}
|
||||
|
||||
//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.rideVel.get()
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.topSpeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelExpr)
|
||||
val speed = state.rideVel.get().length()
|
||||
|
||||
val minSpeed = 0.0
|
||||
|
||||
var newVelocity = Vec3(state.rideVel.get().x, state.rideVel.get().y, state.rideVel.get().z)
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && speed <= topSpeed && state.stamina.get() > 0.0f) {
|
||||
//modify acceleration to be slower when at closer speeds to top speed
|
||||
val accelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2), 0.1)
|
||||
newVelocity = Vec3(newVelocity.x, newVelocity.y, min(newVelocity.z + (accel * accelMod), topSpeed))
|
||||
} else if (driver.zza >= 0.0 && state.stamina.get() == 0.0f || speed > topSpeed) {
|
||||
newVelocity = Vec3(newVelocity.x, newVelocity.y, max(newVelocity.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, 0.0)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
newVelocity =
|
||||
Vec3(newVelocity.x, newVelocity.y, max(newVelocity.z - ((accel * deccelMod) / 2), minSpeed))
|
||||
}
|
||||
|
||||
if (vehicle.onGround()) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
} else {
|
||||
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - 0.2, -1.0), newVelocity.z)
|
||||
}
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the current speed between minSpeed and maxSpeed.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
|
||||
*/
|
||||
private fun normalizeSpeed(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
|
||||
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
|
||||
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseX * 0.1, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseY * 0.1, deltaTime * smoothingSpeed);
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, yInput, xInput)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
//Retrieve stamina from state and tick up at a rate of 0.1 a second
|
||||
val staminaGain = (1.0 / 20.0) * 0.1
|
||||
state.stamina.set(min(state.stamina.get() + staminaGain, 1.0).toFloat())
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = GenericLandState()
|
||||
}
|
||||
|
||||
class GenericLandSettings : RidingBehaviourSettings {
|
||||
override val key = GenericLandBehaviour.KEY
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'LAND', 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 accelExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'LAND', 30.0, 10.0)".asExpression()
|
||||
private set
|
||||
|
||||
//Between a one block jump and a ten block jump
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'LAND', 10.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'LAND', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
driveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GenericLandState : RidingBehaviourState {
|
||||
var rideVel = ridingState(Vec3.ZERO, Side.CLIENT)
|
||||
var stamina = ridingState(1.0f, Side.CLIENT)
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeVec3(rideVel.get())
|
||||
buffer.writeFloat(stamina.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideVel.set(buffer.readVec3(), forced = true)
|
||||
stamina.set(buffer.readFloat(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
rideVel.set(Vec3.ZERO, forced = true)
|
||||
stamina.set(1.0f, forced = true)
|
||||
currSpeed.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "GenericLandState(rideVel=${rideVel.get()}, stamina=${stamina.get()}, currSpeed=${currSpeed.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = GenericLandState().also {
|
||||
it.rideVel.set(this.rideVel.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.currSpeed.set(this.currSpeed.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is GenericLandState) return false
|
||||
if (rideVel != previous.rideVel) return true
|
||||
if (stamina != previous.stamina) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.NoState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
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.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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
|
||||
class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, NoState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/generic")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<GenericSwimSettings, NoState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = vehicle.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
|
||||
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
|
||||
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return regularGravity
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: GenericSwimSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: GenericSwimSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = NoState
|
||||
|
||||
}
|
||||
|
||||
class GenericSwimSettings : RidingBehaviourSettings {
|
||||
override val key = GenericSwimBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
|
||||
var speed = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
canJump = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
speed = buffer.readExpression()
|
||||
driveFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.NoState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, NoState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/glider")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<GliderAirSettings, NoState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
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)
|
||||
val zVector = driver.zza.toDouble()
|
||||
val statSpeed = vehicle.rideProp.calculate(RidingStat.SPEED, RidingStyle.AIR, 0 )
|
||||
|
||||
return Vec3(xVector, yVector, zVector)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity, driver: Player): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GliderAirSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: GliderAirSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = NoState
|
||||
}
|
||||
|
||||
class GliderAirSettings : RidingBehaviourSettings {
|
||||
override val key = GliderAirBehaviour.KEY
|
||||
|
||||
var glideSpeed: Expression = "0.1".asExpression()
|
||||
private set
|
||||
|
||||
var speed: Expression = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var canStrafe: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(glideSpeed)
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(canStrafe)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
glideSpeed = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
canStrafe = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.NoState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
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.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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, NoState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/helicopter")
|
||||
val ROTATION_LIMIT = 30.0f
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<HelicopterSettings, NoState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
//If there are only fluid blocks or air block below the ride
|
||||
//then activate the controller. If it is in water the ride will
|
||||
//dismount accordingly
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any (blockState.isAir || !blockState.fluidState.isEmpty)
|
||||
}
|
||||
true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
//Increased max speed to exaggerate movement.
|
||||
//This likely just needs to be a static number if it really is just
|
||||
//the scalar for the velocity vector
|
||||
return 2.0f
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
|
||||
//If the player is not modulating height then hover
|
||||
var yVel = if (driver.jumping) runtime.resolveDouble(settings.verticalVelocity)
|
||||
else if (driver.isShiftKeyDown) -runtime.resolveDouble(settings.verticalVelocity)
|
||||
else (0.0)
|
||||
|
||||
yVel *= 0.25
|
||||
var xVel = 0.0
|
||||
var zVel = 0.0
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
|
||||
//Horizontal velocity is based on pitch and roll
|
||||
if (controller != null) {
|
||||
xVel = -1.0 * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
zVel = sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
}
|
||||
|
||||
return Vec3(xVel, yVel, zVel)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
|
||||
//In degrees per second? It was supposed to be I think but
|
||||
//I have messed something up
|
||||
val rotationChangeRate = 2.0
|
||||
val rotLimit = 30.0
|
||||
|
||||
var pitchForce = driver.zza * rotationChangeRate
|
||||
var rollForce = -1.0 * driver.xxa * rotationChangeRate
|
||||
|
||||
|
||||
//TODO: Fix accumulated movement causing pitch and roll out of set bounds
|
||||
if (controller != null) {
|
||||
//If the roll or pitch have exceeded the limit then do not modulate that
|
||||
//rotation in that direction further
|
||||
|
||||
//modulate the forces so that they trend towards 0 as they approach rotation limit.
|
||||
//The current function has it drop off very quickly which may not be ideal.
|
||||
//Prev function:
|
||||
// pitchForce = pitchForce * max(rotLim - abs(rollable.pitch.toDouble()), 0.0)
|
||||
|
||||
//The three denotes that the force will be 1/3 what it would have been at
|
||||
//the rotation limit
|
||||
rollForce *= 2.0.pow(-1.0 * (abs(controller.roll.toDouble()) / ROTATION_LIMIT))
|
||||
|
||||
pitchForce *= 2.0.pow(-1.0 * (abs(controller.pitch.toDouble()) / ROTATION_LIMIT))
|
||||
|
||||
if (controller.roll >= ROTATION_LIMIT && rollForce > 0.0) {
|
||||
rollForce = 0.0;
|
||||
}
|
||||
if (controller.roll <= -ROTATION_LIMIT && rollForce < 0.0) {
|
||||
rollForce = 0.0;
|
||||
}
|
||||
if (controller.pitch >= ROTATION_LIMIT && pitchForce > 0.0) {
|
||||
pitchForce = 0.0;
|
||||
}
|
||||
if (controller.pitch <= -ROTATION_LIMIT && pitchForce < 0.0) {
|
||||
pitchForce = 0.0;
|
||||
}
|
||||
|
||||
//Ignore x,y,z its angular velocity:
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, pitchForce.toDouble(), rollForce)
|
||||
}
|
||||
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
val invertYaw = if (Cobblemon.config.invertYaw) -1 else 1
|
||||
//yaw, pitch, roll
|
||||
return Vec3(mouseX * invertYaw, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Double {
|
||||
return 0.1
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = NoState
|
||||
}
|
||||
|
||||
|
||||
class HelicopterSettings : RidingBehaviourSettings {
|
||||
override val key = HelicopterBehaviour.KEY
|
||||
|
||||
var gravity: Expression = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var horizontalAcceleration: Expression = "0.1".asExpression()
|
||||
private set
|
||||
|
||||
var verticalVelocity: Expression = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var speed: Expression = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(horizontalAcceleration)
|
||||
buffer.writeExpression(verticalVelocity)
|
||||
buffer.writeExpression(speed)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readExpression()
|
||||
horizontalAcceleration = buffer.readExpression()
|
||||
verticalVelocity = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
+442
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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.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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.*
|
||||
|
||||
class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/jet")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<JetAirSettings, JetAirState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVel.get().z > 0.1 })
|
||||
|
||||
override fun isActive(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
|
||||
//retrieve minSpeed
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
|
||||
//Reduce stamina unless stamina is infinite
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteStamina)) {
|
||||
//Calculate stamina loss due to speed
|
||||
//At max speed it will tick down 0.1 a second so the stamina will last ten seconds
|
||||
//There has got to be a better way to express this equation. It interpolates between 0.5 and 1.0
|
||||
var staminaRate = (normalizeSpeed(state.rideVel.get().length(), minSpeed, topSpeed))
|
||||
|
||||
//interpolate between 0.25 and 1.0 so that you always have at least a min of 0.25 stam loss
|
||||
staminaRate = 0.25 + (0.75 * staminaRate.pow(3))
|
||||
|
||||
//Calculate stamina loss in seconds achievable at top speed
|
||||
val staminaLoss = staminaRate * (1.0 / (20.0 * staminaStat))
|
||||
state.stamina.set(max(state.stamina.get() - staminaLoss, 0.0).toFloat())
|
||||
} else {
|
||||
state.stamina.set(1.0f)
|
||||
}
|
||||
|
||||
return state.rideVel.get().length().toFloat()
|
||||
}
|
||||
|
||||
//TODO: Move these functions to a riding util class.
|
||||
/*
|
||||
* Normalizes the current speed between minSpeed and maxSpeed.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minSpeed and 1.0 represents maxSpeed.
|
||||
*/
|
||||
private fun normalizeSpeed(currSpeed: Double, minSpeed: Double, maxSpeed: Double): Double {
|
||||
require(maxSpeed > minSpeed) { "maxSpeed must be greater than minSpeed" }
|
||||
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
|
||||
//Calculate ride space velocity
|
||||
calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
|
||||
//Translate ride space velocity to world space velocity.
|
||||
if (controller != null) {
|
||||
upForce = -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().z
|
||||
forwardForce = cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.get().z
|
||||
}
|
||||
|
||||
//If stamina has run out then initiate forced glide down.
|
||||
upForce = if (state.stamina.get() > 0.0) upForce else -0.7
|
||||
|
||||
val altitudeLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (vehicle.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(0.0, upForce, forwardForce)
|
||||
|
||||
return velocity
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val altitudeLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
val speed = state.rideVel.get().length()
|
||||
|
||||
//Give no altitude limit if at max jump stat.
|
||||
val pushingHeightLimit = if (vehicle.runtime.resolveBoolean(settings.infiniteStamina)) false
|
||||
else (vehicle.y >= altitudeLimit && vehicle.xRot <= 0)
|
||||
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && speed < topSpeed && state.stamina.get() > 0.0f && !pushingHeightLimit) {
|
||||
//modify acceleration to be slower when at closer speeds to top speed
|
||||
val accelMod = max(-(normalizeSpeed(speed, minSpeed, topSpeed)) + 1, 0.0)
|
||||
state.rideVel.set(Vec3(state.rideVel.get().x, state.rideVel.get().y, min(state.rideVel.get().z + (accel * accelMod), topSpeed)))
|
||||
} else if (driver.zza >= 0.0 && (state.stamina.get() == 0.0f || pushingHeightLimit)) {
|
||||
state.rideVel.set(Vec3(state.rideVel.get().x, state.rideVel.get().y, max(state.rideVel.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), 0.1)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
state.rideVel.set(Vec3(state.rideVel.get().x, state.rideVel.get().y, max(state.rideVel.get().z - ((accel * deccelMod) / 2), minSpeed)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
//Get handling in degrees per second
|
||||
val yawRotRate = vehicle.runtime.resolveDouble(settings.handlingYawExpr)
|
||||
|
||||
//Base the change off of deltatime.
|
||||
var handlingYaw = yawRotRate * (cappedDeltaTime)
|
||||
|
||||
//apply stamina debuff if applicable
|
||||
handlingYaw *= if (state.stamina.get() > 0.0) 1.0 else 0.5
|
||||
|
||||
//A+D to yaw
|
||||
val yawForce = driver.xxa * handlingYaw * -1
|
||||
|
||||
return Vec3(yawForce, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
//TODO: figure out a cleaner solution to this issue of large jumps when skipping frames or lagging
|
||||
//Cap at a rate of 5fps so frame skips dont lead to huge jumps
|
||||
val cappedDeltaTime = min(deltaTime, 0.2)
|
||||
|
||||
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))
|
||||
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY * invertPitch)).coerceIn(-1.0, 1.0))
|
||||
|
||||
//Get handling in degrees per second
|
||||
var handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
|
||||
//convert it to delta time
|
||||
handling *= (cappedDeltaTime)
|
||||
|
||||
//apply stamina debuff if applicable
|
||||
handling *= if (state.stamina.get() > 0.0) 1.0 else 0.5
|
||||
|
||||
val poke = driver.vehicle as? PokemonEntity
|
||||
|
||||
//TODO: reevaluate if deadzones are needed and if they are still causing issues.
|
||||
//create deadzones for the constant input values.
|
||||
//val xInput = remapWithDeadzone(state.currMouseXForce, 0.025, 1.0)
|
||||
//val yInput = remapWithDeadzone(state.currMouseYForce, 0.025, 1.0)
|
||||
|
||||
val pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
//Roll is 1.5 times as fast as pitch
|
||||
val rollRot = handling * 1.5 * state.currMouseXForce.get()
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, pitchRot, rollRot)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedSpeed = normalizeSpeed(state.rideVel.get().length(), minSpeed, topSpeed)
|
||||
|
||||
//TODO: Determine if this should be based on max possible speed instead of top speed.
|
||||
//Only ever want the fov change to be a max of 0.2 and for it to have non linear scaling.
|
||||
return 1.0f + normalizedSpeed.pow(2).toFloat() * 0.2f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = JetAirState()
|
||||
}
|
||||
|
||||
class JetAirSettings : RidingBehaviourSettings {
|
||||
override val key = JetAirBehaviour.KEY
|
||||
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "1.2".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 25.0, 8.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".asExpression()
|
||||
private set
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readExpression()
|
||||
minSpeed = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class JetAirState : RidingBehaviourState {
|
||||
var currSpeed = ridingState(0.0, Side.CLIENT)
|
||||
var stamina = ridingState(1.0f, Side.CLIENT)
|
||||
var rideVel = ridingState(Vec3.ZERO, Side.CLIENT)
|
||||
var currMouseXForce = ridingState(0.0, Side.BOTH)
|
||||
var currMouseYForce = ridingState(0.0, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeDouble(currSpeed.get())
|
||||
buffer.writeFloat(stamina.get())
|
||||
buffer.writeVec3(rideVel.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
currSpeed.set(buffer.readDouble(), forced = true)
|
||||
stamina.set(buffer.readFloat(), forced = true)
|
||||
rideVel.set(buffer.readVec3(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
currSpeed.set(0.0, forced = true)
|
||||
stamina.set(1.0f, forced = true)
|
||||
rideVel.set(Vec3.ZERO, forced = true)
|
||||
currMouseXForce.set(0.0, forced = true)
|
||||
currMouseYForce.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "JetAirState(currSpeed=${currSpeed.get()}, stamina=${stamina.get()}, rideVel=${rideVel.get()}, currMouseXForce=${currMouseXForce.get()}, currMouseYForce=${currMouseYForce.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = JetAirState().also {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.rideVel.set(rideVel.get(), forced = true)
|
||||
it.currMouseXForce.set(currMouseXForce.get(), forced = true)
|
||||
it.currMouseYForce.set(currMouseYForce.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is JetAirState) return false
|
||||
if (previous.currSpeed != currSpeed) return true
|
||||
if (previous.stamina != stamina) return true
|
||||
if (previous.rideVel != rideVel) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+469
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readExpression
|
||||
import com.cobblemon.mod.common.util.writeExpression
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class JumpToFlightCompositeBehaviour : RidingBehaviour<JumpToFlightCompositeSettings, JumpToFlightCompositeState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("composite/jump_to_flight")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val landBehaviour: GenericLandBehaviour = GenericLandBehaviour()
|
||||
val birdBehaviour: BirdAirBehaviour = BirdAirBehaviour()
|
||||
|
||||
override fun tick(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
val flightState = state.flightState
|
||||
val groundState = state.landState
|
||||
if (shouldTransitionToGround(state, vehicle)) {
|
||||
//Pass the speed to the next state
|
||||
// groundState.currSpeed = flightState.currSpeed
|
||||
groundState.rideVel.set(flightState.rideVel.get())
|
||||
groundState.stamina.set(flightState.stamina.get())
|
||||
|
||||
state.activeController.set(GenericLandBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
state.timeTransitioned.set(vehicle.level().gameTime)
|
||||
} else if (shouldTransitionToAir(state, vehicle, driver)) {
|
||||
//Pass the speed to the next state
|
||||
// flightState.currSpeed = groundState.currSpeed
|
||||
flightState.rideVel.set(groundState.rideVel.get())
|
||||
flightState.stamina.set(groundState.stamina.get())
|
||||
|
||||
state.activeController.set(BirdAirBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
state.timeTransitioned.set(vehicle.level().gameTime)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isActive(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun shouldTransitionToGround(state: JumpToFlightCompositeState, entity: PokemonEntity): Boolean {
|
||||
return state.activeController.get() == BirdAirBehaviour.KEY
|
||||
&& entity.onGround()
|
||||
&& state.timeTransitioned.get() + 20 < entity.level().gameTime
|
||||
}
|
||||
|
||||
private fun shouldTransitionToAir(
|
||||
state: JumpToFlightCompositeState,
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return state.activeController.get() == GenericLandBehaviour.KEY
|
||||
&& driver.jumping
|
||||
&& state.timeTransitioned.get() + 20 < entity.level().gameTime
|
||||
}
|
||||
|
||||
override fun pose(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.pose(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.pose(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.speed(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.speed(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotation(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.rotation(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.velocity(settings.land, state.landState, vehicle, driver, input)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.velocity(settings.bird, state.flightState, vehicle, driver, input)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.angRollVel(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.angRollVel(
|
||||
settings.bird,
|
||||
state.flightState,
|
||||
vehicle,
|
||||
driver,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotationOnMouseXY(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.rotationOnMouseXY(
|
||||
settings.bird,
|
||||
state.flightState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.canJump(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.canJump(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.setRideBar(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.setRideBar(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.jumpForce(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
jumpStrength
|
||||
)
|
||||
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.jumpForce(
|
||||
settings.bird,
|
||||
state.flightState,
|
||||
vehicle,
|
||||
driver,
|
||||
jumpStrength
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.gravity(settings.land, state.landState, vehicle, regularGravity)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.gravity(settings.bird, state.flightState, vehicle, regularGravity)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rideFovMultiplier(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.rideFovMultiplier(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useAngVelSmoothing(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.useAngVelSmoothing(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useRidingAltPose(settings.land, state.landState, vehicle, driver)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.useRidingAltPose(settings.bird, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.inertia(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.inertia(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRoll(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.shouldRoll(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.turnOffOnGround(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.turnOffOnGround(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.dismountOnShift(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.dismountOnShift(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePokemonHead(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.shouldRotatePokemonHead(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: JumpToFlightCompositeSettings,
|
||||
state: JumpToFlightCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePlayerHead(settings.land, state.landState, vehicle)
|
||||
BirdAirBehaviour.KEY -> birdBehaviour.shouldRotatePlayerHead(settings.bird, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun createDefaultState() = JumpToFlightCompositeState()
|
||||
}
|
||||
|
||||
class JumpToFlightCompositeSettings : RidingBehaviourSettings {
|
||||
override val key = JumpToFlightCompositeBehaviour.KEY
|
||||
|
||||
var bird: BirdAirSettings = BirdAirSettings()
|
||||
private set
|
||||
|
||||
var land: GenericLandSettings = GenericLandSettings()
|
||||
private set
|
||||
|
||||
var minimumSpeed: Expression = "0.5".asExpression()
|
||||
private set
|
||||
|
||||
var minimumJump: Expression = "0.5".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
bird.encode(buffer)
|
||||
land.encode(buffer)
|
||||
buffer.writeExpression(minimumSpeed)
|
||||
buffer.writeExpression(minimumJump)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
bird.decode(buffer)
|
||||
land.decode(buffer)
|
||||
minimumSpeed = buffer.readExpression()
|
||||
minimumJump = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class JumpToFlightCompositeState : RidingBehaviourState {
|
||||
var activeController = ridingState(GenericLandBehaviour.KEY, Side.CLIENT)
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var timeTransitioned = ridingState(-100L, Side.BOTH)
|
||||
var landState = GenericLandState()
|
||||
var flightState = BirdAirState()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(activeController.get())
|
||||
landState.encode(buffer)
|
||||
flightState.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
activeController.set(buffer.readResourceLocation(), forced = true)
|
||||
landState.decode(buffer)
|
||||
flightState.decode(buffer)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
activeController.set(GenericLandBehaviour.KEY, forced = true)
|
||||
timeTransitioned.set(-100L, forced = true)
|
||||
currSpeed.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "JumpToFlightCompositeState(activeController=${activeController.get()}, landState=$landState, flightState=$flightState, currSpeed=${currSpeed.get()}, timeTransitioned=${timeTransitioned.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = JumpToFlightCompositeState().also {
|
||||
it.activeController.set(activeController.get(), forced = true)
|
||||
it.landState = landState.copy()
|
||||
it.flightState = flightState.copy()
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.timeTransitioned.set(timeTransitioned.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is JumpToFlightCompositeState) return false
|
||||
if (activeController != previous.activeController) return true
|
||||
if (landState.shouldSync(previous.landState)) return true
|
||||
if (flightState.shouldSync(previous.flightState)) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readExpression
|
||||
import com.cobblemon.mod.common.util.writeExpression
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class RunToJetCompositeBehaviour : RidingBehaviour<RunToJetCompositeSettings, RunToJetCompositeState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("composite/run_to_jet")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val landBehaviour: GenericLandBehaviour = GenericLandBehaviour()
|
||||
val jetBehaviour: JetAirBehaviour = JetAirBehaviour()
|
||||
|
||||
override fun tick(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
val flightState = state.flightState
|
||||
val groundState = state.landState
|
||||
if (shouldTransitionToGround(state, vehicle, driver)) {
|
||||
groundState.currSpeed = flightState.currSpeed
|
||||
groundState.stamina = flightState.stamina
|
||||
groundState.rideVel = flightState.rideVel
|
||||
|
||||
state.activeController.set(GenericLandBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, false)
|
||||
state.timeTransitioned.set(vehicle.level().gameTime)
|
||||
} else if (shouldTransitionToAir(state, vehicle, driver, input)) {
|
||||
flightState.currSpeed = groundState.currSpeed
|
||||
flightState.stamina = groundState.stamina
|
||||
flightState.rideVel = groundState.rideVel
|
||||
|
||||
state.activeController.set(JetAirBehaviour.KEY)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, true)
|
||||
state.timeTransitioned.set(vehicle.level().gameTime)
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldTransitionToGround(
|
||||
state: RunToJetCompositeState,
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
if (state.activeController.get() != JetAirBehaviour.KEY) return false
|
||||
if (state.timeTransitioned.get() + 20 >= entity.level().gameTime) return false
|
||||
return driver.isSprinting || entity.onGround()
|
||||
}
|
||||
|
||||
private fun shouldTransitionToAir(
|
||||
state: RunToJetCompositeState,
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Boolean {
|
||||
if (state.activeController.get() != GenericLandBehaviour.KEY) return false
|
||||
if (state.timeTransitioned.get() + 20 >= entity.level().gameTime) return false
|
||||
return driver.isSprinting && input.z > 0.5
|
||||
}
|
||||
|
||||
override fun isActive(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.pose(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.pose(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.speed(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.speed(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotation(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.rotation(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.velocity(settings.land, state.landState, vehicle, driver, input)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.velocity(settings.jet, state.flightState, vehicle, driver, input)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.angRollVel(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
JetAirBehaviour.KEY -> jetBehaviour.angRollVel(settings.jet, state.flightState, vehicle, driver, deltaTime)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rotationOnMouseXY(
|
||||
settings.land,
|
||||
state.landState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.rotationOnMouseXY(
|
||||
settings.jet,
|
||||
state.flightState,
|
||||
vehicle,
|
||||
driver,
|
||||
mouseY,
|
||||
mouseX,
|
||||
mouseYSmoother,
|
||||
mouseXSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.canJump(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.canJump(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.setRideBar(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.setRideBar(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.jumpForce(settings.land, state.landState, vehicle, driver, jumpStrength)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.jumpForce(settings.jet, state.flightState, vehicle, driver, jumpStrength)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.gravity(settings.land, state.landState, vehicle, regularGravity)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.gravity(settings.jet, state.flightState, vehicle, regularGravity)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.rideFovMultiplier(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.rideFovMultiplier(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useAngVelSmoothing(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.useAngVelSmoothing(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.useRidingAltPose(settings.land, state.landState, vehicle, driver)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.useRidingAltPose(settings.jet, state.flightState, vehicle, driver)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.inertia(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.inertia(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRoll(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.shouldRoll(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.turnOffOnGround(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.turnOffOnGround(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.dismountOnShift(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.dismountOnShift(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePokemonHead(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.shouldRotatePokemonHead(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: RunToJetCompositeSettings,
|
||||
state: RunToJetCompositeState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return when (state.activeController.get()) {
|
||||
GenericLandBehaviour.KEY -> landBehaviour.shouldRotatePlayerHead(settings.land, state.landState, vehicle)
|
||||
JetAirBehaviour.KEY -> jetBehaviour.shouldRotatePlayerHead(settings.jet, state.flightState, vehicle)
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun createDefaultState() = RunToJetCompositeState()
|
||||
}
|
||||
|
||||
class RunToJetCompositeSettings : RidingBehaviourSettings {
|
||||
override val key = RunToJetCompositeBehaviour.KEY
|
||||
|
||||
var jet: JetAirSettings = JetAirSettings()
|
||||
private set
|
||||
|
||||
var land: GenericLandSettings = GenericLandSettings()
|
||||
private set
|
||||
|
||||
var minimumSpeed: Expression = "0.5".asExpression()
|
||||
private set
|
||||
|
||||
var minimumJump: Expression = "0.5".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
jet.encode(buffer)
|
||||
land.encode(buffer)
|
||||
buffer.writeExpression(minimumSpeed)
|
||||
buffer.writeExpression(minimumJump)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
jet.decode(buffer)
|
||||
land.decode(buffer)
|
||||
minimumSpeed = buffer.readExpression()
|
||||
minimumJump = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class RunToJetCompositeState : RidingBehaviourState {
|
||||
var activeController = ridingState(GenericLandBehaviour.KEY, Side.CLIENT)
|
||||
var landState: GenericLandState = GenericLandState()
|
||||
var flightState: JetAirState = JetAirState()
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var timeTransitioned = ridingState(-100L, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(activeController.get())
|
||||
landState.encode(buffer)
|
||||
flightState.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
activeController.set(buffer.readResourceLocation(), forced = true)
|
||||
landState.decode(buffer)
|
||||
flightState.decode(buffer)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
activeController.set(GenericLandBehaviour.KEY, forced = true)
|
||||
timeTransitioned.set(-100L, forced = true)
|
||||
currSpeed.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "RunToJetCompositeState(activeController=${activeController.get()}, landState=$landState, flightState=$flightState, currSpeed=${currSpeed.get()}, timeTransitioned=${timeTransitioned.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = RunToJetCompositeState().also {
|
||||
it.activeController.set(activeController.get(), forced = true)
|
||||
it.landState = landState.copy()
|
||||
it.flightState = flightState.copy()
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.timeTransitioned.set(timeTransitioned.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is RunToJetCompositeState) return false
|
||||
if (activeController != previous.activeController) return true
|
||||
if (landState.shouldSync(previous.landState)) return true
|
||||
if (flightState.shouldSync(previous.flightState)) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
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.util.blockPositionsAsListRounded
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
|
||||
class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/dash")
|
||||
const val DASH_TICKS: Int = 60
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<SwimDashSettings, SwimDashState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = vehicle.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
if(state.dashing.get()) {
|
||||
state.ticks.set(state.ticks.get() + 1)
|
||||
if(state.ticks.get() >= DASH_TICKS) {
|
||||
state.dashing.set(false)
|
||||
}
|
||||
|
||||
return 0.0F
|
||||
}
|
||||
|
||||
state.dashing.set(true)
|
||||
return settings.dashSpeed
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val f = driver.xxa * 0.05f
|
||||
var g = driver.zza * 0.6f
|
||||
if (g <= 0.0f) {
|
||||
g *= 0.25f
|
||||
}
|
||||
|
||||
return Vec3(f.toDouble(), 0.0, g.toDouble())
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseX * invertPitch, mouseY * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return regularGravity
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = SwimDashState()
|
||||
}
|
||||
|
||||
class SwimDashSettings : RidingBehaviourSettings {
|
||||
override val key = SwimDashBehaviour.KEY
|
||||
|
||||
var dashSpeed = 1F
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeFloat(dashSpeed)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
dashSpeed = buffer.readFloat()
|
||||
}
|
||||
}
|
||||
|
||||
class SwimDashState : RidingBehaviourState {
|
||||
var dashing = ridingState(false, Side.BOTH)
|
||||
var ticks = ridingState(0, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
|
||||
override fun reset() {
|
||||
dashing.set(false, forced = true)
|
||||
ticks.set(0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "SwimDashState(dashing=${dashing.get()}, ticks=${ticks.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = SwimDashState().also {
|
||||
it.dashing.set(dashing.get(), forced = true)
|
||||
it.ticks.set(ticks. get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState) = false
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
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
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("land/vehicle")
|
||||
|
||||
val MAX_TOP_SPEED = 1.0 // 20 bl/s
|
||||
val MIN_TOP_SPEED = 0.35 // 7 bl/s
|
||||
//val MIN_SPEED = 0.25 // 5 bl/s
|
||||
|
||||
//Accel will lie between 1.0 second and 5.0 seconds
|
||||
val MAX_ACCEL = (MAX_TOP_SPEED) / (20*3) //3.0 second to max speed
|
||||
val MIN_ACCEL = (MAX_TOP_SPEED) / (20*8) // 8 seconds to max speed
|
||||
|
||||
//Can rotate 90 degrees
|
||||
val MAX_HANDLING = 90.0
|
||||
val MIN_HANDLING = 30.0
|
||||
|
||||
|
||||
val MAX_YAW_HANDLING = 16.0
|
||||
val MIN_YAW_HANDLING = 8.0
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
val poseProvider = PoseProvider<VehicleLandSettings, VehicleLandState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any false
|
||||
}
|
||||
//This might not actually work, depending on what the yPos actually is. yPos of the middle of the entity? the feet?
|
||||
if (it.y.toDouble() == (vehicle.position().y)) {
|
||||
val blockState = vehicle.level().getBlockState(it.below())
|
||||
return@any !(!blockState.isAir && blockState.fluidState.isEmpty)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.getRideStat(RidingStat.SPEED, RidingStyle.AIR, MIN_TOP_SPEED, MAX_TOP_SPEED)
|
||||
val accel = vehicle.getRideStat(RidingStat.ACCELERATION, RidingStyle.AIR, MIN_ACCEL, MAX_ACCEL)
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza > 0.0 && state.currSpeed.get() < topSpeed) {
|
||||
state.currSpeed.set(min(state.currSpeed.get() + accel , topSpeed))
|
||||
} else if (driver.zza < 0.0 && state.currSpeed.get() > 0.0) {
|
||||
//Decelerate is now always a constant half of max acceleration.
|
||||
state.currSpeed.set(max(state.currSpeed.get() - (MAX_ACCEL / 2), 0.0))
|
||||
}
|
||||
|
||||
return state.currSpeed.get().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
val rotationDegrees = driver.xxa * vehicle.runtime.resolveFloat(settings.rotationSpeed)
|
||||
val rotation = Vec2(driver.xRot, vehicle.yRot - rotationDegrees)
|
||||
state.deltaRotation.set(Vec2(rotation.x - driver.rotationVector.x, rotation.y - vehicle.rotationVector.y))
|
||||
return rotation
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
if (driver.xxa != 0F && g.absoluteValue < runtime.resolveFloat(settings.minimumSpeedToTurn)) {
|
||||
driver.xxa = 0F
|
||||
}
|
||||
val velocity = Vec3(0.0 /* Maybe do drifting here later */, 0.0, g.toDouble() * state.currSpeed.get())
|
||||
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return regularGravity
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun inertia(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState() = VehicleLandState()
|
||||
}
|
||||
|
||||
class VehicleLandSettings : RidingBehaviourSettings {
|
||||
override val key = VehicleLandBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
|
||||
var speed = "0.3".asExpression()
|
||||
private set
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var minimumSpeedToTurn = "0.1".asExpression()
|
||||
private set
|
||||
|
||||
var rotationSpeed = "45/20".asExpression()
|
||||
private set
|
||||
|
||||
var lookYawLimit = "101".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(minimumSpeedToTurn)
|
||||
buffer.writeExpression(rotationSpeed)
|
||||
buffer.writeExpression(lookYawLimit)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
canJump = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
speed = buffer.readExpression()
|
||||
driveFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
minimumSpeedToTurn = buffer.readExpression()
|
||||
rotationSpeed = buffer.readExpression()
|
||||
lookYawLimit = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleLandState : RidingBehaviourState {
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var deltaRotation = ridingState(Vec2.ZERO, Side.BOTH)
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) = Unit
|
||||
|
||||
override fun reset() {
|
||||
currSpeed.set(0.0, forced = true)
|
||||
deltaRotation.set(Vec2.ZERO, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "VehicleLandState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = VehicleLandState().also {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.deltaRotation.set(deltaRotation.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState) = false
|
||||
}
|
||||
-153
@@ -1,153 +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.riding.controller
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.api.riding.RidingState
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
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
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* A riding controller is the internal control mechanism for determining how a pokemon
|
||||
* handles during riding. Controllers come into play once the pokemon being ridden has
|
||||
* established the path it's capable of. For instance, a land based controller could have
|
||||
* the pokemon experience drifting after movement, or generic movement. It's up to the
|
||||
* controller to decide how the pokemon behaves.
|
||||
*
|
||||
* @since 1.7.0
|
||||
*/
|
||||
interface RideController : Encodable, Decodable {
|
||||
|
||||
/** A reference key used to denote the individual controller */
|
||||
val key: ResourceLocation
|
||||
|
||||
/**
|
||||
* Specifies the provider of poses which helps control updating the current pose on the pokemon
|
||||
* being ridden. Controllers are expected to define the pose types responsible for posing the entity
|
||||
* through all expected conditions. It should define a default pose, that will be used in all cases
|
||||
* where a pose does not meet the current conditions for the current mount. Typically, this will be
|
||||
* an idle pose.
|
||||
*/
|
||||
val poseProvider: PoseProvider
|
||||
|
||||
/**
|
||||
* Represents a condition that must be met for this controller to be active. For instance, this can be used
|
||||
* to evaluate things such as current velocity or block state of the entity.
|
||||
*/
|
||||
val condition: (PokemonEntity) -> Boolean
|
||||
|
||||
/**
|
||||
* Specifies the pose the ridden mount should be positioned in. This queries the pose provider using
|
||||
* the entity as a means of determining the conditions the entity is currently under. This allows for
|
||||
* dynamic pose updates.
|
||||
*/
|
||||
fun pose(entity: PokemonEntity): PoseType {
|
||||
return this.poseProvider.select(entity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the current speed of the mount.
|
||||
*/
|
||||
fun speed(entity: PokemonEntity, driver: Player): Float
|
||||
|
||||
/**
|
||||
* Sets the rotation of the mount. This is typically based on the controlling driver and is manipulated as
|
||||
* necessary.
|
||||
*/
|
||||
fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2
|
||||
|
||||
/**
|
||||
* Sets the change current change in rotation for that tick in three
|
||||
* dimensions
|
||||
*/
|
||||
fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
fun clampPassengerRotation(entity: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun updatePassengerRotation(entity: PokemonEntity, driver: LivingEntity) {
|
||||
driver.yRot = entity.yRot
|
||||
}
|
||||
|
||||
/**
|
||||
* Manipulates the movement input as necessary by the controller. This is primarily used to apply limits
|
||||
* to the types of movements. For instance, we can apply limits to any sort of sideways movement input, so that
|
||||
* it would otherwise be slower than normal forward movement.
|
||||
*/
|
||||
fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3
|
||||
|
||||
fun setRideBar(entity: PokemonEntity, driver: Player): Float = 0.0f
|
||||
|
||||
fun rideFovMult(entity: PokemonEntity, driver: Player): Float = 1.0f
|
||||
|
||||
fun canJump(entity: PokemonEntity, driver: Player): Boolean
|
||||
|
||||
fun jumpForce(entity: PokemonEntity, driver: Player, jumpStrength: Int): Vec3
|
||||
|
||||
fun gravity(entity: PokemonEntity, regularGravity: Double): Double? = null
|
||||
|
||||
fun inertia(entity: PokemonEntity): Double = 0.5
|
||||
|
||||
fun shouldRoll(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun useAngVelSmoothing(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean = false
|
||||
|
||||
//If function is not overwritten by controllers then just perform the defualt
|
||||
//rolling function which is roll on mousex and pitch on mousey
|
||||
fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is Rollable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val rollable = driver as Rollable
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, yMouse * invertPitch, xMouse * invertRoll)
|
||||
}
|
||||
|
||||
fun turnOffOnGround(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun dismountOnShift(entity: PokemonEntity): Boolean = false
|
||||
|
||||
fun getRuntime(entity: PokemonEntity) = entity.riding.runtime
|
||||
|
||||
fun shouldRotatePokemonHead(): Boolean = false
|
||||
fun shouldRotatePlayerHead(): Boolean = false
|
||||
|
||||
fun <T : RidingState> getState(entity: PokemonEntity, constructor: (PokemonEntity) -> T): T {
|
||||
return entity.riding.getState(key, constructor)
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeIdentifier(this.key)
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +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.riding.controller.posing
|
||||
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import java.util.function.Predicate
|
||||
|
||||
data class PoseOption(val pose: PoseType, val condition: Predicate<PokemonEntity>)
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.controller.posing
|
||||
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
|
||||
class PoseProvider(private val fallback: PoseType) {
|
||||
|
||||
private val options = mutableListOf<PoseOption>()
|
||||
|
||||
fun select(entity: PokemonEntity) : PoseType {
|
||||
return this.options.stream()
|
||||
.filter { it.condition.test(entity) }
|
||||
.map { it.pose }
|
||||
.findFirst()
|
||||
.orElse(this.fallback)
|
||||
}
|
||||
|
||||
fun with(option: PoseOption) : PoseProvider {
|
||||
this.options.add(option)
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.riding.posing
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
|
||||
data class PoseOption<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(
|
||||
val pose: PoseType,
|
||||
val condition: (Settings, State, PokemonEntity) -> Boolean
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.riding.posing
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
|
||||
class PoseProvider<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(private val fallback: PoseType) {
|
||||
|
||||
private val options = mutableListOf<PoseOption<Settings, State>>()
|
||||
|
||||
fun select(settings: Settings, state: State, entity: PokemonEntity) : PoseType {
|
||||
return this.options.stream()
|
||||
.filter { it.condition(settings, state, entity) }
|
||||
.map { it.pose }
|
||||
.findFirst()
|
||||
.orElse(this.fallback)
|
||||
}
|
||||
|
||||
fun with(option: PoseOption<Settings, State>) : PoseProvider<Settings, State> {
|
||||
this.options.add(option)
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -61,9 +61,9 @@ class LocationRuleCalculator : SpawnRuleComponent {
|
||||
reusableContext.value = contextCalculator.name
|
||||
|
||||
if (!this::reusableWorldValue.isInitialized) {
|
||||
reusableWorldValue = world.registryAccess().registryOrThrow(Registries.DIMENSION).getHolder(world.dimension()).get().asWorldMoLangValue()
|
||||
reusableWorldValue = world.registryAccess().registryOrThrow(Registries.DIMENSION).wrapAsHolder(world).asWorldMoLangValue()
|
||||
} else {
|
||||
reusableWorldValue.obj = world.registryAccess().registryOrThrow(Registries.DIMENSION).getHolder(world.dimension()).get()
|
||||
reusableWorldValue.obj = world.registryAccess().registryOrThrow(Registries.DIMENSION).wrapAsHolder(world)
|
||||
}
|
||||
|
||||
if (!this::reusableDimensionTypeValue.isInitialized) {
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
class ActiveBattlePokemon(val actor: BattleActor, var battlePokemon: BattlePokemon? = null): Targetable {
|
||||
val battle = actor.battle
|
||||
@@ -28,4 +32,115 @@ class ActiveBattlePokemon(val actor: BattleActor, var battlePokemon: BattlePokem
|
||||
override fun hasPokemon() = battlePokemon != null
|
||||
fun isGone() = battlePokemon?.gone ?: true
|
||||
fun isAlive() = (battlePokemon?.health ?: 0) > 0
|
||||
|
||||
fun getSendOutPosition(): Vec3? {
|
||||
val pnx = getPNX()
|
||||
val actorEntityPosList = actor.getSide().actors.mapNotNull { if (it is EntityBackedBattleActor<*>) it.initialPos else null }
|
||||
val actorEntityPos = if (actorEntityPosList.size == 1)
|
||||
actorEntityPosList[0]
|
||||
else if (actorEntityPosList.size > 1)
|
||||
actorEntityPosList.fold(Vec3(0.0, 0.0, 0.0)) { acc, vec3 -> acc.add(vec3.scale(1.0 / actorEntityPosList.size)) }
|
||||
else
|
||||
null
|
||||
val opposingActorEntityList = actor.getSide().getOppositeSide().actors.mapNotNull { if (it is EntityBackedBattleActor<*>) it.initialPos else null }
|
||||
val opposingEntityPos = if (opposingActorEntityList.size == 1)
|
||||
opposingActorEntityList[0]
|
||||
else if (opposingActorEntityList.size > 1) {
|
||||
// If multiple actors per side, avg their position
|
||||
opposingActorEntityList.fold(Vec3(0.0, 0.0, 0.0)) { acc, vec3 -> acc.add(vec3.scale(1.0 / opposingActorEntityList.size)) }
|
||||
}
|
||||
else null
|
||||
|
||||
var actorOffset = actorEntityPos?.let { opposingEntityPos?.subtract(it) }
|
||||
var result = actorEntityPos
|
||||
if (actorOffset != null) {
|
||||
var widthSum = 4.0 // Leave a constant to allow double/triples alignment to be consistent
|
||||
var pokemonWidth = battlePokemon?.originalPokemon?.form?.hitbox?.width ?: 0F
|
||||
val pokemonBaseScale = battlePokemon?.originalPokemon?.form?.baseScale ?: 0F
|
||||
pokemonWidth *= pokemonBaseScale
|
||||
if (battle.format.battleType.pokemonPerSide == 1) {
|
||||
battlePokemon?.let { battlePokemon ->
|
||||
// sum of the hitbox widths of both pokemon
|
||||
val opposingActivePokemon = (getOppositeOpponent() as ActiveBattlePokemon)
|
||||
val opposingPokemonWidth = opposingActivePokemon.battlePokemon?.let {
|
||||
it.originalPokemon.form.hitbox.width * it.originalPokemon.form.baseScale
|
||||
} ?: pokemonWidth
|
||||
widthSum = (pokemonWidth + opposingPokemonWidth) / 2.0 // Only care about the front half of each hitbox
|
||||
}
|
||||
}
|
||||
|
||||
val minDistance = 4.0 + widthSum
|
||||
val actorDistance = actorOffset.length()
|
||||
|
||||
if (actorDistance < minDistance) {
|
||||
val temp = actorOffset.scale(minDistance / actorDistance) ?: actorOffset
|
||||
result = actorEntityPos?.subtract(temp.subtract(actorOffset))
|
||||
actorOffset = temp
|
||||
}
|
||||
// orthogonalVector is the sideways displacement from the battle actors
|
||||
var orthogonalVector = Vec3(actorOffset.x, 0.0, actorOffset.z).normalize()
|
||||
orthogonalVector = orthogonalVector.cross(Vec3(0.0, 1.0, 0.0))
|
||||
|
||||
if (battle.format.battleType.pokemonPerSide == 1) { // Singles
|
||||
result = result?.add(actorOffset.scale(if (battle.isPvW) 0.4 else 0.3))
|
||||
battlePokemon?.let { battlePokemon ->
|
||||
val hitbox = battlePokemon.originalPokemon.form.hitbox
|
||||
val scale = battlePokemon.originalPokemon.form.baseScale
|
||||
orthogonalVector = orthogonalVector.scale(-0.3 - hitbox.width * scale )
|
||||
}
|
||||
} else if (battle.format.battleType.pokemonPerSide == 2) { // Doubles/Multi
|
||||
if (battle.actors.first() != battle.actors.last()) {
|
||||
val offsetB = if (pnx[2] == 'a') orthogonalVector.scale(-1.0) else orthogonalVector
|
||||
result = result?.add(actorOffset.scale(0.33))
|
||||
orthogonalVector = offsetB.scale(2.5)
|
||||
}
|
||||
} else if (battle.format.battleType.pokemonPerSide == 3) { // Triples
|
||||
if (battle.actors.first() != battle.actors.last()) {
|
||||
result = when (pnx[2]) {
|
||||
'a' -> {
|
||||
orthogonalVector = orthogonalVector.scale(-3.5)
|
||||
result?.add(actorOffset.scale(0.15))
|
||||
}
|
||||
'b' -> {
|
||||
orthogonalVector = Vec3.ZERO
|
||||
result?.add(actorOffset.scale(0.3))
|
||||
}
|
||||
'c' -> {
|
||||
orthogonalVector = orthogonalVector.scale(3.5)
|
||||
result?.add(actorOffset.scale(0.15))
|
||||
}
|
||||
else -> result
|
||||
}
|
||||
}
|
||||
}
|
||||
val fallbackPos = result
|
||||
result = result?.add(orthogonalVector)
|
||||
if (actor is EntityBackedBattleActor<*> && result != null) {
|
||||
val entity = actor.entity ?: return result
|
||||
// Do a single raycast to estimate if we're trying to throw a pokemon into a wall.
|
||||
// If the collision is too close to the actor, try to find a more reasonable position.
|
||||
// The motivation here is to give setPositionSafely something more reasonable to work with.
|
||||
val collisionResult = entity.level().clip(
|
||||
ClipContext(
|
||||
actorEntityPos!!.add(Vec3(0.0,entity.eyeHeight.toDouble(),0.0)), // start position
|
||||
Vec3(result.x, entity.y + entity.eyeHeight.toDouble(), result.z), // end position
|
||||
ClipContext.Block.OUTLINE,
|
||||
ClipContext.Fluid.NONE,
|
||||
entity
|
||||
)
|
||||
)
|
||||
if (collisionResult.type == HitResult.Type.BLOCK) {
|
||||
// Collided with terrain
|
||||
result = if (collisionResult.location.distanceToSqr(actorEntityPos) < pokemonWidth) {
|
||||
// Fallback to in between the two actors, dropping the orthogonal vector
|
||||
// Ideally this keeps a pokemon in between the actors in a narrow tunnel
|
||||
fallbackPos
|
||||
} else {
|
||||
Vec3(collisionResult.location.x, result.y, collisionResult.location.z)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import com.cobblemon.mod.common.battles.interpreter.instructions.*
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.runOnServer
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.phys.HitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.UUID
|
||||
import kotlin.collections.Iterator
|
||||
@@ -34,6 +36,7 @@ import kotlin.collections.mutableMapOf
|
||||
import kotlin.collections.set
|
||||
import kotlin.collections.toMutableList
|
||||
import kotlin.collections.toTypedArray
|
||||
import kotlin.time.measureTime
|
||||
|
||||
@Suppress("KotlinPlaceholderCountMatchesArgumentCount", "UNUSED_PARAMETER")
|
||||
object ShowdownInterpreter {
|
||||
@@ -138,85 +141,6 @@ object ShowdownInterpreter {
|
||||
// Note '-cureteam' is a legacy thing that is only used in generation 2 and 4 mods for heal bell and aromatherapy respectively as such we can just ignore that
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Figures out the sendout position for a pokemon in a battle
|
||||
*
|
||||
*
|
||||
*/
|
||||
fun getSendoutPosition(battle: PokemonBattle, activePokemon: ActiveBattlePokemon, battleActor: BattleActor): Vec3? {
|
||||
val pnx = activePokemon.getPNX()
|
||||
val actorEntityPosList = battleActor.getSide().actors.mapNotNull { if (it is EntityBackedBattleActor<*>) it.initialPos else null }
|
||||
val actorEntityPos = if (actorEntityPosList.size == 1)
|
||||
actorEntityPosList[0]
|
||||
else if (actorEntityPosList.size > 1)
|
||||
actorEntityPosList.fold(Vec3(0.0, 0.0, 0.0)) { acc, vec3 -> acc.add(vec3.scale(1.0 / actorEntityPosList.size)) }
|
||||
else
|
||||
null
|
||||
val opposingActorEntityList = battleActor.getSide().getOppositeSide().actors.mapNotNull { if (it is EntityBackedBattleActor<*>) it.initialPos else null }
|
||||
val opposingEntityPos = if (opposingActorEntityList.size == 1)
|
||||
opposingActorEntityList[0]
|
||||
else if (opposingActorEntityList.size > 1) {
|
||||
// If multiple actors per side, avg their position
|
||||
opposingActorEntityList.fold(Vec3(0.0, 0.0, 0.0)) { acc, vec3 -> acc.add(vec3.scale(1.0 / opposingActorEntityList.size)) }
|
||||
}
|
||||
else null
|
||||
|
||||
var actorOffset = actorEntityPos?.let { opposingEntityPos?.subtract(it) }
|
||||
var result = actorEntityPos
|
||||
if (actorOffset != null) {
|
||||
var widthSum = 4.0 // Leave a constant to allow double/triples alignment to be consistent
|
||||
if (battle.format.battleType.pokemonPerSide == 1) {
|
||||
activePokemon.battlePokemon?.let { battlePokemon ->
|
||||
// sum of the hitbox widths of both pokemon
|
||||
val opposingActivePokemon = (activePokemon.getOppositeOpponent() as ActiveBattlePokemon)
|
||||
val pokemonWidth = battlePokemon.originalPokemon.form.hitbox.width * battlePokemon.originalPokemon.form.baseScale
|
||||
val opposingPokemonWidth = opposingActivePokemon.battlePokemon?.let {
|
||||
it.originalPokemon.form.hitbox.width * it.originalPokemon.form.baseScale
|
||||
} ?: pokemonWidth
|
||||
widthSum = (pokemonWidth + opposingPokemonWidth) / 2.0 // Only care about the front half of each hitbox
|
||||
}
|
||||
}
|
||||
|
||||
val minDistance = 4.0 + widthSum
|
||||
val actorDistance = actorOffset.length()
|
||||
|
||||
if (actorDistance < minDistance) {
|
||||
val temp = actorOffset.scale(minDistance / actorDistance) ?: actorOffset
|
||||
result = actorEntityPos?.subtract(temp.subtract(actorOffset))
|
||||
actorOffset = temp
|
||||
}
|
||||
var vector = Vec3(actorOffset.x, 0.0, actorOffset.z).normalize()
|
||||
vector = vector.cross(Vec3(0.0, 1.0, 0.0))
|
||||
|
||||
if (battle.format.battleType.pokemonPerSide == 1) { // Singles
|
||||
result = result?.add(actorOffset.scale(if (battle.isPvW) 0.4 else 0.3))
|
||||
activePokemon.battlePokemon?.let { battlePokemon ->
|
||||
val hitbox = battlePokemon.originalPokemon.form.hitbox
|
||||
val scale = battlePokemon.originalPokemon.form.baseScale
|
||||
activePokemon.getAdjacentOpponents()
|
||||
result = result?.add(vector.scale(-0.3 - hitbox.width * scale ))
|
||||
}
|
||||
} else if (battle.format.battleType.pokemonPerSide == 2) { // Doubles/Multi
|
||||
if (battle.actors.first() !== battle.actors.last()) {
|
||||
val offsetB = if (pnx[2] == 'a') vector.scale(-1.0) else vector
|
||||
result = result?.add(actorOffset.scale(0.33))?.add(offsetB.scale(2.5))
|
||||
}
|
||||
} else if (battle.format.battleType.pokemonPerSide == 3) { // Triples
|
||||
if (battle.actors.first() !== battle.actors.last()) {
|
||||
result = when (pnx[2]) {
|
||||
'a' -> result?.add(actorOffset.scale(0.15))?.add(vector.scale(-3.5))
|
||||
'b' -> result?.add(actorOffset.scale(0.3))
|
||||
'c' -> result?.add(actorOffset.scale(0.15))?.add(vector.scale(3.5))
|
||||
else -> result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun interpretMessage(battleId: UUID, message: String) {
|
||||
// Check key map and use function if matching
|
||||
|
||||
+2
-3
@@ -13,7 +13,6 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleSwapPokemonPacket
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.setPositionSafely
|
||||
@@ -42,12 +41,12 @@ class SwapInstruction(val message: BattleMessage, val instructionSet: Instructio
|
||||
// Swap references of the 2 pokemon
|
||||
actor.activePokemon.swap((pnxA[2] - 'a'), (pnxB[2] - 'a'))
|
||||
|
||||
val posA = ShowdownInterpreter.getSendoutPosition(battle, activePokemonA, battlePokemonA.actor) ?: activePokemonA.position?.second
|
||||
val posA = activePokemonA.getSendOutPosition() ?: activePokemonA.position?.second
|
||||
if (posA != null && battlePokemonA.entity != null) {
|
||||
battlePokemonA.entity?.setPositionSafely(battlePokemonA.entity!!.getAjustedSendoutPosition(posA))
|
||||
}
|
||||
|
||||
val posB = ShowdownInterpreter.getSendoutPosition(battle, activePokemonB, battlePokemonA.actor) ?: activePokemonB.position?.second
|
||||
val posB = activePokemonB.getSendOutPosition() ?: activePokemonB.position?.second
|
||||
val battlePokemonB = activePokemonB.battlePokemon
|
||||
if (posB != null && battlePokemonB?.entity != null) {
|
||||
activePokemonB.battlePokemon?.entity?.setPositionSafely(battlePokemonB.entity!!.getAjustedSendoutPosition(posB))
|
||||
|
||||
+4
-4
@@ -70,7 +70,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
else if (pokemonEntity == null && entity != null) {
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
val targetPos = ShowdownInterpreter.getSendoutPosition(battle, activePokemon, battleActor)
|
||||
val targetPos = activePokemon.getSendOutPosition()
|
||||
if (targetPos != null) {
|
||||
val battleSendoutCount = activePokemon.getActorShowdownId()[1].digitToInt() - 1 + actor.stillSendingOutCount
|
||||
actor.stillSendingOutCount++
|
||||
@@ -180,7 +180,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
}
|
||||
} else {
|
||||
// For Singles, we modify the sendout position based on the pokemon's hitbox size
|
||||
val pos = (if (battle.format.battleType.pokemonPerSide == 1) ShowdownInterpreter.getSendoutPosition(battle, activePokemon, actor)
|
||||
val pos = (if (battle.format.battleType.pokemonPerSide == 1) activePokemon.getSendOutPosition()
|
||||
else activePokemon.position?.second) ?: entity.position()
|
||||
// Send out at previous Pokémon's location if it is known, otherwise actor location
|
||||
val world = entity.level() as ServerLevel
|
||||
@@ -213,8 +213,8 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
val publicPokemon = (illusion ?: newPokemon).effectedPokemon
|
||||
val publicLang = publicPokemon.nickname?.let { nickname ->
|
||||
battleLang("switch.other.nickname", actor.getName(), nickname, publicPokemon.species.translatedName)
|
||||
} ?: battleLang("switch.other", actor.getName(), publicPokemon.getDisplayName())
|
||||
actor.sendMessage(battleLang("switch.self", publicPokemon.getDisplayName()))
|
||||
} ?: battleLang("switch.other", actor.getName(), publicPokemon.getDisplayName(true))
|
||||
actor.sendMessage(battleLang("switch.self", publicPokemon.getDisplayName(true)))
|
||||
battle.actors.filter { it != actor }.forEach {
|
||||
it.sendMessage(publicLang)
|
||||
}
|
||||
|
||||
+43
-4
@@ -12,8 +12,8 @@ import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
@@ -32,6 +32,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.Primar
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
|
||||
import com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer.Companion.ease
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
@@ -42,10 +43,9 @@ import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Entity.MoveFunction
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
|
||||
class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
@@ -103,6 +103,7 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
currentEntity.pokemon.species = PokemonSpecies.getByIdentifier(identifier)!! // TODO exception handling
|
||||
// force a model update - handles edge case where the PosableState's tracked PosableModel isn't updated until the LivingEntityRenderer render is run
|
||||
currentModel = VaryingModelRepository.getPoser(identifier, this)
|
||||
currentEntity.refreshRiding()
|
||||
} else if (data == PokemonEntity.ASPECTS) {
|
||||
currentAspects = currentEntity.entityData.get(PokemonEntity.ASPECTS)
|
||||
currentEntity.pokemon.shiny = currentAspects.contains("shiny")
|
||||
@@ -376,6 +377,18 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
override fun tick(entity: PokemonEntity) {
|
||||
incrementAge(entity)
|
||||
playWildShinySounds()
|
||||
sendRidingChanges(entity)
|
||||
}
|
||||
|
||||
private fun sendRidingChanges(entity: PokemonEntity) {
|
||||
val player = Minecraft.getInstance().player ?: return
|
||||
if (entity.controllingPassenger != player) return
|
||||
entity.ifRidingAvailable { behaviour, _, state ->
|
||||
if (entity.previousRidingState != null && !state.shouldSync(entity.previousRidingState!!)) {
|
||||
return@ifRidingAvailable
|
||||
}
|
||||
CobblemonNetwork.sendToServer(ServerboundUpdateRidingStatePacket(entity.id, behaviour.key, state))
|
||||
}
|
||||
}
|
||||
|
||||
fun playWildShinySounds() {
|
||||
@@ -440,4 +453,30 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
}
|
||||
cryAnimation = animation
|
||||
}
|
||||
}
|
||||
|
||||
override fun positionRider(passenger: Entity, positionUpdater: MoveFunction) {
|
||||
val index =
|
||||
this.getEntity().passengers.indexOf(passenger).takeIf { it >= 0 && it < this.getEntity().seats.size }
|
||||
?: return
|
||||
val seat = this.getEntity().seats[index]
|
||||
val locator = this.locatorStates[seat.locator]
|
||||
|
||||
if (locator == null) return
|
||||
|
||||
val offset = locator.matrix.getTranslation(Vector3f())
|
||||
.sub(
|
||||
Vector3f(
|
||||
0f,
|
||||
passenger.eyeHeight - (passenger.bbHeight / 2),
|
||||
0f
|
||||
)
|
||||
) // This is close but not exact
|
||||
|
||||
positionUpdater.accept(
|
||||
passenger,
|
||||
this.getEntity().x + offset.x,
|
||||
this.getEntity().y + offset.y,
|
||||
this.getEntity().z + offset.z
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.common
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
|
||||
class MarkIcon(
|
||||
val x: Number,
|
||||
val y: Number,
|
||||
val mark: Mark,
|
||||
val showTooltip: Boolean = true,
|
||||
val opacity: Float = 1F
|
||||
) {
|
||||
companion object {
|
||||
const val SIZE = 32
|
||||
const val SCALE = 0.5F
|
||||
}
|
||||
|
||||
fun render(context: GuiGraphics, mouseX: Int, mouseY: Int) {
|
||||
blitk(
|
||||
matrixStack = context.pose(),
|
||||
texture = mark.texture,
|
||||
x = x.toFloat() / SCALE,
|
||||
y = y.toFloat() / SCALE,
|
||||
height = SIZE,
|
||||
width = SIZE,
|
||||
alpha = opacity,
|
||||
scale = SCALE
|
||||
)
|
||||
|
||||
if (showTooltip && isHovered(mouseX, mouseY)) {
|
||||
context.renderTooltip(Minecraft.getInstance().font, mark.getName(), mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
|
||||
fun isHovered(mouseX: Int, mouseY: Int): Boolean =
|
||||
mouseX.toFloat() in (x.toFloat()..(x.toFloat() + (SIZE * SCALE)))
|
||||
&& mouseY.toFloat() in (y.toFloat()..(y.toFloat() + (SIZE * SCALE)))
|
||||
}
|
||||
+4
-4
@@ -98,13 +98,13 @@ class CobblemonConfigIntVariable(
|
||||
override fun getConfigValueAsString(): String = (config.getter.call(parent.parent.clonedConfig) as Int?).toString()
|
||||
|
||||
init {
|
||||
editBox.setFilter { value -> value.toIntOrNull() != null || value.isBlank() }
|
||||
editBox.setFilter { value -> value.toIntOrNull() != null || value.isBlank() || value == "-" }
|
||||
editBox.setResponder { value ->
|
||||
if (value.isBlank()) {
|
||||
return@setResponder
|
||||
}
|
||||
|
||||
val intValue = value.toInt()
|
||||
val intValue = value.toIntOrNull() ?: return@setResponder
|
||||
setConfigValue(intValue, false)
|
||||
|
||||
if (intConstraintAnnotation != null) {
|
||||
@@ -129,7 +129,7 @@ class CobblemonConfigFloatVariable(
|
||||
override fun getConfigValueAsString(): String = (config.getter.call(parent.parent.clonedConfig) as Float?).toString()
|
||||
|
||||
init {
|
||||
editBox.setFilter { value -> value.toFloatOrNull() != null || value.isBlank() }
|
||||
editBox.setFilter { value -> value.toFloatOrNull() != null || value.isBlank() || value == "." || value == "-" }
|
||||
editBox.setResponder { value ->
|
||||
if (value.toFloatOrNull() != null) {
|
||||
setConfigValue(value.toFloat(), false)
|
||||
@@ -145,7 +145,7 @@ class CobblemonConfigDoubleVariable(
|
||||
override fun getConfigValueAsString(): String = (config.getter.call(parent.parent.clonedConfig) as Double?).toString()
|
||||
|
||||
init {
|
||||
editBox.setFilter { value -> value.toDoubleOrNull() != null || value.isBlank() }
|
||||
editBox.setFilter { value -> value.toDoubleOrNull() != null || value.isBlank() || value == "." || value == "-" }
|
||||
editBox.setResponder { value ->
|
||||
if (value.toDoubleOrNull() != null) {
|
||||
setConfigValue(value.toDouble(), false)
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.reformatNatureTextIfMinted
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
@@ -81,9 +82,10 @@ class PCGUI(
|
||||
private lateinit var boxNameWidget: BoxNameWidget
|
||||
private lateinit var filterWidget: FilterWidget
|
||||
private lateinit var wallpaperWidget: WallpapersScrollingWidget
|
||||
|
||||
private lateinit var markingsWidget: MarkingsWidget
|
||||
private var modelWidget: ModelWidget? = null
|
||||
internal var previewPokemon: Pokemon? = null
|
||||
var isPreviewInParty: Boolean? = null
|
||||
|
||||
private val optionButtons: MutableList<IconButton> = mutableListOf()
|
||||
|
||||
@@ -110,6 +112,7 @@ class PCGUI(
|
||||
for (button in optionButtons) button.highlighted = false
|
||||
playSound(CobblemonSounds.PC_CLICK)
|
||||
} else {
|
||||
saveMarkings(isPreviewInParty ?: false)
|
||||
configuration.exitFunction(this)
|
||||
}
|
||||
}
|
||||
@@ -239,6 +242,8 @@ class PCGUI(
|
||||
}
|
||||
}
|
||||
|
||||
this.markingsWidget = MarkingsWidget(x + 29, y + 96.5, null, false)
|
||||
this.addRenderableWidget(markingsWidget)
|
||||
this.setPreviewPokemon(null)
|
||||
|
||||
super.init()
|
||||
@@ -575,12 +580,15 @@ class PCGUI(
|
||||
val filterFocused = this::filterWidget.isInitialized && filterWidget.isFocused
|
||||
|
||||
if (isInventoryKeyPressed(minecraft, keyCode, scanCode) && !boxNameFocused && !filterFocused) {
|
||||
saveMarkings(isPreviewInParty ?: false)
|
||||
playSound(CobblemonSounds.PC_OFF)
|
||||
UnlinkPlayerFromPCPacket().sendToServer()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
return true
|
||||
}
|
||||
|
||||
if (keyCode == InputConstants.KEY_ESCAPE) saveMarkings(isPreviewInParty ?: false)
|
||||
|
||||
if (!filterFocused && !boxNameFocused) {
|
||||
when (keyCode) {
|
||||
InputConstants.KEY_ESCAPE -> {
|
||||
@@ -628,8 +636,13 @@ class PCGUI(
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
fun setPreviewPokemon(pokemon: Pokemon?) {
|
||||
private fun saveMarkings(isParty: Boolean = false) {
|
||||
if (::markingsWidget.isInitialized) markingsWidget.saveMarkingsToPokemon(isParty)
|
||||
}
|
||||
|
||||
fun setPreviewPokemon(pokemon: Pokemon?, isParty: Boolean = false) {
|
||||
if (pokemon != null) {
|
||||
saveMarkings(isParty)
|
||||
previewPokemon = pokemon
|
||||
|
||||
val x = (width - BASE_WIDTH) / 2
|
||||
@@ -644,9 +657,11 @@ class PCGUI(
|
||||
rotationY = 325F,
|
||||
offsetY = -10.0
|
||||
)
|
||||
markingsWidget.setActivePokemon(previewPokemon)
|
||||
} else {
|
||||
previewPokemon = null
|
||||
modelWidget = null
|
||||
markingsWidget.setActivePokemon(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +321,11 @@ class StorageWidget(
|
||||
slot.render(context, mouseX, mouseY, delta)
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon) pcGui.setPreviewPokemon(pokemon)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: false)
|
||||
pcGui.isPreviewInParty = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pcGui.ticksElapsed >= 10) screenLoaded = true
|
||||
@@ -334,7 +338,10 @@ class StorageWidget(
|
||||
val pokemon = slot.getPokemon()
|
||||
if (grabbedSlot == null && slot.isHovered(mouseX, mouseY)
|
||||
&& pokemon != null && pokemon != pcGui.previewPokemon
|
||||
) pcGui.setPreviewPokemon(pokemon)
|
||||
) {
|
||||
pcGui.setPreviewPokemon(pokemon, pcGui.isPreviewInParty ?: true)
|
||||
pcGui.isPreviewInParty = true
|
||||
} // TODO: Hovering from party to party or pc not saving marks
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +434,7 @@ class StorageWidget(
|
||||
}
|
||||
|
||||
this.selectedPosition = clickedPosition
|
||||
this.pcGui.setPreviewPokemon(clickedPokemon)
|
||||
this.pcGui.setPreviewPokemon(clickedPokemon, pcGui.isPreviewInParty ?: false)
|
||||
grabbedSlot = GrabbedStorageSlot(
|
||||
x = button.x,
|
||||
y = button.y,
|
||||
|
||||
@@ -23,12 +23,10 @@ import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.EvolutionSelectScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.ModelWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.NicknameEntryWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.PartyWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.*
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.SummaryTab
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.info.InfoWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks.MarksWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MoveSwapScreen
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.moves.MovesWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.stats.StatWidget
|
||||
@@ -75,6 +73,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
private const val INFO = 0
|
||||
private const val MOVES = 1
|
||||
private const val STATS = 2
|
||||
private const val MARKS = 3
|
||||
|
||||
// Side Screen Index
|
||||
const val PARTY = 0
|
||||
@@ -93,6 +92,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
private val tabIconInfo = cobblemonResource("textures/gui/summary/summary_tab_icon_info.png")
|
||||
private val tabIconMoves = cobblemonResource("textures/gui/summary/summary_tab_icon_moves.png")
|
||||
private val tabIconStats = cobblemonResource("textures/gui/summary/summary_tab_icon_stats.png")
|
||||
private val tabIconMarks = cobblemonResource("textures/gui/summary/summary_tab_icon_marks.png")
|
||||
val iconShinyResource = cobblemonResource("textures/gui/summary/icon_shiny.png")
|
||||
val iconHeldItemResource = cobblemonResource("textures/gui/summary/icon_item_held.png")
|
||||
val iconCosmeticItemResource = cobblemonResource("textures/gui/summary/icon_item_cosmetic.png")
|
||||
@@ -122,8 +122,10 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
lateinit var sideScreen: GuiEventListener
|
||||
private lateinit var modelWidget: ModelWidget
|
||||
private lateinit var nicknameEntryWidget: NicknameEntryWidget
|
||||
private lateinit var markingsWidget: MarkingsWidget
|
||||
private val summaryTabs = mutableListOf<SummaryTab>()
|
||||
private var showCosmeticItem = false
|
||||
private lateinit var heldItemVisibilityButton: SummaryButton
|
||||
private var mainScreenIndex = INFO
|
||||
var sideScreenIndex = PARTY
|
||||
private val party = ArrayList(party)
|
||||
@@ -155,6 +157,13 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
displayMainScreen(mainScreenIndex)
|
||||
displaySideScreen(PARTY)
|
||||
|
||||
markingsWidget = MarkingsWidget(
|
||||
x + 29,
|
||||
y + 102,
|
||||
selectedPokemon
|
||||
)
|
||||
addRenderableWidget(markingsWidget)
|
||||
|
||||
// Evolve Button
|
||||
addRenderableWidget(
|
||||
SummaryButton(
|
||||
@@ -173,7 +182,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
)
|
||||
|
||||
//Item Visibility Button
|
||||
val HeldItemVisibilityButton = SummaryButton(
|
||||
heldItemVisibilityButton = SummaryButton(
|
||||
buttonX = x + 3F,
|
||||
buttonY = y + 104F,
|
||||
buttonWidth = 32,
|
||||
@@ -183,7 +192,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
activeResource = itemHiddenResource,
|
||||
clickAction = {
|
||||
selectedPokemon.heldItemVisible = !selectedPokemon.heldItemVisible
|
||||
(it as SummaryButton).buttonActive = !selectedPokemon.heldItemVisible
|
||||
heldItemVisibilityButton.buttonActive = !selectedPokemon.heldItemVisible
|
||||
modelWidget.heldItem = if (selectedPokemon.heldItemVisible) selectedPokemon.heldItem else null
|
||||
// Send item visibility update to server
|
||||
sendToServer(SetItemHiddenPacket(selectedPokemon.uuid, selectedPokemon.heldItemVisible))
|
||||
@@ -191,8 +200,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
renderRequirement = { !selectedPokemon.heldItemNoCopy().isEmpty && !showCosmeticItem },
|
||||
clickRequirement = { !selectedPokemon.heldItemNoCopy().isEmpty && !showCosmeticItem }
|
||||
)
|
||||
|
||||
addRenderableWidget(HeldItemVisibilityButton)
|
||||
heldItemVisibilityButton.buttonActive = !selectedPokemon.heldItemVisible
|
||||
addRenderableWidget(heldItemVisibilityButton)
|
||||
|
||||
// Held/Cosmetic Item Button
|
||||
addRenderableWidget(
|
||||
@@ -215,28 +224,25 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
summaryTabs.clear()
|
||||
summaryTabs.add(
|
||||
SummaryTab(pX = x + 78, pY = y - 1, icon = tabIconInfo) {
|
||||
if (mainScreenIndex != INFO) {
|
||||
displayMainScreen(INFO)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
if (mainScreenIndex != INFO) displayMainScreen(INFO)
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs.add(
|
||||
SummaryTab(pX = x + 119, pY = y - 1, icon = tabIconMoves) {
|
||||
if (mainScreenIndex != MOVES) {
|
||||
displayMainScreen(MOVES)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
SummaryTab(pX = x + 109, pY = y - 1, icon = tabIconMoves) {
|
||||
if (mainScreenIndex != MOVES) displayMainScreen(MOVES)
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs.add(
|
||||
SummaryTab(pX = x + 160, pY = y - 1, icon = tabIconStats) {
|
||||
if (mainScreenIndex != STATS) {
|
||||
displayMainScreen(STATS)
|
||||
playSound(CobblemonSounds.GUI_CLICK)
|
||||
}
|
||||
SummaryTab(pX = x + 140, pY = y - 1, icon = tabIconStats) {
|
||||
if (mainScreenIndex != STATS) displayMainScreen(STATS)
|
||||
}
|
||||
)
|
||||
|
||||
summaryTabs.add(
|
||||
SummaryTab(pX = x + 171, pY = y - 1, icon = tabIconMarks) {
|
||||
if (mainScreenIndex != MARKS) displayMainScreen(MARKS)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -250,6 +256,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
if (sideScreenIndex != PARTY) {
|
||||
displaySideScreen(PARTY)
|
||||
} else {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
}
|
||||
}
|
||||
@@ -314,6 +322,7 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
* Switches the selected PKM
|
||||
*/
|
||||
fun switchSelection(newSelection: Int) {
|
||||
saveMarkings()
|
||||
this.selectedPokemon.moveSet.changeFunction = {}
|
||||
this.party.getOrNull(newSelection)?.let { this.selectedPokemon = it }
|
||||
listenToMoveSet()
|
||||
@@ -323,11 +332,12 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
if (::modelWidget.isInitialized) {
|
||||
modelWidget.pokemon = selectedPokemon.asRenderablePokemon()
|
||||
modelWidget.heldItem = if (selectedPokemon.heldItemVisible) selectedPokemon.heldItem else null
|
||||
heldItemVisibilityButton.buttonActive = !selectedPokemon.heldItemVisible
|
||||
}
|
||||
|
||||
if (this::nicknameEntryWidget.isInitialized) {
|
||||
this.nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
|
||||
}
|
||||
if (::nicknameEntryWidget.isInitialized) nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
|
||||
|
||||
if (::markingsWidget.isInitialized) markingsWidget.setActivePokemon(selectedPokemon)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,6 +351,14 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveMarkings() {
|
||||
if (::markingsWidget.isInitialized) markingsWidget.saveMarkingsToPokemon()
|
||||
}
|
||||
|
||||
private fun saveActiveMark() {
|
||||
if (mainScreenIndex == MARKS && mainScreen is MarksWidget) (mainScreen as MarksWidget).saveActiveMarkToPokemon()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this Screen is open or not
|
||||
*/
|
||||
@@ -350,6 +368,9 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
* Switch center screen
|
||||
*/
|
||||
private fun displayMainScreen(screen: Int) {
|
||||
// Save mark to Pokémon if any changes when switching out of marks screen
|
||||
saveActiveMark()
|
||||
|
||||
// Get stat tab index if currently displaying stat screen
|
||||
val subIndex = if (mainScreenIndex == STATS && mainScreen is StatWidget) (mainScreen as StatWidget).statTabIndex else 0
|
||||
|
||||
@@ -389,6 +410,14 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
tabIndex = subIndex
|
||||
)
|
||||
}
|
||||
|
||||
MARKS -> {
|
||||
mainScreen = MarksWidget(
|
||||
pX = x + 77,
|
||||
pY = y + 12,
|
||||
pokemon = this.selectedPokemon
|
||||
)
|
||||
}
|
||||
}
|
||||
addRenderableWidget(mainScreen)
|
||||
}
|
||||
@@ -438,6 +467,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
|
||||
EVOLVE -> {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
sideScreen = EvolutionSelectScreen(
|
||||
x + 216,
|
||||
y + 23,
|
||||
@@ -651,7 +682,15 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
|
||||
val nicknameSelected = this::nicknameEntryWidget.isInitialized && nicknameEntryWidget.isFocused
|
||||
|
||||
if (keyCode == InputConstants.KEY_ESCAPE) {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
}
|
||||
|
||||
|
||||
if (isInventoryKeyPressed(minecraft, keyCode, scanCode) && !nicknameSelected) {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
Minecraft.getInstance().setScreen(null)
|
||||
return true
|
||||
}
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class MarkingButton(
|
||||
val buttonX: Number,
|
||||
val buttonY: Number,
|
||||
var buttonState: Int,
|
||||
var canEdit: Boolean = true,
|
||||
private val resource: ResourceLocation,
|
||||
val clickAction: OnPress
|
||||
): Button(buttonX.toInt(), buttonY.toInt(), (SIZE / 2), (SIZE / 2), "".text(), clickAction, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
|
||||
companion object {
|
||||
const val SIZE = 12
|
||||
const val SCALE = 0.5F
|
||||
}
|
||||
|
||||
fun renderButton(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
val matrices = context.pose()
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = resource,
|
||||
x = buttonX.toFloat() / SCALE,
|
||||
y = buttonY.toFloat() / SCALE,
|
||||
width = SIZE,
|
||||
height = SIZE,
|
||||
vOffset = buttonState * SIZE,
|
||||
uOffset = if (canEdit && isMouseOver(mouseX.toDouble(), mouseY.toDouble())) SIZE else 0,
|
||||
textureHeight = SIZE * 3,
|
||||
textureWidth = SIZE * 2,
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
if (canEdit) soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
|
||||
override fun onClick(mouseX: Double, mouseY: Double) {
|
||||
if (canEdit) super.onClick(mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class MarkingsWidget(
|
||||
val pX: Number,
|
||||
val pY: Number,
|
||||
var pokemon: Pokemon?,
|
||||
var canEdit: Boolean = true,
|
||||
): SoundlessWidget(pX.toInt(), pY.toInt(), WIDTH, HEIGHT, Component.literal("MarkingsWidget")) {
|
||||
companion object {
|
||||
private const val WIDTH = 82
|
||||
private const val HEIGHT = 12
|
||||
}
|
||||
|
||||
var markingStates: MutableList<Int> = mutableListOf(0, 0, 0, 0, 0, 0)
|
||||
var markings: MutableList<MarkingButton> = mutableListOf()
|
||||
|
||||
init { setActivePokemon(pokemon) }
|
||||
|
||||
fun incrementState(state: Int) : Int = (state + 1) % 3
|
||||
|
||||
fun setActivePokemon(newPokemon: Pokemon?) {
|
||||
pokemon = newPokemon
|
||||
|
||||
children.clear()
|
||||
pokemon?.let {
|
||||
markingStates = it.markings.toMutableList()
|
||||
markingStates.forEachIndexed { index, state ->
|
||||
addWidget(MarkingButton(
|
||||
buttonX = pX.toFloat() + (index * ((MarkingButton.SIZE / 2) + 1)),
|
||||
buttonY = pY,
|
||||
buttonState = state,
|
||||
canEdit = canEdit,
|
||||
resource = cobblemonResource("textures/gui/summary/icon_marking_${index}.png")
|
||||
) {
|
||||
val nextState = incrementState(markingStates.get(index))
|
||||
markingStates.set(index, nextState)
|
||||
(it as MarkingButton).buttonState = nextState
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveMarkingsToPokemon(isParty: Boolean = true) {
|
||||
pokemon?.let {
|
||||
val currentStates = markingStates.toList()
|
||||
if (it.markings != currentStates) sendToServer(SetMarkingsPacket(it.uuid, currentStates, isParty))
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
children.forEach { (it as MarkingButton).renderButton(context, mouseX, mouseY, partialTicks) }
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -18,7 +18,6 @@ import com.cobblemon.mod.common.util.math.fromEulerXYZDegrees
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
|
||||
@@ -114,12 +113,13 @@ class ModelWidget(
|
||||
)
|
||||
|
||||
heldItemRenderer.renderOnModel(
|
||||
state.currentModel!!,
|
||||
heldItem?: ItemStack.EMPTY,
|
||||
state.currentModel!!,
|
||||
state,
|
||||
matrices,
|
||||
context.bufferSource(),
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
light = 0xF000F0,
|
||||
true
|
||||
)
|
||||
|
||||
matrices.popPose()
|
||||
|
||||
+20
-19
@@ -8,14 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.client.CobblemonResources
|
||||
import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.gui.components.Button
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.client.sounds.SoundManager
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -25,7 +25,15 @@ class SummaryTab(
|
||||
val label: MutableComponent? = null,
|
||||
val icon: ResourceLocation? = null,
|
||||
onPress: OnPress
|
||||
): Button(pX, pY, 50, 13, label, onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
): Button(pX, pY, WIDTH, HEIGHT, label, onPress, DEFAULT_NARRATION), CobblemonRenderable {
|
||||
companion object {
|
||||
private const val WIDTH = 39
|
||||
private const val HEIGHT = 13
|
||||
private const val SCALE = 0.5F
|
||||
|
||||
private val tabResource = cobblemonResource("textures/gui/summary/summary_tab.png")
|
||||
}
|
||||
|
||||
private var isActive = false
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTicks: Float) {
|
||||
@@ -33,7 +41,7 @@ class SummaryTab(
|
||||
if (isActive) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = cobblemonResource("textures/gui/summary/summary_tab.png"),
|
||||
texture = tabResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
@@ -45,31 +53,24 @@ class SummaryTab(
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = icon,
|
||||
x = (x + 21) / 0.5F,
|
||||
y = (y + 3.5) / 0.5F,
|
||||
x = (x + 15.5) / SCALE,
|
||||
y = (y + 3.5) / SCALE,
|
||||
width = 17,
|
||||
height = 17,
|
||||
scale = 0.5F
|
||||
scale = SCALE
|
||||
)
|
||||
}
|
||||
|
||||
if (label !== null) {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = label.bold(),
|
||||
x = x + 25,
|
||||
y = y + 3,
|
||||
centered = true,
|
||||
shadow = true
|
||||
)
|
||||
if (label !== null && isMouseOver(pMouseX.toDouble(), pMouseY.toDouble())) {
|
||||
context.renderTooltip(Minecraft.getInstance().font, label, pMouseX, pMouseY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun playDownSound(soundManager: SoundManager) {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
|
||||
fun toggleTab(state: Boolean = true) {
|
||||
isActive = state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks
|
||||
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.client.gui.ScrollingWidget
|
||||
import com.cobblemon.mod.common.client.gui.common.MarkIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks.MarksScrollingWidget.ScrollSlotRow
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.util.Mth
|
||||
|
||||
class MarksScrollingWidget(val pX: Int, val pY: Int, val setSelectedMark: () -> (Unit), val setHoveredMark: (Mark?) -> (Unit)): ScrollingWidget<ScrollSlotRow>(
|
||||
width = WIDTH,
|
||||
height = HEIGHT,
|
||||
left = pX,
|
||||
top = pY - HEIGHT,
|
||||
slotHeight = SLOT_SIZE + SLOT_SPACING
|
||||
) {
|
||||
companion object {
|
||||
const val WIDTH = 119
|
||||
const val HEIGHT = 98
|
||||
const val SLOT_SIZE = 16
|
||||
const val SLOT_SPACING = 3
|
||||
}
|
||||
|
||||
fun createEntries(marks: List<Mark?>) {
|
||||
marks.chunked(6).forEachIndexed { index, listChunk ->
|
||||
addEntry(ScrollSlotRow(this, listChunk, setSelectedMark, setHoveredMark))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRowLeft(): Int = if (children().size > 5) (left + 1) else left
|
||||
|
||||
override fun getScrollbarPosition(): Int = rowLeft + width - 3
|
||||
|
||||
override fun renderScrollbar(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
// Do not render scrollbar if all rows are already visible
|
||||
if (children().size > 5) {
|
||||
val xLeft = this.scrollbarPosition
|
||||
val xRight = xLeft + 3
|
||||
|
||||
val barHeight = this.bottom - this.y
|
||||
|
||||
var yBottom = ((barHeight * barHeight).toFloat() / this.maxPosition.toFloat()).toInt()
|
||||
yBottom = Mth.clamp(yBottom, 32, barHeight - 8)
|
||||
var yTop = scrollAmount.toInt() * (barHeight - yBottom) / this.maxScroll + this.y
|
||||
if (yTop < this.y) {
|
||||
yTop = this.y
|
||||
}
|
||||
|
||||
context.fill(xLeft, this.y, xRight, this.bottom, FastColor.ARGB32.color(255, 75, 75, 75)) // background
|
||||
context.fill(xLeft,yTop, xRight, yTop + yBottom, FastColor.ARGB32.color(255, 141, 141, 141)) // base
|
||||
}
|
||||
}
|
||||
|
||||
fun renderEntry(context: GuiGraphics, mouseX: Int, mouseY: Int, index: Int, x: Int, y: Int): Boolean {
|
||||
val entry = this.getEntry(index)
|
||||
entry.x = x
|
||||
entry.y = y
|
||||
return entry.renderRow( context, y, x, mouseX, mouseY)
|
||||
}
|
||||
|
||||
override fun getEntry(index: Int): ScrollSlotRow = children()[index] as ScrollSlotRow
|
||||
|
||||
override fun renderListItems(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
val rowX = rowLeft
|
||||
|
||||
var anyHovered = false
|
||||
for (index in 0 until this.itemCount) {
|
||||
val rowY = this.getRowTop(index)
|
||||
val o = this.getRowBottom(index)
|
||||
if (o >= this.y && rowY <= this.bottom) {
|
||||
if (this.renderEntry(context!!, mouseX, mouseY, index, rowX, rowY)) anyHovered = true
|
||||
}
|
||||
}
|
||||
if (!anyHovered) setHoveredMark(null)
|
||||
}
|
||||
|
||||
override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, dragX: Double, dragY: Double): Boolean {
|
||||
// Prevent scrollbar drag if all rows are already visible
|
||||
return if (children().size > 5) super.mouseDragged(mouseX, mouseY, button, dragX, dragY) else true
|
||||
}
|
||||
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
|
||||
// Prevent scroll if all rows are already visible
|
||||
return if (children().size > 5) super.mouseScrolled(mouseX, mouseY, scrollX, scrollY) else true
|
||||
}
|
||||
|
||||
class ScrollSlotRow(
|
||||
val parent: MarksScrollingWidget,
|
||||
val markList: List<Mark?>,
|
||||
val setSelectedMark : () -> Unit,
|
||||
val setHoveredMark: (Mark?) -> Unit
|
||||
): Slot<ScrollSlotRow>() {
|
||||
companion object {
|
||||
private val slotResource = cobblemonResource("textures/gui/summary/summary_mark_slot.png")
|
||||
}
|
||||
|
||||
var x: Int = 0
|
||||
var y: Int = 0
|
||||
|
||||
fun renderRow(context: GuiGraphics, y: Int, x: Int, mouseX: Int, mouseY: Int): Boolean {
|
||||
var anyHovered = false
|
||||
val horizontalSpacing = if (isScrollVisible()) SLOT_SPACING else (SLOT_SPACING + 1)
|
||||
markList.forEachIndexed { index, mark ->
|
||||
val matrices = context.pose()
|
||||
|
||||
val startPosX = x + ((horizontalSpacing + SLOT_SIZE) * index)
|
||||
val startPosY = y + SLOT_SPACING
|
||||
|
||||
val slotHovered = mark != null && getHoveredSlotIndex(mouseX, mouseY) == index
|
||||
|
||||
if (slotHovered) {
|
||||
setHoveredMark(markList[index])
|
||||
anyHovered = true
|
||||
}
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = slotResource,
|
||||
x = startPosX,
|
||||
y = startPosY,
|
||||
width = SLOT_SIZE,
|
||||
height = SLOT_SIZE,
|
||||
vOffset = if (slotHovered) SLOT_SIZE else 0,
|
||||
textureHeight = SLOT_SIZE * 2
|
||||
)
|
||||
|
||||
if (mark != null) MarkIcon(startPosX, startPosY, mark, false).render(context, mouseX, mouseY)
|
||||
}
|
||||
return anyHovered
|
||||
}
|
||||
|
||||
override fun render(
|
||||
context: GuiGraphics,
|
||||
index: Int,
|
||||
y: Int,
|
||||
x: Int,
|
||||
entryWidth: Int,
|
||||
entryHeight: Int,
|
||||
mouseX: Int,
|
||||
mouseY: Int,
|
||||
hovered: Boolean,
|
||||
tickDelta: Float
|
||||
) {}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
setSelectedMark.invoke()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isScrollVisible(): Boolean = parent.children().size > 5
|
||||
|
||||
private fun getHoveredSlotIndex(mouseX: Int, mouseY: Int): Int {
|
||||
val horizontalSpacing = if (isScrollVisible()) SLOT_SPACING else (SLOT_SPACING + 1)
|
||||
markList.forEachIndexed { index, _ ->
|
||||
val startPosX = x + ((horizontalSpacing + SLOT_SIZE) * index)
|
||||
val startPosY = y + SLOT_SPACING + 1
|
||||
|
||||
if (mouseX in startPosX..(startPosX + SLOT_SIZE)
|
||||
&& mouseY in startPosY..(startPosY + SLOT_SIZE)) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
override fun getNarration(): Component {
|
||||
if (markList.isNotEmpty()) {
|
||||
return "${markList[0]}-${markList[markList.size - 1]}".text()
|
||||
}
|
||||
return "".text()
|
||||
}
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.gui.summary.widgets.screens.marks
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendToServer
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.gui.ColourLibrary
|
||||
import com.cobblemon.mod.common.api.gui.MultiLineLabelK
|
||||
import com.cobblemon.mod.common.api.gui.blitk
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.client.gui.common.MarkIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.SoundlessWidget
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.GuiGraphics
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
class MarksWidget(
|
||||
pX: Int, pY: Int,
|
||||
val pokemon: Pokemon
|
||||
): SoundlessWidget(pX, pY, WIDTH, HEIGHT, Component.literal("MarksWidget")) {
|
||||
companion object {
|
||||
private const val WIDTH = 134
|
||||
private const val HEIGHT = 148
|
||||
const val SCALE = 0.5F
|
||||
|
||||
private val marksBaseResource = cobblemonResource("textures/gui/summary/summary_marks_base.png")
|
||||
}
|
||||
|
||||
var activeMark: Mark? = null
|
||||
var selectedMark: Mark? = null
|
||||
var hoveredMark: Mark? = null
|
||||
|
||||
val marksScrollList = MarksScrollingWidget(
|
||||
pX = pX + 9,
|
||||
pY = pY + 45,
|
||||
setSelectedMark = {
|
||||
if (hoveredMark != null) {
|
||||
selectedMark = hoveredMark
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
},
|
||||
setHoveredMark = { hoveredMark = it }
|
||||
)
|
||||
|
||||
init {
|
||||
children.clear()
|
||||
activeMark = pokemon.activeMark
|
||||
selectedMark = pokemon.activeMark
|
||||
val marksList: MutableList<Mark?> = pokemon.marks.sortedBy { it.identifier.toString() }.toMutableList()
|
||||
while ((marksList.size < 30) || (marksList.size > 30 && marksList.size % 6 != 0)) marksList.add(null)
|
||||
marksScrollList.createEntries(marksList)
|
||||
addWidget(marksScrollList)
|
||||
}
|
||||
|
||||
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
|
||||
if (selectedMark !== null && isSelectedMarkHovered(mouseX.toInt(), mouseY.toInt())) {
|
||||
selectedMark = null
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(CobblemonSounds.GUI_CLICK, 1.0F))
|
||||
}
|
||||
return super.mouseClicked(mouseX, mouseY, button)
|
||||
}
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, mouseX: Int, mouseY: Int, partialTicks: Float) {
|
||||
val matrices = context.pose()
|
||||
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = marksBaseResource,
|
||||
x = x,
|
||||
y = y,
|
||||
width = width,
|
||||
height = height
|
||||
)
|
||||
|
||||
if (selectedMark != null) {
|
||||
MarkIcon(
|
||||
x = x + 12,
|
||||
y = y + 12,
|
||||
selectedMark!!
|
||||
).render(context, mouseX, mouseY)
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.scale(SCALE, SCALE, 1F)
|
||||
MultiLineLabelK.create(
|
||||
component = selectedMark!!.getDescription(),
|
||||
width = 85 / SCALE,
|
||||
maxLines = 4
|
||||
).renderLeftAligned(
|
||||
context = context,
|
||||
x = (x + 38) / SCALE,
|
||||
y = (y + 11) / SCALE,
|
||||
ySpacing = 5 / SCALE,
|
||||
colour = ColourLibrary.WHITE,
|
||||
shadow = true
|
||||
)
|
||||
matrices.popPose()
|
||||
}
|
||||
|
||||
// Title
|
||||
(if (selectedMark?.title != null) selectedMark!!.getTitle(pokemon.getDisplayName()) else pokemon.getDisplayName())?.let {
|
||||
drawScaledText(
|
||||
context = context,
|
||||
text = it,
|
||||
x = x + (width / 2),
|
||||
y = y + 38,
|
||||
scale = SCALE,
|
||||
centered = true
|
||||
)
|
||||
}
|
||||
|
||||
marksScrollList.render(context, mouseX, mouseY, partialTicks)
|
||||
if (hoveredMark !== null && marksScrollList.isMouseOver(mouseX.toDouble(), mouseY.toDouble())) {
|
||||
context.renderTooltip(Minecraft.getInstance().font, hoveredMark!!.getName(), mouseX, mouseY)
|
||||
}
|
||||
}
|
||||
|
||||
fun isSelectedMarkHovered(mouseX: Int, mouseY: Int): Boolean {
|
||||
val markX = x + 12
|
||||
val markY = y + 12
|
||||
return mouseX in (markX..(markX + (MarkIcon.SIZE * MarkIcon.SCALE).toInt()))
|
||||
&& mouseY in (markY..(markY + (MarkIcon.SIZE * MarkIcon.SCALE).toInt()))
|
||||
}
|
||||
|
||||
fun saveActiveMarkToPokemon() {
|
||||
if (selectedMark != activeMark) sendToServer(SetActiveMarkPacket(pokemon.uuid, selectedMark))
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.client.gui.CobblemonRenderable
|
||||
import com.cobblemon.mod.common.client.gui.ExitButton
|
||||
import com.cobblemon.mod.common.client.gui.TypeIcon
|
||||
import com.cobblemon.mod.common.client.gui.summary.Summary
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.MarkingsWidget
|
||||
import com.cobblemon.mod.common.client.gui.summary.widgets.common.reformatNatureTextIfMinted
|
||||
import com.cobblemon.mod.common.client.render.drawScaledText
|
||||
import com.cobblemon.mod.common.client.render.drawScaledTextJustifiedRight
|
||||
@@ -99,6 +100,9 @@ class TradeGUI(
|
||||
private var offeredPokemonModel: ModelWidget? = null
|
||||
private var opposingOfferedPokemonModel: ModelWidget? = null
|
||||
|
||||
private lateinit var offeredPokemonMarkings: MarkingsWidget
|
||||
private lateinit var opposingOfferedPokemonMarkings: MarkingsWidget
|
||||
|
||||
var offeredPokemon: Pokemon? = null
|
||||
var opposingOfferedPokemon: Pokemon? = null
|
||||
|
||||
@@ -247,6 +251,11 @@ class TradeGUI(
|
||||
|
||||
setOfferedPokemon(pokemon = offeredPokemon, isOpposing = false)
|
||||
setOfferedPokemon(pokemon = opposingOfferedPokemon, isOpposing = true)
|
||||
|
||||
offeredPokemonMarkings = MarkingsWidget(x + 74.5, y + 21, offeredPokemon, false)
|
||||
opposingOfferedPokemonMarkings = MarkingsWidget(x + 177.5, y + 21, opposingOfferedPokemon, false)
|
||||
addRenderableWidget(offeredPokemonMarkings)
|
||||
addRenderableWidget(opposingOfferedPokemonMarkings)
|
||||
}
|
||||
|
||||
override fun render(context: GuiGraphics, mouseX: Int, mouseY: Int, delta: Float) {
|
||||
@@ -522,6 +531,7 @@ class TradeGUI(
|
||||
rotationY = 35F,
|
||||
offsetY = PORTRAIT_MODEL_OFFSET_Y
|
||||
) else null
|
||||
if (::opposingOfferedPokemonMarkings.isInitialized) opposingOfferedPokemonMarkings.setActivePokemon(opposingOfferedPokemon)
|
||||
trade.acceptedOppositeOffer = false
|
||||
} else {
|
||||
offeredPokemon = pokemon
|
||||
@@ -535,6 +545,7 @@ class TradeGUI(
|
||||
rotationY = 325F,
|
||||
offsetY = PORTRAIT_MODEL_OFFSET_Y
|
||||
) else null
|
||||
if (::offeredPokemonMarkings.isInitialized) offeredPokemonMarkings.setActivePokemon(offeredPokemon)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateOrientationPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object S2CUpdateOrientationHandler : ClientNetworkPacketHandler<ClientboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ClientboundUpdateOrientationPacket, client: Minecraft) {
|
||||
client.executeIfPossible {
|
||||
val level = client.level ?: return@executeIfPossible
|
||||
val entity = level.getEntity(packet.entityId)
|
||||
if (entity is OrientationControllable) {
|
||||
packet.active?.let {
|
||||
entity.orientationController.active = it
|
||||
if (!it) {
|
||||
entity.orientationController.reset()
|
||||
}
|
||||
}
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object ClientboundUpdateRidingStateHandler : ClientNetworkPacketHandler<ClientboundUpdateRidingStatePacket> {
|
||||
override fun handle(packet: ClientboundUpdateRidingStatePacket, client: Minecraft) {
|
||||
client.executeIfPossible {
|
||||
val player = client.player ?: return@executeIfPossible
|
||||
val entity = player.level().getEntity(packet.entity) ?: return@executeIfPossible
|
||||
if (entity !is PokemonEntity) return@executeIfPossible
|
||||
if (entity.controllingPassenger == player) return@executeIfPossible
|
||||
val buffer = packet.data ?: return@executeIfPossible
|
||||
if (entity.riding?.key != packet.behaviour) return@executeIfPossible
|
||||
entity.ridingState?.decode(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-106
@@ -11,9 +11,12 @@ package com.cobblemon.mod.common.client.render.item
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags.WEARABLE_FACE_ITEMS
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags.WEARABLE_HAT_ITEMS
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
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.PosableState
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -24,7 +27,7 @@ import net.minecraft.client.renderer.texture.OverlayTexture
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemDisplayContext
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Vector3f
|
||||
|
||||
class HeldItemRenderer {
|
||||
private val itemRenderer: ItemRenderer = Minecraft.getInstance().itemRenderer
|
||||
@@ -34,133 +37,91 @@ class HeldItemRenderer {
|
||||
const val ITEM_FACE = "item_face"
|
||||
const val ITEM_HAT = "item_hat"
|
||||
const val ITEM = "item"
|
||||
}
|
||||
|
||||
fun render(
|
||||
entity: LivingEntity?,
|
||||
model: PosableModel,
|
||||
item: ItemStack,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
seed: Int,
|
||||
rotation: Vec3
|
||||
) {
|
||||
if (item.isEmpty) return
|
||||
displayContext = ItemDisplayContext.FIXED
|
||||
|
||||
poseStack.pushPose()
|
||||
when {
|
||||
//item_face locator
|
||||
(locators.containsKey(ITEM_FACE) && item.`is`(WEARABLE_FACE_ITEMS)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM_FACE) ?: ItemDisplayContext.HEAD
|
||||
poseStack.mulPose(locators[ITEM_FACE]!!.matrix)
|
||||
poseStack.translate(0f, 0f, .28f)
|
||||
poseStack.scale(0.7f, 0.7f, 0.7f)
|
||||
}
|
||||
//item_hat locator
|
||||
(locators.containsKey(ITEM_HAT) && item.`is`(WEARABLE_HAT_ITEMS)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM_HAT) ?: ItemDisplayContext.HEAD
|
||||
poseStack.mulPose(locators[ITEM_HAT]!!.matrix)
|
||||
poseStack.translate(0f, -0.26f, 0f)
|
||||
poseStack.scale(.68f, .68f, .68f)
|
||||
}
|
||||
//item locator
|
||||
(locators.containsKey(ITEM)) -> {
|
||||
displayContext = model.getLocatorDisplayContext(ITEM) ?: ItemDisplayContext.FIXED
|
||||
poseStack.mulPose(locators[ITEM]!!.matrix)
|
||||
applyContextTransformation(poseStack, rotation)
|
||||
}
|
||||
// Don't render any item
|
||||
else -> {
|
||||
poseStack.popPose()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, seed)
|
||||
poseStack.popPose()
|
||||
}
|
||||
|
||||
private fun renderAnimationItem(
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
locators: Map<String, MatrixWrapper>,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
entity: LivingEntity?,
|
||||
rotation: Vec3
|
||||
) {
|
||||
state.itemRenderingLocations.forEach { (locatorName, item) ->
|
||||
poseStack.pushPose()
|
||||
if (locators.containsKey(locatorName)) {
|
||||
displayContext = model.getLocatorDisplayContext(locatorName)?: ItemDisplayContext.FIXED
|
||||
poseStack.mulPose(locators[locatorName]!!.matrix)
|
||||
applyContextTransformation(poseStack, rotation)
|
||||
}
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, 0)
|
||||
poseStack.popPose()
|
||||
private fun PoseStack.setOriginAndScale(x:Float,y:Float,z:Float,scale:Float=1f) {
|
||||
this.translate(x*.0625*scale, y*.0625*scale, z*.0625*scale)
|
||||
this.scale(scale, scale, scale)
|
||||
}
|
||||
}
|
||||
|
||||
fun renderOnModel(
|
||||
model: PosableModel,
|
||||
item: ItemStack,
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
rotation: Vec3 = Vec3(0.0,0.0,0.0),
|
||||
light: Int = LightTexture.pack(11, 7),
|
||||
frontLight: Boolean = false,
|
||||
entity: LivingEntity? = null
|
||||
) {
|
||||
val locators: Map<String, MatrixWrapper> = state.locatorStates
|
||||
if (state.itemRenderingLocations.isNotEmpty()) {
|
||||
renderAnimationItem(model, state, locators, poseStack, buffer, light, null, rotation)
|
||||
}
|
||||
else if (!item.`is`(CobblemonItemTags.HIDDEN_ITEMS)) {
|
||||
render(null, model, item, locators, poseStack, buffer, light, 0, rotation)
|
||||
}
|
||||
if (!item.`is`(CobblemonItemTags.HIDDEN_ITEMS)) renderAtLocator(item, model, state, entity, poseStack, buffer, light, 0, frontLight)
|
||||
state.animationItems.forEach { (targetLocator, item) -> renderAtLocator(item, model, state, entity, poseStack, buffer, light, 0, frontLight, targetLocator) }
|
||||
}
|
||||
|
||||
fun renderOnEntity(
|
||||
entity: LivingEntity,
|
||||
private fun renderAtLocator(
|
||||
item: ItemStack,
|
||||
model: PosableModel,
|
||||
state: PosableState,
|
||||
entity: LivingEntity?,
|
||||
poseStack: PoseStack,
|
||||
buffer: MultiBufferSource,
|
||||
light: Int,
|
||||
rotation: Vec3 = Vec3(0.0,0.0,0.0)
|
||||
seed: Int,
|
||||
frontLight: Boolean = false,
|
||||
targetLocator: String =
|
||||
if (item.`is`(WEARABLE_FACE_ITEMS) && state.locatorStates.containsKey(ITEM_FACE)) ITEM_FACE
|
||||
else if (item.`is`(WEARABLE_HAT_ITEMS) && state.locatorStates.containsKey(ITEM_HAT)) ITEM_HAT
|
||||
else ITEM
|
||||
) {
|
||||
val locators: Map<String, MatrixWrapper> = state.locatorStates
|
||||
if (state.itemRenderingLocations.isNotEmpty()) {
|
||||
renderAnimationItem(model, state, locators, poseStack, buffer, light, entity, rotation)
|
||||
}
|
||||
else {
|
||||
render(entity, model, item, locators, poseStack, buffer, light, 0, rotation)
|
||||
}
|
||||
}
|
||||
if (item.isEmpty) return
|
||||
|
||||
private fun applyContextTransformation(poseStack: PoseStack, rotation: Vec3) {
|
||||
when (displayContext) {
|
||||
ItemDisplayContext.FIXED -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90.0f))
|
||||
poseStack.scale(.5f, .5f, .5f )
|
||||
poseStack.translate(0f, 0.01666f, 0f)
|
||||
if (state.locatorStates.containsKey(targetLocator)) {
|
||||
poseStack.pushPose()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
|
||||
displayContext = model.getLocatorDisplayContext(targetLocator)?:
|
||||
if ((item.`is`(WEARABLE_FACE_ITEMS) && targetLocator==ITEM_FACE) || (item.`is`(WEARABLE_HAT_ITEMS) && targetLocator== ITEM_HAT)) ItemDisplayContext.HEAD
|
||||
else ItemDisplayContext.FIXED
|
||||
|
||||
poseStack.mulPose(state.locatorStates[targetLocator]!!.matrix)
|
||||
when (displayContext) {
|
||||
ItemDisplayContext.FIXED -> {
|
||||
poseStack.setOriginAndScale(0f,.5f,0f, .5f)
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90.0f))
|
||||
}
|
||||
ItemDisplayContext.THIRD_PERSON_RIGHT_HAND, ItemDisplayContext.THIRD_PERSON_LEFT_HAND -> {
|
||||
//For Minecraft player models
|
||||
if (state is NPCClientDelegate) {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(-90.0F))
|
||||
}
|
||||
//for T-Posing Models
|
||||
else if (state is PokemonClientDelegate || state is FloatingState) {
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(-90.0F))
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(90.0F))
|
||||
}
|
||||
poseStack.translate(0.025f * if (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND) 1 else -1 , 0.0f, 0.0f)
|
||||
}
|
||||
ItemDisplayContext.HEAD -> {
|
||||
if (state is NPCClientDelegate) {
|
||||
if (item.`is`(WEARABLE_FACE_ITEMS)) poseStack.setOriginAndScale(0f,-2f,7.25f, 0.62f)
|
||||
else if (item.`is`(WEARABLE_HAT_ITEMS)) poseStack.setOriginAndScale(0f,-10.25f,0f, 0.62f)
|
||||
}
|
||||
else {
|
||||
if (item.`is`(WEARABLE_FACE_ITEMS)) poseStack.setOriginAndScale(0f,1f,(7.25f)-.5f, 0.62f)
|
||||
else if (item.`is`(WEARABLE_HAT_ITEMS)) poseStack.setOriginAndScale(0f,(-7.25f)+.5f,0f, 0.62f)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
ItemDisplayContext.THIRD_PERSON_RIGHT_HAND, ItemDisplayContext.THIRD_PERSON_LEFT_HAND -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees((rotation.x).toFloat()))
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees((rotation.y).toFloat()))
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees((rotation.z).toFloat()))
|
||||
poseStack.translate(0.025f * if (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND) 1 else -1 , 0.0f, 0.0f)
|
||||
|
||||
//Render front lighting for UI Models
|
||||
if (frontLight) {
|
||||
RenderSystem.setShaderLights(Vector3f(0F,0F,1F), Vector3f(0F,0F,1F))
|
||||
}
|
||||
ItemDisplayContext.HEAD -> {
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(90.0f))
|
||||
poseStack.scale(.6f, .6f, .6f)
|
||||
poseStack.translate(0f, -0.6f, 0f)
|
||||
}
|
||||
else -> {}
|
||||
|
||||
itemRenderer.renderStatic(entity, item, displayContext, (displayContext==ItemDisplayContext.THIRD_PERSON_LEFT_HAND), poseStack, buffer, null, light, OverlayTexture.NO_OVERLAY, seed)
|
||||
|
||||
poseStack.popPose()
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -37,7 +37,6 @@ import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PokemonOnShoulderRenderer<T : Player>(renderLayerParent: RenderLayerParent<T, PlayerModel<T>>) : RenderLayer<T, PlayerModel<T>>(renderLayerParent) {
|
||||
|
||||
@@ -162,12 +161,12 @@ class PokemonOnShoulderRenderer<T : Player>(renderLayerParent: RenderLayerParent
|
||||
}
|
||||
|
||||
heldItemRenderer.renderOnModel(
|
||||
model,
|
||||
shoulderData.shownItem,
|
||||
model,
|
||||
state,
|
||||
matrixStack,
|
||||
buffer,
|
||||
Vec3(0.0,-90.0,-90.0)
|
||||
packedLight
|
||||
)
|
||||
|
||||
model.setDefault()
|
||||
|
||||
+8
-1
@@ -78,8 +78,15 @@ class JsonPose(model: PosableModel, json: JsonObject) {
|
||||
it[2].asDouble
|
||||
)
|
||||
} ?: Vec3.ZERO
|
||||
val scale = it.get("scale")?.asJsonArray?.let {
|
||||
Vec3(
|
||||
it[0].asDouble,
|
||||
it[1].asDouble,
|
||||
it[2].asDouble
|
||||
)
|
||||
} ?: Vec3(1.0,1.0,1.0)
|
||||
val isVisible = it.get("isVisible")?.asString?.asExpressionLike()
|
||||
return@map part.withPosition(position.x, position.y, position.z).withRotationDegrees(rotation.x, rotation.y, rotation.z).also { if (isVisible != null) it.withVisibility(isVisible) }
|
||||
return@map part.withPosition(position.x, position.y, position.z).withRotationDegrees(rotation.x, rotation.y, rotation.z).withScale(scale.x, scale.y, scale.z).also { if (isVisible != null) it.withVisibility(isVisible) }
|
||||
}?.toTypedArray() ?: arrayOf()
|
||||
|
||||
val idleAnimations = (json.get("animations")?.asJsonArray ?: JsonArray()).asJsonArray.mapNotNull {
|
||||
|
||||
+16
-9
@@ -11,13 +11,12 @@ package com.cobblemon.mod.common.client.render.models.blockbench
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Rollable
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.animationFunctions
|
||||
import com.cobblemon.mod.common.client.ClientMoLangFunctions.setupClient
|
||||
import com.cobblemon.mod.common.client.entity.NPCClientDelegate
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.AnimatedModelTextureSupplier
|
||||
import com.cobblemon.mod.common.client.render.ModelLayer
|
||||
@@ -57,7 +56,6 @@ import net.minecraft.client.renderer.texture.DynamicTexture
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemDisplayContext
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix4f
|
||||
@@ -94,6 +92,9 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
|
||||
open var profileScale = 1F
|
||||
|
||||
/** Used for third person riding camera */
|
||||
open var seatToCameraOffset = mutableMapOf<String, Vec3>()
|
||||
|
||||
/**
|
||||
* These are open-ended properties that can be used to store miscellaneous properties about the model.
|
||||
*
|
||||
@@ -530,7 +531,7 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
/** Puts the model back to its original location and rotations. */
|
||||
fun setDefault() {
|
||||
defaultPositions.forEach { it.set() }
|
||||
transformedParts.forEach { it.set() }
|
||||
transformedParts.forEach { it.apply() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -603,7 +604,11 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
applyPose(state, pose, 1F)
|
||||
|
||||
val primaryAnimation = state.primaryAnimation
|
||||
val shouldRotateHead = if(entity is PokemonEntity) entity.riding.shouldRotatePokemonHead(entity) else true
|
||||
val shouldRotateHead = if (entity is PokemonEntity) {
|
||||
entity.ifRidingAvailableSupply(true) { behaviour, settings, ridingState ->
|
||||
behaviour.shouldRotatePokemonHead(settings, ridingState, entity)
|
||||
}
|
||||
} else true
|
||||
|
||||
// Quirks will run if there is no primary animation running and quirks are enabled for this context.
|
||||
if (primaryAnimation == null && context.request(RenderContext.DO_QUIRKS) != false) {
|
||||
@@ -717,12 +722,14 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
var scale = 1F
|
||||
// We could improve this to be generalized for other entities. First we'd have to figure out wtf is going on, though.
|
||||
if (entity is PokemonEntity) {
|
||||
if(entity.passengers.isNotEmpty() && entity.controllingPassenger is Rollable && (entity.controllingPassenger as Rollable).orientation != null){
|
||||
val controllingPassenger = entity.controllingPassenger
|
||||
if(entity.passengers.isNotEmpty() && entity.controllingPassenger is OrientationControllable
|
||||
&& (entity.controllingPassenger as OrientationControllable).orientationController.active){
|
||||
val controllingPassenger = entity.controllingPassenger as OrientationControllable
|
||||
val controller = controllingPassenger.orientationController
|
||||
val transformationMatrix = Matrix4f()
|
||||
val center = Vector3f(0f, entity.bbHeight/2, 0f)
|
||||
transformationMatrix.translate(center)
|
||||
transformationMatrix.mul(Matrix4f((controllingPassenger as Rollable).orientation!!))
|
||||
transformationMatrix.rotate(controller.getRenderOrientation(state.getPartialTicks()))
|
||||
transformationMatrix.translate(center.negate())
|
||||
matrixStack.mulPose(transformationMatrix)
|
||||
} else {
|
||||
@@ -819,4 +826,4 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
condition = condition,
|
||||
animations = { animations(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-7
@@ -46,7 +46,6 @@ import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix4f
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
@@ -128,9 +127,8 @@ abstract class PosableState : Schedulable {
|
||||
/** This gets called 500 million times so use a mutable value for runtime */
|
||||
private val reusableAnimTime = DoubleValue(0.0)
|
||||
|
||||
val itemRenderingLocations = mutableMapOf<String, ItemStack>()
|
||||
// var itemRenderingLocation = ""
|
||||
// var animationItem : ItemStack? = null
|
||||
/** A list of items to be rendered on a PosableModel during an animation */
|
||||
val animationItems = mutableMapOf<String, ItemStack>()
|
||||
|
||||
/** All of the MoLang functions that can be applied to something with this state. */
|
||||
val functions = QueryStruct(hashMapOf())
|
||||
@@ -167,13 +165,13 @@ abstract class PosableState : Schedulable {
|
||||
val renderLocation = if (params.contains(1)) params.getString(1) else "item"
|
||||
|
||||
if (!item.isEmpty && locatorStates.containsKey(renderLocation)) {
|
||||
itemRenderingLocations.put(renderLocation, item)
|
||||
animationItems.put(renderLocation, item)
|
||||
} else {
|
||||
if (itemRenderingLocations.containsKey(renderLocation)) itemRenderingLocations.remove(renderLocation)
|
||||
if (animationItems.containsKey(renderLocation)) animationItems.remove(renderLocation)
|
||||
return@addFunction Unit
|
||||
}
|
||||
}
|
||||
.addFunction("clear_items") { itemRenderingLocations.clear() }
|
||||
.addFunction("clear_items") { animationItems.clear() }
|
||||
.addFunction("play_animation") { params ->
|
||||
val animationParameter = params.get<MoValue>(0)
|
||||
val animation = if (animationParameter is ObjectValue<*>) {
|
||||
|
||||
+2
-2
@@ -77,6 +77,6 @@ class PoseTransitionAnimation(
|
||||
it.apply(context, model, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch, newIntensity)
|
||||
}
|
||||
|
||||
return ratio < 1F
|
||||
return ratio <= 1F
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation.Companion.X_AXIS
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class EeveeModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("eevee")
|
||||
val body = getPart("body")
|
||||
override val head = getPart("head")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val foreLeftLeg= getPart("leg_front_left")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.4, -0.54, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var stand: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("eevee", "cry") }
|
||||
|
||||
val shoulderOffset = 4
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("eevee", "blink") }
|
||||
stand = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("eevee", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("eevee", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("eevee", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(X_AXIS, shoulderOffset)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("eevee", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(X_AXIS, -shoulderOffset)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
-62
@@ -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.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class FlareonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("flareon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.6, -0.45, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.36, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("flareon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("flareon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("flareon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("flareon", "faint") else null
|
||||
}
|
||||
-62
@@ -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.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class JolteonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("jolteon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.3F
|
||||
override var portraitTranslation = Vec3(-0.55, -0.6, 0.0)
|
||||
|
||||
override var profileScale = 1.0F
|
||||
override var profileTranslation = Vec3(0.0, 0.2, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("jolteon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("jolteon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("jolteon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("jolteon", "faint") else null
|
||||
}
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PidgeotModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("pidgeot")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val head = getPart("neck")
|
||||
|
||||
private val wingOpenRight = getPart("wing_open_right")
|
||||
private val wingOpenLeft = getPart("wing_open_left")
|
||||
private val wingClosedRight = getPart("wing_closed_right")
|
||||
private val wingClosedLeft = getPart("wing_closed_left")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.6, 0.15, 0.0)
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
|
||||
|
||||
// lateinit var sleep: CobblemonPose
|
||||
lateinit var stand: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var hover: CobblemonPose
|
||||
lateinit var fly: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("pidgeot", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("pidgeot", "blink")}
|
||||
val flyQuirk1 = quirk { bedrockStateful("pidgeot", "air_fly_quirk") }
|
||||
val flyQuirk2 = quirk { bedrockStateful("pidgeot", "air_fly_quirk2") }
|
||||
|
||||
// sleep = registerPose(
|
||||
// poseName = "sleeping",
|
||||
// transformedParts = arrayOf(
|
||||
// wingClosedLeft.createTransformation().withVisibility(visibility = true),
|
||||
// wingClosedRight.createTransformation().withVisibility(visibility = true),
|
||||
// wingOpenLeft.createTransformation().withVisibility(visibility = false),
|
||||
// wingOpenRight.createTransformation().withVisibility(visibility = false)
|
||||
// ),
|
||||
// poseType = PoseType.SLEEP,
|
||||
// animations = arrayOf(bedrock("pidgeot", "sleep"))
|
||||
// )
|
||||
|
||||
stand = registerPose(
|
||||
poseName = "stand",
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = true),
|
||||
wingClosedRight.createTransformation().withVisibility(visibility = true),
|
||||
wingOpenLeft.createTransformation().withVisibility(visibility = false),
|
||||
wingOpenRight.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
poseTypes = PoseType.STATIONARY_POSES - PoseType.HOVER - PoseType.FLOAT + UI_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pidgeot", "ground_idle_PLACEHOLDER"),
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = true),
|
||||
wingClosedRight.createTransformation().withVisibility(visibility = true),
|
||||
wingOpenLeft.createTransformation().withVisibility(visibility = false),
|
||||
wingOpenRight.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
poseTypes = PoseType.MOVING_POSES - PoseType.FLY - PoseType.SWIM,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pidgeot", "ground_idle_PLACEHOLDER"),
|
||||
BipedWalkAnimation(this)
|
||||
)
|
||||
)
|
||||
|
||||
hover = registerPose(
|
||||
poseName = "floating",
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = false),
|
||||
wingClosedRight.createTransformation().withVisibility(visibility = false),
|
||||
wingOpenLeft.createTransformation().withVisibility(visibility = true),
|
||||
wingOpenRight.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pidgeot", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
fly = registerPose(
|
||||
poseName = "flying",
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = false),
|
||||
wingClosedRight.createTransformation().withVisibility(visibility = false),
|
||||
wingOpenLeft.createTransformation().withVisibility(visibility = true),
|
||||
wingOpenRight.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
|
||||
quirks = arrayOf(blink, flyQuirk1, flyQuirk2),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pidgeot", "air_fly")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class VaporeonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("vaporeon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.6, -0.58, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.35, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var swimIdle: Pose
|
||||
lateinit var swimMove: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("vaporeon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES - PoseType.FLOAT,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("vaporeon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = setOf(PoseType.WALK),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("vaporeon", "ground_run")
|
||||
)
|
||||
)
|
||||
|
||||
swimIdle = registerPose(
|
||||
poseName = "float",
|
||||
poseTypes = setOf(PoseType.FLOAT),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("vaporeon", "water_idle")
|
||||
)
|
||||
)
|
||||
|
||||
swimMove = registerPose(
|
||||
poseName = "swim",
|
||||
poseTypes = setOf(PoseType.SWIM),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("vaporeon", "water_swim")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("vaporeon", "faint") else null
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class EspeonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("espeon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.15F
|
||||
override var portraitTranslation = Vec3(-0.55, -0.43, 0.0)
|
||||
|
||||
override var profileScale = 0.81F
|
||||
override var profileTranslation = Vec3(0.07, 0.59, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("espeon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("espeon", "blink")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("espeon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("espeon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("espeon", "faint") else null
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen2
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class UmbreonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("umbreon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.6, -0.45, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.35, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("umbreon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("umbreon", "blink")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("umbreon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("umbreon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("umbreon", "faint") else null
|
||||
}
|
||||
-62
@@ -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.client.render.models.blockbench.pokemon.gen3
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class NosepassModel(root: ModelPart) : PokemonPosableModel(root), BipedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("nosepass")
|
||||
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
|
||||
override var portraitScale = 1.5F
|
||||
override var portraitTranslation = Vec3(-0.1, -0.1, 0.0)
|
||||
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.65, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("nosepass", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
animations = arrayOf(
|
||||
bedrock("nosepass", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
animations = arrayOf(
|
||||
bedrock("nosepass", "ground_walk"),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(state: PosableState) = if (state.isNotPosedIn(sleep)) bedrockStateful("nosepass", "faint") else null
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen3
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.QuadrupedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class TropiusModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("tropius")
|
||||
override val head = getPart("neck")
|
||||
|
||||
override val foreLeftLeg= getPart("leg_front_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
|
||||
override var portraitScale = 1.31F
|
||||
override var portraitTranslation = Vec3(-1.23, 5.01, 0.0)
|
||||
|
||||
override var profileScale = 0.28F
|
||||
override var profileTranslation = Vec3(0.0, 1.26, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("tropius", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("tropius", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("tropius", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("tropius", "ground_idle"),
|
||||
QuadrupedWalkAnimation(this, periodMultiplier = 0.7F, amplitudeMultiplier = 0.7F)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GlaceonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("glaceon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.4F
|
||||
override var portraitTranslation = Vec3(-0.7, -0.75, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.35, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("glaceon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
// val blink = quirk { bedrockStateful("glaceon", "blink")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("glaceon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("glaceon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("glaceon", "faint") else null
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class HonchkrowModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BiWingedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("honchkrow")
|
||||
override val head = getPart("head")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftWing = getPart("wing_left")
|
||||
override val rightWing = getPart("wing_right")
|
||||
|
||||
override var portraitScale = 3.4F
|
||||
override var portraitTranslation = Vec3(-0.35, -1.2, 0.0)
|
||||
|
||||
override var profileScale = 1.2F
|
||||
override var profileTranslation = Vec3(0.0, -0.05, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
lateinit var hover: Pose
|
||||
lateinit var fly: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("honchkrow", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(
|
||||
bedrock("honchkrow", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink), animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("honchkrow", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink), animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("honchkrow", "ground_idle"),
|
||||
BipedWalkAnimation(this, amplitudeMultiplier = 0.8F, periodMultiplier = 0.7F)
|
||||
// bedrock("honchkrow", "ground_walk")
|
||||
)
|
||||
)
|
||||
hover = registerPose(
|
||||
poseName = "hover",
|
||||
poseType = PoseType.HOVER,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("honchkrow", "air_idle"),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.6F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
fly = registerPose(
|
||||
poseName = "fly",
|
||||
poseType = PoseType.FLY,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("honchkrow", "air_fly"),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -14F.toRadians(), period = 0.9F, amplitude = 0.9F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen4
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class LeafeonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("leafeon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.3F
|
||||
override var portraitTranslation = Vec3(-0.7, -0.7, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.35, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("leafeon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
// val blink = quirk { bedrockStateful("leafeon", "blink")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("leafeon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("leafeon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("leafeon", "faint") else null
|
||||
}
|
||||
-62
@@ -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.client.render.models.blockbench.pokemon.gen4
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ProbopassModel(root: ModelPart) : PokemonPosableModel(root) {
|
||||
override val rootPart = root.registerChildWithAllChildren("probopass")
|
||||
|
||||
override var portraitScale = 1F
|
||||
override var portraitTranslation = Vec3(0.0, 0.425, 0.0)
|
||||
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("probopass", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("probopass", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("probopass", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("probopass", "ground_walk"),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(state: PosableState) = if (state.isNotPosedIn(sleep)) bedrockStateful("probopass", "faint") else null
|
||||
}
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen6
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SylveonModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("sylveon")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.4F
|
||||
override var portraitTranslation = Vec3(-0.55, -0.45, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.43, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("sylveon", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("sylveon", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("sylveon", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("sylveon", "ground_run")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("sylveon", "faint") else null
|
||||
}
|
||||
+2
-2
@@ -46,7 +46,7 @@ class ModelPartTransformation(val modelPart: ModelPart) {
|
||||
var visibility: ExpressionLike? = null
|
||||
|
||||
/** Applies the transformation to the model part. */
|
||||
fun apply(state: PosableState, intensity: Float) {
|
||||
fun apply(state: PosableState? = null, intensity: Float = 1f) {
|
||||
modelPart.x += position[0] * intensity
|
||||
modelPart.y += position[1] * intensity
|
||||
modelPart.z += position[2] * intensity
|
||||
@@ -56,7 +56,7 @@ class ModelPartTransformation(val modelPart: ModelPart) {
|
||||
modelPart.xScale *= ((1 - scale[0]).absoluteValue * intensity) * (scale[0] - 1).sign + 1
|
||||
modelPart.yScale *= ((1 - scale[1]).absoluteValue * intensity) * (scale[1] - 1).sign + 1
|
||||
modelPart.zScale *= ((1 - scale[2]).absoluteValue * intensity) * (scale[2] - 1).sign + 1
|
||||
visibility?.let { modelPart.visible = state.runtime.resolveBoolean(it) }
|
||||
visibility?.let { modelPart.visible = state?.runtime?.resolveBoolean(it)?: defaultRuntime.resolveBoolean(it) }
|
||||
}
|
||||
|
||||
fun set() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user