forked from mirrors/cobblemon
Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da4e1a96a4 | ||
|
|
c4a4b9cb86 | ||
|
|
4912a89e6e | ||
|
|
f2e10d1b01 | ||
|
|
25eb197491 | ||
|
|
8de233b572 | ||
|
|
83972ca9e6 | ||
|
|
35e2190cae | ||
|
|
b966cd2db0 | ||
|
|
3e492541cc | ||
|
|
4e9541d7f5 | ||
|
|
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 | ||
|
|
f058d6e635 | ||
|
|
f9377b7489 | ||
|
|
e59b5094ad | ||
|
|
922ee95fd2 |
@@ -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,6 +11,7 @@
|
||||
- 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
|
||||
|
||||
### Changes
|
||||
@@ -75,6 +76,8 @@
|
||||
- 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.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,10 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
@@ -47,6 +49,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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;
|
||||
@@ -55,10 +58,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
@@ -80,6 +80,8 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
|
||||
@Shadow public abstract void displayClientMessage(Component message, boolean overlay);
|
||||
|
||||
@Shadow @Final private static Map<Pose, EntityDimensions> POSES;
|
||||
@Shadow @Final public static EntityDimensions STANDING_DIMENSIONS;
|
||||
@Unique private OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
@@ -108,6 +110,19 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@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 (EntityDimensions)POSES.getOrDefault(pose, STANDING_DIMENSIONS);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "removeEntitiesOnShoulder",
|
||||
at = @At(
|
||||
@@ -252,8 +267,10 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -10,10 +10,13 @@ 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.S2CUpdateOrientationPacket;
|
||||
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;
|
||||
@@ -37,28 +40,50 @@ import java.util.function.Consumer;
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow @Final private Consumer<Packet<?>> broadcast;
|
||||
@Shadow @Final private Entity entity;
|
||||
@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$sendOrientationChanges(CallbackInfo ci) {
|
||||
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;
|
||||
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());
|
||||
@@ -68,35 +93,8 @@ public abstract class ServerEntityMixin {
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, new S2CUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
OrientationController controller = controllable.getOrientationController();
|
||||
Matrix3f currOrientation = controller.getOrientation();
|
||||
|
||||
if(currOrientation != cobblemon$lastSentOrientation) {
|
||||
cobblemon$lastSentOrientation = new Matrix3f(currOrientation);
|
||||
|
||||
//this.broadcast.accept(new S2CUpdateOrientationPacket(currOrientation,this.entity.getId()))
|
||||
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
Long2ObjectMap<ChunkMap.TrackedEntity> entityMap = ((ChunkMapAccessor) chunkMap).getEntityMap();
|
||||
TrackedEntity trackedEntity = entityMap.get(entity.getId());
|
||||
if (trackedEntity == null) return;
|
||||
Set<ServerPlayerConnection> seenBy = ((TrackedEntityAccessor) trackedEntity).getSeenBy();
|
||||
for (ServerPlayerConnection conn : seenBy) {
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (player == entity) continue; // optional safety filter
|
||||
CobblemonNetwork.sendPacketToPlayer(player, new S2CUpdateOrientationPacket(orientation, entity.getId()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ public abstract class ServerPlayerMixin {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
@@ -41,4 +43,4 @@ public abstract class ServerPlayerMixin {
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,19 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
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.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
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.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
@@ -22,6 +32,7 @@ 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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@@ -35,6 +46,12 @@ public abstract class CameraMixin {
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
@Shadow private Vec3 position;
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@@ -77,6 +94,49 @@ public abstract class CameraMixin {
|
||||
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){
|
||||
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);
|
||||
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()));
|
||||
|
||||
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;
|
||||
float currEyeHeight = Mth.lerp(instance.getPartialTickTime(), eyeHeightOld, eyeHeight);
|
||||
var controller = rollable.getOrientationController();
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight, 0f)));
|
||||
|
||||
var position = locatorOffset.add(entityPos).add(rotatedEyeHeight);
|
||||
setPosition(position);
|
||||
} else {
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
|
||||
@@ -11,10 +11,9 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket;
|
||||
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.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -34,14 +33,14 @@ public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
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 C2SUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
// @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) {
|
||||
@@ -49,7 +48,7 @@ public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
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 C2SUpdateOrientationPacket(controller.getOrientation()));
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -65,7 +64,9 @@ public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.getRiding().shouldRoll(pokemonEntity);
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -182,8 +182,9 @@ public class MouseHandlerMixin {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return Vec3.ZERO;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
return pokemonEntity.getRiding().angRollVel(pokemonEntity, player, deltaTime);
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.angRollVel(settings, state, pokemonEntity, player, deltaTime);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -192,20 +193,23 @@ public class MouseHandlerMixin {
|
||||
if (player == null) return Vec3.ZERO;
|
||||
var vehicle = player.getVehicle();
|
||||
if (vehicle == null) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemon)) return Vec3.ZERO;
|
||||
if (!(vehicle instanceof PokemonEntity pokemonEntity)) return Vec3.ZERO;
|
||||
|
||||
var sensitivity = cobblemon$getRidingSensitivity();
|
||||
|
||||
return pokemon.getRiding().rotationOnMouseXY(
|
||||
pokemon,
|
||||
player,
|
||||
mouseY,
|
||||
mouseX,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
return pokemonEntity.ifRidingAvailableSupply(Vec3.ZERO, (behaviour, settings, state) -> {
|
||||
return behaviour.rotationOnMouseXY(
|
||||
settings,
|
||||
state,
|
||||
pokemonEntity,
|
||||
player,
|
||||
mouseY,
|
||||
mouseX,
|
||||
yMouseSmoother,
|
||||
xMouseSmoother,
|
||||
sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Unique
|
||||
@@ -222,8 +226,9 @@ public class MouseHandlerMixin {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return true;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return true;
|
||||
|
||||
return pokemonEntity.getRiding().useAngVelSmoothing(pokemonEntity);
|
||||
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,7 @@ 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))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,6 +35,7 @@ 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
|
||||
@@ -74,7 +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.S2CUpdateOrientationPacket
|
||||
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
|
||||
@@ -144,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
|
||||
@@ -153,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
|
||||
@@ -195,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
|
||||
@@ -267,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()))
|
||||
@@ -359,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))
|
||||
@@ -390,7 +405,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(S2CUpdateOrientationPacket.ID, S2CUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
@@ -418,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
|
||||
}
|
||||
|
||||
@@ -426,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))
|
||||
@@ -513,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
|
||||
}
|
||||
|
||||
+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,6 +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.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
@@ -71,12 +61,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
|
||||
@@ -85,11 +71,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 +80,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 +92,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 +218,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)
|
||||
@@ -469,6 +467,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 +739,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 +779,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 +1467,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
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+39
@@ -1,10 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.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
|
||||
|
||||
@@ -21,6 +31,9 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
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
|
||||
|
||||
@@ -37,6 +50,8 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
|
||||
fun reset() {
|
||||
orientation = null
|
||||
renderOrientationO = null
|
||||
renderOrientation = null
|
||||
active = false
|
||||
}
|
||||
|
||||
@@ -46,6 +61,30 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
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)
|
||||
|
||||
|
||||
@@ -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,210 +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.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.withQueryValue
|
||||
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
|
||||
|
||||
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
|
||||
controller.tick(entity, driver, input)
|
||||
if (!entity.level().isClientSide) {
|
||||
val pose = controller.pose(entity)
|
||||
entity.entityData.set(PokemonEntity.POSE_TYPE, pose)
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
+536
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* 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.1 })
|
||||
|
||||
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.altitudeExpr)
|
||||
|
||||
//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.topSpeedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glideTopSpeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelExpr)
|
||||
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
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
lerp( newVelocity.z,0.0, topSpeed / ( 20.0 * 30.0))
|
||||
)
|
||||
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.topSpeedExpr)
|
||||
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.topSpeedExpr)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseX * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseY * 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.topSpeedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glideTopSpeedExpr)
|
||||
|
||||
//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
|
||||
|
||||
//max y level for the ride
|
||||
var altitudeExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
private set
|
||||
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
private set
|
||||
|
||||
var glideTopSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 3 seconds. The conversion in the function below is to convert seconds to ticks
|
||||
var accelExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
private set
|
||||
|
||||
//Seconds self propelled flight (glide is not self propelled in this case)
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(altitudeExpr)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(glideTopSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
altitudeExpr = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
glideTopSpeedExpr = buffer.readExpression()
|
||||
accelExpr = 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()
|
||||
}
|
||||
}
|
||||
+161
-78
@@ -6,18 +6,21 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.riding.controllers
|
||||
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.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseProvider
|
||||
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
|
||||
@@ -28,25 +31,24 @@ import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
/**
|
||||
* Allows for flight like a bird controller, except you don't have to do any "flapping" motion,
|
||||
* you can just go up and down like creative
|
||||
*
|
||||
* @author Apion, Jackowes
|
||||
* @since January 1, 2025
|
||||
*/
|
||||
class HelicopterAirController : RideController {
|
||||
override val key = KEY
|
||||
override val poseProvider = PoseProvider(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { it.entityData.get(PokemonEntity.MOVING) })
|
||||
class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, NoState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/helicopter")
|
||||
val ROTATION_LIMIT = 30.0f
|
||||
}
|
||||
|
||||
//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
|
||||
override val condition: (PokemonEntity) -> Boolean = { entity ->
|
||||
Shapes.create(entity.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (it.y.toDouble() == (entity.position().y)) {
|
||||
val blockState = entity.level().getBlockState(it.below())
|
||||
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
|
||||
@@ -54,33 +56,38 @@ class HelicopterAirController : RideController {
|
||||
}
|
||||
}
|
||||
|
||||
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 pose(settings: HelicopterSettings, state: NoState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
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(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
override fun rotation(
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
val runtime = getRuntime(entity)
|
||||
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(verticalVelocity)
|
||||
else if (driver.isShiftKeyDown) -runtime.resolveDouble(verticalVelocity)
|
||||
var yVel = if (driver.jumping) runtime.resolveDouble(settings.verticalVelocity)
|
||||
else if (driver.isShiftKeyDown) -runtime.resolveDouble(settings.verticalVelocity)
|
||||
else (0.0)
|
||||
|
||||
yVel *= 0.25
|
||||
@@ -98,9 +105,13 @@ class HelicopterAirController : RideController {
|
||||
return Vec3(xVel, yVel, zVel)
|
||||
}
|
||||
|
||||
|
||||
override fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
|
||||
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
|
||||
@@ -149,35 +160,15 @@ class HelicopterAirController : RideController {
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(entity: PokemonEntity): Boolean = true
|
||||
|
||||
|
||||
override fun inertia(entity: PokemonEntity): Double = 0.1
|
||||
|
||||
override fun canJump(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun shouldRoll(entity: PokemonEntity): Boolean = true
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
settings: HelicopterSettings,
|
||||
state: NoState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
@@ -186,18 +177,116 @@ class HelicopterAirController : RideController {
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
val invertYaw = if (Cobblemon.config.invertYaw) -1 else 1
|
||||
//yaw, pitch, roll
|
||||
return Vec3(xMouse * invertYaw, 0.0, 0.0)
|
||||
return Vec3(mouseX * invertYaw, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double {
|
||||
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
|
||||
}
|
||||
|
||||
//Need to ensure that crouching lowers altitude and doesn't eject the player
|
||||
override fun dismountOnShift(entity: PokemonEntity): Boolean = false
|
||||
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) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(horizontalAcceleration)
|
||||
buffer.writeExpression(verticalVelocity)
|
||||
@@ -210,10 +299,4 @@ class HelicopterAirController : RideController {
|
||||
verticalVelocity = buffer.readExpression()
|
||||
speed = buffer.readExpression()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/helicopter")
|
||||
val ROTATION_LIMIT = 30.0f
|
||||
}
|
||||
}
|
||||
+449
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* 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.topSpeedExpr)
|
||||
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.topSpeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelExpr)
|
||||
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.topSpeedExpr)
|
||||
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 handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 25.0, 8.0)".asExpression()
|
||||
private set
|
||||
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.5, 1.0)".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', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
// Between 60 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
gravity = buffer.readExpression()
|
||||
minSpeed = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = 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
|
||||
}
|
||||
-152
@@ -1,152 +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.OrientationControllable
|
||||
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
|
||||
|
||||
fun tick(entity: PokemonEntity, driver: Player, input: Vec3) {}
|
||||
|
||||
/**
|
||||
* 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) {}
|
||||
|
||||
/**
|
||||
* 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 defauit
|
||||
//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 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, 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) {
|
||||
|
||||
+2
-2
@@ -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)
|
||||
}
|
||||
|
||||
+15
@@ -12,6 +12,7 @@ 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.api.entity.PokemonSideDelegate
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
@@ -31,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
|
||||
@@ -99,6 +101,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")
|
||||
@@ -372,6 +375,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() {
|
||||
|
||||
@@ -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)))
|
||||
}
|
||||
@@ -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,6 +122,7 @@ 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 var mainScreenIndex = INFO
|
||||
@@ -155,6 +156,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(
|
||||
@@ -215,28 +223,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 +255,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 +321,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()
|
||||
@@ -325,9 +333,9 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
modelWidget.heldItem = if (selectedPokemon.heldItemVisible) selectedPokemon.heldItem else null
|
||||
}
|
||||
|
||||
if (this::nicknameEntryWidget.isInitialized) {
|
||||
this.nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
|
||||
}
|
||||
if (::nicknameEntryWidget.isInitialized) nicknameEntryWidget.setSelectedPokemon(selectedPokemon)
|
||||
|
||||
if (::markingsWidget.isInitialized) markingsWidget.setActivePokemon(selectedPokemon)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,6 +349,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 +366,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 +408,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 +465,8 @@ class Summary private constructor(party: Collection<Pokemon?>, private val edita
|
||||
}
|
||||
|
||||
EVOLVE -> {
|
||||
saveActiveMark()
|
||||
saveMarkings()
|
||||
sideScreen = EvolutionSelectScreen(
|
||||
x + 216,
|
||||
y + 23,
|
||||
@@ -651,7 +680,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) }
|
||||
}
|
||||
}
|
||||
+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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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(listChunk, setSelectedMark, setHoveredMark))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getScrollbarPosition(): Int = pX + 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, 47, 47, 47)) // background
|
||||
context.fill(xLeft,yTop, xRight, yTop + yBottom, FastColor.ARGB32.color(255, 198, 198, 198)) // 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 = this.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 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
|
||||
markList.forEachIndexed { index, mark ->
|
||||
val matrices = context.pose()
|
||||
|
||||
val startPosX = x + ((SLOT_SPACING + 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 getHoveredSlotIndex(mouseX: Int, mouseY: Int): Int {
|
||||
markList.forEachIndexed { index, _ ->
|
||||
val startPosX = x + ((SLOT_SPACING + 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 + 10,
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.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.S2CUpdateOrientationPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object S2CUpdateOrientationHandler : ClientNetworkPacketHandler<S2CUpdateOrientationPacket> {
|
||||
override fun handle(packet: S2CUpdateOrientationPacket, client: Minecraft) {
|
||||
val level = client.level ?: return
|
||||
val entity = level.getEntity(packet.entityId)
|
||||
if (entity is OrientationControllable) {
|
||||
entity.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
packet.active?.let {
|
||||
entity.orientationController.active = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-4
@@ -40,6 +40,7 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.plus
|
||||
import com.cobblemon.mod.common.util.toRGBA
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
@@ -48,7 +49,9 @@ import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.player.RemotePlayer
|
||||
import net.minecraft.client.renderer.MultiBufferSource
|
||||
import net.minecraft.client.renderer.RenderStateShard
|
||||
import net.minecraft.client.renderer.RenderType
|
||||
@@ -602,7 +605,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 +724,13 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
// 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 OrientationControllable
|
||||
&& (entity.controllingPassenger as OrientationControllable).orientationController.orientation != null){
|
||||
val controllingPassenger = entity.controllingPassenger
|
||||
&& (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 OrientationControllable).orientationController.orientation!!))
|
||||
transformationMatrix.rotate(controller.getRenderOrientation(state.getPartialTicks()))
|
||||
transformationMatrix.translate(center.negate())
|
||||
matrixStack.mulPose(transformationMatrix)
|
||||
} else {
|
||||
|
||||
+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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -14,10 +14,12 @@ import com.cobblemon.mod.common.api.riding.Rideable
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animation.BedrockAnimationRepository
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.math.Axis
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.player.AbstractClientPlayer
|
||||
import net.minecraft.client.player.RemotePlayer
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
@@ -34,8 +36,6 @@ object MountedPlayerRenderer {
|
||||
if(player.vehicle !is Rideable) return
|
||||
val matrix = stack.last().pose()
|
||||
|
||||
val vehicle = player.vehicle as Rideable?
|
||||
val entity = vehicle!!.riding.entity
|
||||
val seatIndex = entity.passengers.indexOf(player)
|
||||
val seat = entity.seats[seatIndex]
|
||||
val delegate = entity.delegate as PokemonClientDelegate
|
||||
@@ -49,6 +49,10 @@ object MountedPlayerRenderer {
|
||||
val locatorOffsetToCenter = locatorOffset.sub(center, Vector3f())
|
||||
|
||||
val transformationMatrix = Matrix4f()
|
||||
//if (player is Rollable && player.shouldRoll()){
|
||||
//transformationMatrix.rotate(Axis.YP.rotationDegrees(-yBodyRot))
|
||||
//transformationMatrix.mulLocal(player.orientation)
|
||||
//}
|
||||
|
||||
val rotatedOffset = transformationMatrix.transformPosition(locatorOffsetToCenter, Vector3f()).add(center).sub(Vector3f(0f, player.bbHeight/2, 0f))
|
||||
matrix.translate(rotatedOffset)
|
||||
@@ -70,21 +74,17 @@ object MountedPlayerRenderer {
|
||||
}
|
||||
|
||||
//Rotates player
|
||||
val controller = (player as? OrientationControllable)?.orientationController ?: return
|
||||
if (controller.active && !disableRollableRenderDebug) {
|
||||
if (player is OrientationControllable && player.orientationController.active && !disableRollableRenderDebug) {
|
||||
val center = Vector3f(0f, player.bbHeight / 2, 0f)
|
||||
val transformationMatrix = Matrix4f()
|
||||
transformationMatrix.translate(center)
|
||||
|
||||
val orientation = controller.orientation ?: Matrix3f()
|
||||
transformationMatrix.mul(Matrix4f(orientation))
|
||||
|
||||
transformationMatrix.rotate(player.orientationController.getRenderOrientation(partialTicks))
|
||||
transformationMatrix.translate(center.negate(Vector3f()))
|
||||
//Pre-Undo Yaw
|
||||
transformationMatrix.rotate(Axis.YP.rotationDegrees(yBodyRot+180f))
|
||||
matrix.mul(transformationMatrix)
|
||||
}
|
||||
matrix.translate(0f, 0.5f, 0f)
|
||||
matrix.translate(0f, 0.25f, 0f)
|
||||
}
|
||||
|
||||
fun animate(
|
||||
|
||||
+3
-3
@@ -45,6 +45,7 @@ import com.mojang.math.Axis
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.gui.Font.DisplayMode
|
||||
import net.minecraft.client.player.RemotePlayer
|
||||
import net.minecraft.client.renderer.*
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer
|
||||
@@ -190,8 +191,7 @@ class PokemonRenderer(
|
||||
//Move origin to center of Pokemon
|
||||
transformationMatrix.translate(center)
|
||||
|
||||
val orientation = controller.orientation ?: Matrix3f()
|
||||
transformationMatrix.mul(Matrix4f(orientation))
|
||||
transformationMatrix.rotate(controller.getRenderOrientation(partialTicks))
|
||||
//Move origin to base of the entity
|
||||
transformationMatrix.translate(center.negate(Vector3f()))
|
||||
|
||||
@@ -453,7 +453,7 @@ class PokemonRenderer(
|
||||
private fun resolveBaseLabel(entity: PokemonEntity): MutableComponent {
|
||||
return when {
|
||||
!ServerSettings.displayEntityNameLabel -> Component.empty()
|
||||
Cobblemon.config.displayNameForUnknownPokemon || CobblemonClient.clientPokedexData.getKnowledgeForSpecies(entity.pokemon.species.resourceIdentifier) != PokedexEntryProgress.NONE -> entity.name.copy()
|
||||
Cobblemon.config.displayNameForUnknownPokemon || CobblemonClient.clientPokedexData.getKnowledgeForSpecies(entity.pokemon.species.resourceIdentifier) != PokedexEntryProgress.NONE -> entity.getTitledName()
|
||||
else -> Component.literal(HIDDEN_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.command
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.util.commandLang
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.cobblemon.mod.common.util.player
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object MarkGiveAllCommand {
|
||||
|
||||
private const val NAME = "giveallmarks"
|
||||
private const val PLAYER = "player"
|
||||
private const val SLOT = "slot"
|
||||
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
val command = Commands.literal(NAME)
|
||||
.permission(CobblemonPermissions.CHANGE_MARK)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.player())
|
||||
.then(Commands.argument(SLOT, PartySlotArgumentType.partySlot())
|
||||
.executes { execute(it, it.player()) }
|
||||
))
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>, player: ServerPlayer) : Int {
|
||||
val pokemon = PartySlotArgumentType.getPokemonOf(context, SLOT, player)
|
||||
|
||||
pokemon.marks = Marks.all().toMutableSet()
|
||||
|
||||
val givenMessage = commandLang(NAME, player.name, pokemon.getDisplayName())
|
||||
context.source.sendSuccess({ givenMessage }, true)
|
||||
|
||||
if (context.source.player?.equals(player) != true) {
|
||||
player.sendSystemMessage(givenMessage)
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.command.argument.MarkArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.util.commandLang
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.cobblemon.mod.common.util.player
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object MarkGiveCommand {
|
||||
|
||||
private const val NAME = "givemark"
|
||||
private const val PLAYER = "player"
|
||||
private const val SLOT = "slot"
|
||||
private const val MARK = "mark"
|
||||
private val ALREADY_HAS_EXCEPTION = Dynamic3CommandExceptionType { a, b, c -> commandLang("$NAME.already_has", a, b, c).red() }
|
||||
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
val command = Commands.literal(NAME)
|
||||
.permission(CobblemonPermissions.CHANGE_MARK)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.player())
|
||||
.then(Commands.argument(SLOT, PartySlotArgumentType.partySlot())
|
||||
.then(Commands.argument(MARK, MarkArgumentType.mark())
|
||||
.executes { execute(it, it.player()) }
|
||||
))
|
||||
)
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>, player: ServerPlayer) : Int {
|
||||
val pokemon = PartySlotArgumentType.getPokemonOf(context, SLOT, player)
|
||||
val mark = MarkArgumentType.getMark(context, MARK)
|
||||
|
||||
if (pokemon.marks.contains(mark)) {
|
||||
throw ALREADY_HAS_EXCEPTION.create(player.name, pokemon.getDisplayName(), mark.getName())
|
||||
}
|
||||
|
||||
pokemon.exchangeMark(mark, true)
|
||||
|
||||
val givenMessage = commandLang(NAME, player.name, pokemon.getDisplayName(), mark.getName())
|
||||
context.source.sendSuccess({ givenMessage }, true)
|
||||
|
||||
if (context.source.player?.equals(player) != true) {
|
||||
player.sendSystemMessage(givenMessage)
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.command
|
||||
|
||||
import com.cobblemon.mod.common.api.permission.CobblemonPermissions
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.command.argument.MarkArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.util.commandLang
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.cobblemon.mod.common.util.player
|
||||
import com.mojang.brigadier.Command
|
||||
import com.mojang.brigadier.CommandDispatcher
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType
|
||||
import net.minecraft.commands.CommandSourceStack
|
||||
import net.minecraft.commands.Commands
|
||||
import net.minecraft.commands.arguments.EntityArgument
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object MarkTakeCommand {
|
||||
|
||||
private const val NAME = "takemark"
|
||||
private const val PLAYER = "player"
|
||||
private const val SLOT = "slot"
|
||||
private const val MARK = "mark"
|
||||
private val ALREADY_HAS_EXCEPTION = Dynamic3CommandExceptionType { a, b, c -> commandLang("$NAME.does_not_have", a, b, c).red() }
|
||||
|
||||
fun register(dispatcher : CommandDispatcher<CommandSourceStack>) {
|
||||
val command = Commands.literal(NAME)
|
||||
.permission(CobblemonPermissions.CHANGE_MARK)
|
||||
.then(Commands.argument(PLAYER, EntityArgument.player())
|
||||
.then(Commands.argument(SLOT, PartySlotArgumentType.partySlot())
|
||||
.then(Commands.argument(MARK, MarkArgumentType.mark())
|
||||
.executes { execute(it, it.player()) }
|
||||
))
|
||||
)
|
||||
dispatcher.register(command)
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>, player: ServerPlayer) : Int {
|
||||
val pokemon = PartySlotArgumentType.getPokemonOf(context, SLOT, player)
|
||||
val mark = MarkArgumentType.getMark(context, MARK)
|
||||
|
||||
if (!pokemon.marks.contains(mark)) {
|
||||
throw ALREADY_HAS_EXCEPTION.create(player.name, pokemon.getDisplayName(), mark.getName())
|
||||
}
|
||||
|
||||
pokemon.exchangeMark(mark, false)
|
||||
|
||||
val takenMessage = commandLang(NAME, mark.getName(), player.name, pokemon.getDisplayName())
|
||||
context.source.sendSuccess({ takenMessage }, true)
|
||||
|
||||
if (context.source.player?.equals(player) != true) {
|
||||
player.sendSystemMessage(takenMessage)
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.command.argument
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.brigadier.StringReader
|
||||
import com.mojang.brigadier.arguments.ArgumentType
|
||||
import com.mojang.brigadier.context.CommandContext
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType
|
||||
import com.mojang.brigadier.suggestion.Suggestions
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder
|
||||
import net.minecraft.commands.SharedSuggestionProvider
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class MarkArgumentType: ArgumentType<Mark> {
|
||||
|
||||
override fun parse(reader: StringReader): Mark {
|
||||
try {
|
||||
return reader.asIdentifierDefaultingNamespace().let { Marks.getByIdentifier(it) } ?: throw Exception()
|
||||
} catch (e: Exception) {
|
||||
throw SimpleCommandExceptionType(INVALID_MARK).createWithContext(reader)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <S : Any> listSuggestions(
|
||||
context: CommandContext<S>,
|
||||
builder: SuggestionsBuilder
|
||||
): CompletableFuture<Suggestions> {
|
||||
return SharedSuggestionProvider.suggest(Marks.identifiers(), builder)
|
||||
}
|
||||
|
||||
override fun getExamples() = EXAMPLES
|
||||
|
||||
companion object {
|
||||
|
||||
val EXAMPLES: List<String> = listOf("cobblemon:ribbon_event")
|
||||
val INVALID_MARK: MutableComponent = Component.translatable("cobblemon.command.mark.invalid")
|
||||
|
||||
fun mark() = MarkArgumentType()
|
||||
|
||||
fun <S> getMark(context: CommandContext<S>, name: String): Mark {
|
||||
return context.getArgument(name, Mark::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import com.cobblemon.mod.common.api.fishing.FishingBaits
|
||||
import com.cobblemon.mod.common.api.fishing.PokeRods
|
||||
import com.cobblemon.mod.common.api.fossil.Fossils
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
@@ -96,6 +97,7 @@ object CobblemonDataProvider : DataProvider {
|
||||
this.register(CobblemonCosmeticItems)
|
||||
this.register(CobblemonFlows)
|
||||
this.register(CobblemonUnlockableWallpapers)
|
||||
this.register(Marks)
|
||||
|
||||
CobblemonSpawnPools.load()
|
||||
this.register(PokeRods)
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.*
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
@@ -20,11 +22,13 @@ import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveEvent
|
||||
import com.cobblemon.mod.common.api.events.entity.PokemonEntitySaveToWorldEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.ShoulderMountEvent
|
||||
import com.cobblemon.mod.common.api.interaction.PokemonEntityInteraction
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addLivingEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonEntityFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.net.serializers.PlatformTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
@@ -37,6 +41,8 @@ import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.*
|
||||
import com.cobblemon.mod.common.api.riding.events.SelectDriverEvent
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -98,6 +104,7 @@ import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.NbtUtils
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.chat.contents.PlainTextContents
|
||||
import net.minecraft.network.protocol.Packet
|
||||
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket
|
||||
@@ -138,7 +145,6 @@ import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
@@ -153,6 +159,7 @@ open class PokemonEntity(
|
||||
@JvmStatic val SPECIES = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.STRING)
|
||||
@JvmStatic val NICKNAME = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.COMPONENT)
|
||||
@JvmStatic val NICKNAME_VISIBLE = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
@JvmStatic val MARK = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.STRING)
|
||||
@JvmStatic val SHOULD_RENDER_NAME = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
@JvmStatic val MOVING = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BOOLEAN)
|
||||
@JvmStatic val BEHAVIOUR_FLAGS = SynchedEntityData.defineId(PokemonEntity::class.java, EntityDataSerializers.BYTE)
|
||||
@@ -199,6 +206,7 @@ open class PokemonEntity(
|
||||
value.isClient = this.level().isClientSide
|
||||
field = value
|
||||
delegate.changePokemon(value)
|
||||
refreshRiding()
|
||||
|
||||
//This used to be referring to this.updateEyeHeight, I think this is the best conversion
|
||||
// We need to update this value every time the Pokémon changes, other eye height related things will be dynamic.
|
||||
@@ -244,7 +252,43 @@ open class PokemonEntity(
|
||||
|
||||
var enablePoseTypeRecalculation = true
|
||||
|
||||
override val riding: RidingManager = RidingManager(this)
|
||||
// override var ridingController: RideController? = null
|
||||
|
||||
var previousRidingState: RidingBehaviourState? = null
|
||||
var ridingState: RidingBehaviourState? = null
|
||||
var ridingBehaviourSettings: RidingBehaviourSettings? = null
|
||||
override var riding: RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>? = null
|
||||
|
||||
val runtime: MoLangRuntime by lazy {
|
||||
MoLangRuntime()
|
||||
.setup()
|
||||
.withQueryValue("entity", struct)
|
||||
.also {
|
||||
it.environment.query.addFunction("passenger_count") { DoubleValue(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 = rideProp.calculate(rideStat, rideStyle, 0) / 100.0f
|
||||
val trueStatVal = (normalizedStat * (maxVal - minVal)) + minVal
|
||||
|
||||
DoubleValue(trueStatVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshRiding() {
|
||||
riding = null
|
||||
ridingState = null
|
||||
ridingBehaviourSettings = null
|
||||
if (pokemon.riding.behaviour == null) return
|
||||
|
||||
riding = RidingBehaviours.get(pokemon.riding.behaviour!!.key) as RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>?
|
||||
ridingState = riding!!.createDefaultState()
|
||||
ridingBehaviourSettings = pokemon.riding.behaviour!!
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of steps this entity has traveled.
|
||||
@@ -260,11 +304,15 @@ open class PokemonEntity(
|
||||
*/
|
||||
var beamMode: Int
|
||||
get() = entityData.get(BEAM_MODE).toInt()
|
||||
set(value) { entityData.set(BEAM_MODE, value.toByte()) }
|
||||
set(value) {
|
||||
entityData.set(BEAM_MODE, value.toByte())
|
||||
}
|
||||
|
||||
var phasingTargetId: Int
|
||||
get() = entityData.get(PHASING_TARGET_ID)
|
||||
set(value) { entityData.set(PHASING_TARGET_ID, value) }
|
||||
set(value) {
|
||||
entityData.set(PHASING_TARGET_ID, value)
|
||||
}
|
||||
|
||||
/** The [SpawnCause] that created it, if this was the result of the [BestSpawner]. Note: This will be wiped by chunk-unload. */
|
||||
var spawnCause: SpawnCause? = null
|
||||
@@ -287,14 +335,17 @@ open class PokemonEntity(
|
||||
val exposedForm: FormData get() = this.effects.mockEffect?.exposedForm ?: this.pokemon.form
|
||||
|
||||
/** The aspects exposed to the client */
|
||||
val exposedAspects: Set<String> get() = this.effects.mockEffect?.exposedForm?.aspects?.toSet() ?: this.pokemon.aspects
|
||||
val exposedAspects: Set<String>
|
||||
get() = this.effects.mockEffect?.exposedForm?.aspects?.toSet() ?: this.pokemon.aspects
|
||||
|
||||
/** The pokeball exposed to the client. Used for sendout animation. */
|
||||
val exposedBall: PokeBall get() = this.effects.mockEffect?.exposedBall ?: this.pokemon.caughtBall
|
||||
|
||||
var platform : PlatformType
|
||||
var platform: PlatformType
|
||||
get() = entityData.get(PLATFORM_TYPE)
|
||||
set(value) { entityData.set(PLATFORM_TYPE, value) }
|
||||
set(value) {
|
||||
entityData.set(PLATFORM_TYPE, value)
|
||||
}
|
||||
|
||||
override val struct: ObjectValue<PokemonEntity> = ObjectValue(this).also {
|
||||
it.addStandardFunctions()
|
||||
@@ -314,6 +365,7 @@ open class PokemonEntity(
|
||||
delegate.changePokemon(pokemon)
|
||||
refreshDimensions()
|
||||
addPosableFunctions(struct)
|
||||
refreshRiding()
|
||||
}
|
||||
|
||||
override fun defineSynchedData(builder: SynchedEntityData.Builder) {
|
||||
@@ -321,6 +373,7 @@ open class PokemonEntity(
|
||||
builder.define(SPECIES, "")
|
||||
builder.define(NICKNAME, Component.empty())
|
||||
builder.define(NICKNAME_VISIBLE, true)
|
||||
builder.define(MARK, "")
|
||||
builder.define(SHOULD_RENDER_NAME, true)
|
||||
builder.define(MOVING, false)
|
||||
builder.define(BEHAVIOUR_FLAGS, 0)
|
||||
@@ -409,7 +462,12 @@ open class PokemonEntity(
|
||||
super.sendDebugPackets()
|
||||
DebugPackets.sendEntityBrain(this)
|
||||
DebugPackets.sendGoalSelector(level(), this, this.goalSelector)
|
||||
DebugPackets.sendPathFindingPacket(level(), this, this.navigation.path, this.navigation.path?.distToTarget ?: 0F)
|
||||
DebugPackets.sendPathFindingPacket(
|
||||
level(),
|
||||
this,
|
||||
this.navigation.path,
|
||||
this.navigation.path?.distToTarget ?: 0F
|
||||
)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
@@ -437,10 +495,11 @@ open class PokemonEntity(
|
||||
// This can't be done in the BattleMovementGoal as the sleep goal will override it.
|
||||
// Clients also don't seem to have correct info about behavior
|
||||
if (!level().isClientSide && ticksLived > 5 && platform == PlatformType.NONE
|
||||
&& ownerUUID != null
|
||||
&& isInWater && !isUnderWater
|
||||
&& !exposedForm.behaviour.moving.swim.canBreatheUnderwater && !exposedForm.behaviour.moving.swim.canWalkOnWater
|
||||
&& !getBehaviourFlag(PokemonBehaviourFlag.FLYING)) {
|
||||
&& ownerUUID != null
|
||||
&& isInWater && !isUnderWater
|
||||
&& !exposedForm.behaviour.moving.swim.canBreatheUnderwater && !exposedForm.behaviour.moving.swim.canWalkOnWater
|
||||
&& !getBehaviourFlag(PokemonBehaviourFlag.FLYING)
|
||||
) {
|
||||
platform = PlatformType.getPlatformTypeForPokemon((exposedForm))
|
||||
}
|
||||
} else {
|
||||
@@ -493,6 +552,7 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
previousRidingState = ridingState?.copy()
|
||||
schedulingTracker.update(1 / 20F)
|
||||
}
|
||||
|
||||
@@ -706,6 +766,7 @@ open class PokemonEntity(
|
||||
// init SynchedEntityData
|
||||
entityData.set(SPECIES, effects.mockEffect?.mock?.species ?: pokemon.species.resourceIdentifier.toString())
|
||||
entityData.set(NICKNAME, pokemon.nickname ?: Component.empty())
|
||||
entityData.set(MARK, pokemon.activeMark?.identifier.toString())
|
||||
entityData.set(LABEL_LEVEL, pokemon.level)
|
||||
entityData.set(POSE_TYPE, PoseType.valueOf(nbt.getString(DataKeys.POKEMON_POSE_TYPE)))
|
||||
entityData.set(BEHAVIOUR_FLAGS, nbt.getByte(DataKeys.POKEMON_BEHAVIOUR_FLAGS))
|
||||
@@ -765,7 +826,7 @@ open class PokemonEntity(
|
||||
goalSelector.addGoal(0, PokemonInBattleMovementGoal(this, 10))
|
||||
goalSelector.addGoal(0, object : Goal() {
|
||||
override fun canUse() =
|
||||
this@PokemonEntity.entityData.get(PHASING_TARGET_ID) != -1 ||
|
||||
this@PokemonEntity.entityData.get(PHASING_TARGET_ID) != -1 ||
|
||||
pokemon.status?.status == Statuses.SLEEP ||
|
||||
entityData.get(DYING_EFFECTS_STARTED) ||
|
||||
evolutionEntity != null
|
||||
@@ -880,7 +941,8 @@ open class PokemonEntity(
|
||||
}
|
||||
return InteractionResult.sidedSuccess(level().isClientSide)
|
||||
} else {
|
||||
val mushroomStew = ItemUtils.createFilledResult(itemStack, player, Items.MUSHROOM_STEW.defaultInstance)
|
||||
val mushroomStew =
|
||||
ItemUtils.createFilledResult(itemStack, player, Items.MUSHROOM_STEW.defaultInstance)
|
||||
player.setItemInHand(hand, mushroomStew)
|
||||
return InteractionResult.sidedSuccess(level().isClientSide)
|
||||
}
|
||||
@@ -949,7 +1011,11 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
if (hand == InteractionHand.MAIN_HAND && player is ServerPlayer && pokemon.getOwnerPlayer() == player) {
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(player.level().registryAccess(), pokemon, itemStack)
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
player.level().registryAccess(),
|
||||
pokemon,
|
||||
itemStack
|
||||
)
|
||||
if (player.isShiftKeyDown) {
|
||||
InteractPokemonUIPacket(
|
||||
this.getUUID(),
|
||||
@@ -1168,11 +1234,27 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
val text = when {
|
||||
isCosmetic && giving.isEmpty -> lang("cosmetic_item.take", returned.hoverName, this.pokemon.getDisplayName())
|
||||
isCosmetic && returned.isEmpty -> lang("cosmetic_item.give", this.pokemon.getDisplayName(), giving.hoverName)
|
||||
isCosmetic && giving.isEmpty -> lang(
|
||||
"cosmetic_item.take",
|
||||
returned.hoverName,
|
||||
this.pokemon.getDisplayName()
|
||||
)
|
||||
|
||||
isCosmetic && returned.isEmpty -> lang(
|
||||
"cosmetic_item.give",
|
||||
this.pokemon.getDisplayName(),
|
||||
giving.hoverName
|
||||
)
|
||||
|
||||
!isCosmetic && giving.isEmpty -> lang("held_item.take", returned.hoverName, this.pokemon.getDisplayName())
|
||||
!isCosmetic && returned.isEmpty -> lang("held_item.give", this.pokemon.getDisplayName(), giving.hoverName)
|
||||
isCosmetic -> lang("cosmetic_item.replace", returned.hoverName, this.pokemon.getDisplayName(), returned.hoverName)
|
||||
isCosmetic -> lang(
|
||||
"cosmetic_item.replace",
|
||||
returned.hoverName,
|
||||
this.pokemon.getDisplayName(),
|
||||
returned.hoverName
|
||||
)
|
||||
|
||||
else -> lang("held_item.replace", returned.hoverName, this.pokemon.getDisplayName(), returned.hoverName)
|
||||
}
|
||||
|
||||
@@ -1189,11 +1271,11 @@ open class PokemonEntity(
|
||||
|
||||
fun isBlacklisted(stack: ItemStack): Boolean =
|
||||
BuiltInRegistries.ITEM.getTagOrEmpty(CobblemonItemTags.BLACKLISTED_ITEMS_TO_HOLD).any()
|
||||
&& stack.`is`(CobblemonItemTags.BLACKLISTED_ITEMS_TO_HOLD)
|
||||
&& stack.`is`(CobblemonItemTags.BLACKLISTED_ITEMS_TO_HOLD)
|
||||
|
||||
fun isWhitelisted(stack: ItemStack): Boolean =
|
||||
BuiltInRegistries.ITEM.getTagOrEmpty(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD).none()
|
||||
|| stack.`is`(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD)
|
||||
|| stack.`is`(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD)
|
||||
|
||||
fun tryMountingShoulder(player: ServerPlayer): Boolean {
|
||||
if (this.pokemon.belongsTo(player) && this.hasRoomToMount(player)) {
|
||||
@@ -1244,9 +1326,9 @@ open class PokemonEntity(
|
||||
|
||||
player.shoulderEntityLeft.isPokemonEntity() && player.shoulderEntityLeft.getCompound(DataKeys.POKEMON)
|
||||
.getUUID(DataKeys.POKEMON_UUID) == this.pokemon.uuid -> {
|
||||
isLeft = true
|
||||
player.shoulderEntityLeft.copy()
|
||||
}
|
||||
isLeft = true
|
||||
player.shoulderEntityLeft.copy()
|
||||
}
|
||||
|
||||
else -> return true
|
||||
}
|
||||
@@ -1255,7 +1337,10 @@ open class PokemonEntity(
|
||||
nbt.putString(DataKeys.SHOULDER_FORM, this.pokemon.form.name)
|
||||
nbt.put(DataKeys.SHOULDER_ASPECTS, this.pokemon.aspects.map(StringTag::valueOf).toNbtList())
|
||||
nbt.putFloat(DataKeys.SHOULDER_SCALE_MODIFIER, this.pokemon.scaleModifier)
|
||||
nbt.put(DataKeys.SHOULDER_ITEM, this.level().registryAccess().let { if (this.shownItem.isEmpty) CompoundTag() else this.shownItem.saveOptional(it) } as CompoundTag)
|
||||
nbt.put(
|
||||
DataKeys.SHOULDER_ITEM,
|
||||
this.level().registryAccess()
|
||||
.let { if (this.shownItem.isEmpty) CompoundTag() else this.shownItem.saveOptional(it) } as CompoundTag)
|
||||
if (isLeft) player.shoulderEntityLeft = nbt else player.shoulderEntityRight = nbt
|
||||
return true
|
||||
}
|
||||
@@ -1264,7 +1349,7 @@ open class PokemonEntity(
|
||||
* Adjusts a given sent out position based on the local environment.
|
||||
* Returns the new position and a PlatformType if the pokemon should be placed on one.
|
||||
*/
|
||||
fun getAjustedSendoutPosition(pos: Vec3) : Vec3 {
|
||||
fun getAjustedSendoutPosition(pos: Vec3): Vec3 {
|
||||
var platform = PlatformType.NONE
|
||||
var blockPos = BlockPos(pos.x.toInt(), pos.y.toInt(), pos.z.toInt())
|
||||
var blockLookCount = 5
|
||||
@@ -1289,7 +1374,13 @@ open class PokemonEntity(
|
||||
testPos = testPos.above()
|
||||
}
|
||||
if (foundSurface) {
|
||||
val hasHeadRoom = !collidesWithBlock(Vec3(blockPos.x.toDouble(), (blockPos.y).toDouble(), (blockPos.z).toDouble()))
|
||||
val hasHeadRoom = !collidesWithBlock(
|
||||
Vec3(
|
||||
blockPos.x.toDouble(),
|
||||
(blockPos.y).toDouble(),
|
||||
(blockPos.z).toDouble()
|
||||
)
|
||||
)
|
||||
if (hasHeadRoom) {
|
||||
result = Vec3(result.x, testPos.y.toDouble(), result.z)
|
||||
}
|
||||
@@ -1300,7 +1391,7 @@ open class PokemonEntity(
|
||||
} else if (this.level().isEmptyBlock(blockPos)) {
|
||||
// look downward for a water surface
|
||||
blockLookCount = 64 // Higher because the pokemon can fall down to water below
|
||||
var testPos = BlockPos(pos.x.toInt(), pos.y.toInt(), pos.z.toInt())
|
||||
var testPos = BlockPos(pos.x.toInt(), pos.y.toInt(), pos.z.toInt())
|
||||
for (i in 0..blockLookCount) {
|
||||
// Try to find a surface...
|
||||
val blockState = this.level().getBlockState(testPos)
|
||||
@@ -1317,7 +1408,8 @@ open class PokemonEntity(
|
||||
if (foundSurface) {
|
||||
val canFly = form.behaviour.moving.fly.canFly
|
||||
if (canFly) {
|
||||
val hasHeadRoom = !collidesWithBlock(Vec3(blockPos.x.toDouble(), (result.y + 1), (blockPos.z).toDouble()))
|
||||
val hasHeadRoom =
|
||||
!collidesWithBlock(Vec3(blockPos.x.toDouble(), (result.y + 1), (blockPos.z).toDouble()))
|
||||
if (hasHeadRoom) {
|
||||
result = Vec3(result.x, result.y + 1.0, result.z)
|
||||
}
|
||||
@@ -1326,13 +1418,22 @@ open class PokemonEntity(
|
||||
val halfHeight = getDimensions(this.pose).height / 2.0
|
||||
for (i in 1..halfHeight.toInt()) {
|
||||
blockPos = blockPos.below()
|
||||
if (!this.level().isWaterAt(blockPos) || !this.level().getBlockState(blockPos).getCollisionShape(this.level(), blockPos).isEmpty) {
|
||||
if (!this.level().isWaterAt(blockPos) || !this.level().getBlockState(blockPos)
|
||||
.getCollisionShape(this.level(), blockPos).isEmpty
|
||||
) {
|
||||
break
|
||||
}
|
||||
}
|
||||
result = Vec3(result.x, result.y + halfHeight - halfHeight.toInt(), result.z)
|
||||
} else {
|
||||
platform = if (form.behaviour.moving.swim.canWalkOnWater || collidesWithBlock(Vec3(result.x, result.y, result.z))) PlatformType.NONE else PlatformType.getPlatformTypeForPokemon(form)
|
||||
platform = if (form.behaviour.moving.swim.canWalkOnWater || collidesWithBlock(
|
||||
Vec3(
|
||||
result.x,
|
||||
result.y,
|
||||
result.z
|
||||
)
|
||||
)
|
||||
) PlatformType.NONE else PlatformType.getPlatformTypeForPokemon(form)
|
||||
}
|
||||
}
|
||||
this.platform = platform
|
||||
@@ -1340,7 +1441,7 @@ open class PokemonEntity(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun Entity.collidesWithBlock(pos: Vec3) : Boolean {
|
||||
private fun Entity.collidesWithBlock(pos: Vec3): Boolean {
|
||||
return level().getBlockCollisions(this, boundingBox.move(pos)).iterator().hasNext()
|
||||
}
|
||||
|
||||
@@ -1374,9 +1475,10 @@ open class PokemonEntity(
|
||||
fun cry() {
|
||||
if (this.isSilent) return
|
||||
val pkt = PlayPosableAnimationPacket(id, setOf("cry"), emptyList())
|
||||
level().getEntitiesOfClass(ServerPlayer::class.java, AABB.ofSize(position(), 64.0, 64.0, 64.0)) { true }.forEach {
|
||||
it.sendPacket(pkt)
|
||||
}
|
||||
level().getEntitiesOfClass(ServerPlayer::class.java, AABB.ofSize(position(), 64.0, 64.0, 64.0)) { true }
|
||||
.forEach {
|
||||
it.sendPacket(pkt)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dropAllDeathLoot(world: ServerLevel, source: DamageSource) {
|
||||
@@ -1393,8 +1495,9 @@ open class PokemonEntity(
|
||||
(isAlwaysExperienceDropper ||
|
||||
lastHurtByPlayerTime > 0 &&
|
||||
shouldDropExperience() &&
|
||||
level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_LOOT
|
||||
))
|
||||
level().gameRules.getBoolean(
|
||||
CobblemonGameRules.DO_POKEMON_LOOT
|
||||
))
|
||||
) {
|
||||
ExperienceOrb.award(level() as ServerLevel, position(), baseExperienceReward)
|
||||
}
|
||||
@@ -1417,16 +1520,28 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleRelativeFrictionAndCalculateMovement(deltaMovement: Vec3 , friction: Float ): Vec3 {
|
||||
override fun handleRelativeFrictionAndCalculateMovement(deltaMovement: Vec3, friction: Float): Vec3 {
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
if (riders.isEmpty()) {
|
||||
if (riders.isEmpty() || this.controllingPassenger == null) {
|
||||
super.handleRelativeFrictionAndCalculateMovement(deltaMovement, friction)
|
||||
} else {
|
||||
val velocity = ifRidingAvailableSupply(fallback = Vec3.ZERO) { behaviour, settings, state ->
|
||||
behaviour.velocity(settings, state, this, this.controllingPassenger as Player, deltaMovement)
|
||||
}
|
||||
//Handle ridden pokemon differently to allow vector lerp instead of simple addition.
|
||||
val v = Entity.getInputVector(riding.velocity(this, this.controllingPassenger as Player, Vec3.ZERO), 1.0f, this.getYRot());
|
||||
val v = Entity.getInputVector(velocity, 1.0f, this.getYRot());
|
||||
//changing this will give the ride more or less inertia/handling/drift
|
||||
this.deltaMovement = this.deltaMovement.lerp(v, riding.inertia(this));
|
||||
this.move(MoverType.SELF, this.deltaMovement.scale(this.speed.toDouble()))
|
||||
val inertia = ifRidingAvailableSupply(fallback = 0.5) { behaviour, settings, state ->
|
||||
behaviour.inertia(settings, state,this)
|
||||
}
|
||||
|
||||
// TODO: jackowes look over this so I don't accidentally break anything
|
||||
this.deltaMovement = this.deltaMovement.lerp(v, inertia)
|
||||
var pos = this.deltaMovement.scale(this.speed.toDouble())
|
||||
if (super.onGround() && this.deltaMovement.y == 0.0) {
|
||||
pos = pos.subtract(0.0, 0.0001, 0.0)
|
||||
}
|
||||
this.move(MoverType.SELF, pos)
|
||||
}
|
||||
|
||||
return this.deltaMovement
|
||||
@@ -1493,7 +1608,8 @@ open class PokemonEntity(
|
||||
|
||||
fun isFlying() = this.getBehaviourFlag(PokemonBehaviourFlag.FLYING)
|
||||
|
||||
fun isFalling() = this.fallDistance > 0 && this.level().getBlockState(this.blockPosition().below()).isAir && !this.isFlying()
|
||||
fun isFalling() =
|
||||
this.fallDistance > 0 && this.level().getBlockState(this.blockPosition().below()).isAir && !this.isFlying()
|
||||
|
||||
fun couldStopFlying() = isFlying() && !behaviour.moving.walk.avoidsLand && behaviour.moving.walk.canWalk
|
||||
|
||||
@@ -1518,6 +1634,17 @@ open class PokemonEntity(
|
||||
?: pokemon.getDisplayName()
|
||||
}
|
||||
|
||||
/**
|
||||
* If this Pokémon has an active mark that has an applicable title, then the name with the title is returned.
|
||||
* Otherwise, [getName] is returned
|
||||
*
|
||||
* @return The current display name with title of this entity.
|
||||
*/
|
||||
fun getTitledName(): MutableComponent {
|
||||
val mark = entityData.get(MARK).let { Marks.getByIdentifier(it.asResource()) } ?: pokemon.activeMark
|
||||
return mark?.getTitle(getName().copy()) ?: getName().copy()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the custom name of this entity, in the context of Cobblemon it is the [Pokemon.nickname].
|
||||
*
|
||||
@@ -1541,7 +1668,8 @@ open class PokemonEntity(
|
||||
*
|
||||
* @return If the backing [pokemon] has a non-null [Pokemon.nickname].
|
||||
*/
|
||||
override fun hasCustomName(): Boolean = pokemon.nickname != null && pokemon.nickname?.contents != PlainTextContents.EMPTY
|
||||
override fun hasCustomName(): Boolean =
|
||||
pokemon.nickname != null && pokemon.nickname?.contents != PlainTextContents.EMPTY
|
||||
|
||||
/**
|
||||
* This method toggles the visibility of the entity name,
|
||||
@@ -1661,7 +1789,7 @@ open class PokemonEntity(
|
||||
|
||||
override fun setLeashedTo(entity: Entity, bl: Boolean) {
|
||||
super.setLeashedTo(entity, bl)
|
||||
if (this.ownerUUID != null && this.ownerUUID != entity.uuid ) {
|
||||
if (this.ownerUUID != null && this.ownerUUID != entity.uuid) {
|
||||
dropLeash(true, true)
|
||||
}
|
||||
}
|
||||
@@ -1682,9 +1810,9 @@ open class PokemonEntity(
|
||||
|
||||
// Takes in a requested stat type with a base minimum and base maximum and returns the interpolated
|
||||
// stat based on the boost of that pokemons stat
|
||||
fun getRideStat(stat: RidingStat, style: RidingStyle, baseMin: Double, baseMax: Double ): Double {
|
||||
fun getRideStat(stat: RidingStat, style: RidingStyle, baseMin: Double, baseMax: Double): Double {
|
||||
//TODO: Change from static zero boost once aprijuice is implemented.
|
||||
val stat = this.rideProp.calculate(stat, style, 0 )
|
||||
val stat = this.rideProp.calculate(stat, style, 0)
|
||||
val statVal = (((baseMax - baseMin) / 100) * stat) + baseMin
|
||||
return statVal
|
||||
}
|
||||
@@ -1698,24 +1826,47 @@ open class PokemonEntity(
|
||||
jumping = value
|
||||
}
|
||||
|
||||
fun ifRidingAvailable(block: (RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>, RidingBehaviourSettings, RidingBehaviourState) -> Unit) {
|
||||
if (riding == null || ridingBehaviourSettings == null || ridingState == null) return
|
||||
block(riding!!, ridingBehaviourSettings!!, ridingState!!)
|
||||
}
|
||||
|
||||
fun <T> ifRidingAvailableSupply(
|
||||
fallback: T,
|
||||
block: (RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>, RidingBehaviourSettings, RidingBehaviourState) -> T
|
||||
): T {
|
||||
var result = fallback
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
result = block(behaviour, settings, state)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun tickRidden(driver: Player, movementInput: Vec3) {
|
||||
super.tickRidden(driver, movementInput)
|
||||
this.riding.tick(this, driver, movementInput)
|
||||
val rotation = this.getControlledRotation(driver)
|
||||
setRot(rotation.y, rotation.x)
|
||||
this.yHeadRot = this.yRot
|
||||
this.yBodyRot = this.yRot
|
||||
this.yRotO = this.yRot
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.tick(settings, state, this, driver, movementInput)
|
||||
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
if (!this.level().isClientSide) {
|
||||
val pose = behaviour.pose(settings, state, this)
|
||||
if (pose != this.entityData.get(POSE_TYPE)) {
|
||||
entityData.set(POSE_TYPE, pose)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.riding.canJump(this, driver)) {
|
||||
if (this.onGround()) {
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
setRot(rotation.y, rotation.x)
|
||||
this.yHeadRot = this.yRot
|
||||
this.yBodyRot = this.yRot
|
||||
this.yRotO = this.yRot
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
|
||||
if (behaviour.isActive(settings, state, this) && behaviour.canJump(settings, state, this, driver)) {
|
||||
if (this.jumpInputStrength > 0) {
|
||||
//this.jump(this.jumpStrength, movementInput)
|
||||
//this.jump()
|
||||
val f = PI.toFloat() - this.yRot * PI.toFloat() / 180
|
||||
val jumpVector = riding.jumpVelocity(this, driver, this.jumpInputStrength)
|
||||
val jumpVector = behaviour.jumpForce(settings, state, this, driver, this.jumpInputStrength)
|
||||
val velocity = jumpVector.yRot(f)
|
||||
// Rotate the jump vector f degrees around the Y axis
|
||||
//val velocity = Vec3d(-sin(f) * jumpVector.x, jumpVector.y, cos(f) * jumpVector.z)
|
||||
@@ -1767,12 +1918,11 @@ open class PokemonEntity(
|
||||
//// this.velocityDirty = true
|
||||
// }
|
||||
|
||||
private fun getControlledRotation(controller: LivingEntity): Vec2 {
|
||||
return this.riding.controlledRotation(this, controller as Player)
|
||||
}
|
||||
|
||||
override fun onPassengerTurned(entityToUpdate: Entity) {
|
||||
return this.riding.clampPassengerRotation(this, entityToUpdate as? LivingEntity ?: return)
|
||||
if (entityToUpdate !is LivingEntity) return
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.clampPassengerRotation(settings, state, this, entityToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
override fun positionRider(passenger: Entity, positionUpdater: MoveFunction) {
|
||||
@@ -1780,16 +1930,24 @@ open class PokemonEntity(
|
||||
val index = this.passengers.indexOf(passenger).takeIf { it >= 0 && it < this.seats.size } ?: return
|
||||
val seat = this.seats[index]
|
||||
val seatOffset = seat.getOffset(this.getCurrentPoseType()).toVector3f()
|
||||
val center = Vector3f(0f, this.bbHeight/2, 0f)
|
||||
val center = Vector3f(0f, this.bbHeight / 2, 0f)
|
||||
|
||||
val seatToCenter = center.sub(seatOffset, Vector3f())
|
||||
val matrix = (this.passengers.first() as? OrientationControllable)?.orientationController?.orientation ?: Matrix3f().rotate((180f-passenger.yRot).toRadians(), Vector3f(0f, 1f, 0f))
|
||||
val rotatedOffset = matrix.transform(seatToCenter, Vector3f()).add(center).sub(Vector3f(0f, passenger.bbHeight/2, 0f))
|
||||
val matrix = (this.passengers.first() as? OrientationControllable)?.orientationController?.orientation
|
||||
?: Matrix3f().rotate((180f - passenger.yRot).toRadians(), Vector3f(0f, 1f, 0f))
|
||||
val rotatedOffset =
|
||||
matrix.transform(seatToCenter, Vector3f()).add(center).sub(Vector3f(0f, passenger.bbHeight / 2, 0f))
|
||||
|
||||
positionUpdater.accept(passenger, this.x + rotatedOffset.x, this.y + rotatedOffset.y, this.z + rotatedOffset.z)
|
||||
positionUpdater.accept(
|
||||
passenger,
|
||||
this.x + rotatedOffset.x,
|
||||
this.y + rotatedOffset.y,
|
||||
this.z + rotatedOffset.z
|
||||
)
|
||||
if (passenger is LivingEntity) {
|
||||
this.riding.updatePassengerRotation(this, passenger)
|
||||
this.riding.clampPassengerRotation(this, passenger)
|
||||
ifRidingAvailable { behaviour, settings, state ->
|
||||
behaviour.updatePassengerRotation(settings, state,this, passenger)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1797,7 +1955,7 @@ open class PokemonEntity(
|
||||
override fun getControllingPassenger(): LivingEntity? {
|
||||
val riders = this.passengers.filterIsInstance<LivingEntity>()
|
||||
if (riders.isEmpty()) {
|
||||
riding.states.clear()
|
||||
ridingState?.reset()
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -1818,16 +1976,22 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun getRiddenInput(controller: Player, movementInput: Vec3): Vec3 {
|
||||
return this.riding.velocity(this, controller, movementInput)
|
||||
return ifRidingAvailableSupply(fallback = Vec3.ZERO) { behaviour, settings, state ->
|
||||
behaviour.velocity(settings, state, this, controller, movementInput)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRiddenSpeed(controller: Player): Float {
|
||||
return this.riding.speed(this, controller)
|
||||
return ifRidingAvailableSupply(fallback = 0.05f) { behaviour, settings, state ->
|
||||
behaviour.speed(settings, state,this, controller)
|
||||
}
|
||||
}
|
||||
|
||||
fun useRidingAltPose(): Boolean {
|
||||
val driver = this.controllingPassenger as? Player ?: return false
|
||||
return this.riding.useRidingAltPose(this, driver)
|
||||
return ifRidingAvailableSupply(fallback = false) { behaviour, settings, state ->
|
||||
behaviour.useRidingAltPose(settings, state, this, driver)
|
||||
}
|
||||
}
|
||||
|
||||
var jumpInputStrength: Int = 0 // move this
|
||||
@@ -1880,7 +2044,7 @@ open class PokemonEntity(
|
||||
//Change this so it calls something from the controller to check
|
||||
//if the specific controller wants to ignore fluid physics since
|
||||
//not every single one will want to
|
||||
fluidAffected = false
|
||||
fluidAffected = false
|
||||
}
|
||||
|
||||
return fluidAffected
|
||||
@@ -1892,14 +2056,15 @@ open class PokemonEntity(
|
||||
//flying or swimming but they are touching the ground and this needs to be prevented.
|
||||
//Having it be able to be turned off by the flying or swimming controllers is the
|
||||
//temp solution I have found.
|
||||
override fun onGround() : Boolean {
|
||||
if (riding.turnOffOnGround(this)) {
|
||||
return false
|
||||
override fun onGround(): Boolean {
|
||||
val result = ifRidingAvailableSupply(fallback = null) { behaviour, settings, state ->
|
||||
behaviour.turnOffOnGround(settings, state, this)
|
||||
}
|
||||
if (result != null && result) return false
|
||||
return super.onGround()
|
||||
}
|
||||
|
||||
//I think already mentioned but should maybe be riding controller configurable
|
||||
//I think already mentioned but should maybe be riding controller configurable
|
||||
override fun dismountsUnderwater(): Boolean {
|
||||
return false
|
||||
}
|
||||
@@ -1909,17 +2074,23 @@ open class PokemonEntity(
|
||||
if (this.passengers.isEmpty()) {
|
||||
return regularGravity
|
||||
}
|
||||
return riding.gravity(this, regularGravity) ?: regularGravity
|
||||
return ifRidingAvailableSupply(fallback = regularGravity) { behaviour, settings, state ->
|
||||
behaviour.gravity(settings, state, this, regularGravity)
|
||||
}
|
||||
}
|
||||
|
||||
fun setRideBar(): Float {
|
||||
val driver = this.controllingPassenger as? Player ?: return 0.0f
|
||||
return this.riding.setRideBar(this, driver)
|
||||
return ifRidingAvailableSupply(fallback = 0.0f) { behaviour, settings, state ->
|
||||
behaviour.setRideBar(settings, state, this, driver)
|
||||
}
|
||||
}
|
||||
|
||||
fun rideFovMult(): Float {
|
||||
val driver = this.controllingPassenger as? Player ?: return 1.0f
|
||||
return this.riding.rideFovMult(this, driver)
|
||||
return ifRidingAvailableSupply(fallback = 1.0f) { behaviour, settings, state ->
|
||||
behaviour.rideFovMultiplier(settings, state, this, driver)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+7
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.entity.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSender
|
||||
import com.cobblemon.mod.common.api.entity.PokemonSideDelegate
|
||||
@@ -18,6 +19,7 @@ import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.activestate.ActivePokemonState
|
||||
import com.cobblemon.mod.common.pokemon.activestate.SentOutState
|
||||
@@ -25,6 +27,7 @@ import com.cobblemon.mod.common.util.getIsSubmerged
|
||||
import com.cobblemon.mod.common.util.playSoundServer
|
||||
import com.cobblemon.mod.common.util.update
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.syncher.EntityDataAccessor
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -104,6 +107,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
fun updateTrackedValues() {
|
||||
val trackedSpecies = mock?.species ?: entity.pokemon.species.resourceIdentifier.toString()
|
||||
val trackedNickname = mock?.nickname ?: entity.pokemon.nickname ?: Component.empty()
|
||||
val trackedMark = entity.pokemon.activeMark?.identifier.toString()
|
||||
val trackedAspects = mock?.aspects ?: entity.pokemon.aspects
|
||||
val trackedBall = mock?.pokeball ?: entity.pokemon.caughtBall.name.toString()
|
||||
|
||||
@@ -112,6 +116,9 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
if (entity.entityData.get(PokemonEntity.NICKNAME) != trackedNickname) {
|
||||
entity.entityData.set(PokemonEntity.NICKNAME, trackedNickname)
|
||||
}
|
||||
if (entity.entityData.get(PokemonEntity.MARK) !=trackedMark) {
|
||||
entity.entityData.set(PokemonEntity.MARK, trackedMark)
|
||||
}
|
||||
entity.entityData.set(PokemonEntity.ASPECTS, trackedAspects)
|
||||
entity.entityData.set(PokemonEntity.LABEL_LEVEL, entity.pokemon.level)
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.events
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.CobblemonFlows
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
|
||||
@@ -20,6 +22,7 @@ import com.cobblemon.mod.common.util.cobblemonResource
|
||||
object FlowHandler {
|
||||
fun setup() {
|
||||
CobblemonEvents.POKEMON_CAPTURED.subscribe { CobblemonFlows.run(cobblemonResource("pokemon_captured"), it.context) }
|
||||
CobblemonEvents.POKEMON_ENTITY_SPAWN.subscribe { CobblemonFlows.run(cobblemonResource("pokemon_entity_spawn"), mutableMapOf<String, MoValue>("pokemon_entity" to it.entity.asMoLangValue())) }
|
||||
CobblemonEvents.BATTLE_VICTORY.subscribe { CobblemonFlows.run(cobblemonResource("battle_victory"), it.context) }
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.subscribe { CobblemonFlows.run(cobblemonResource("pokedex_data_changed_pre"), it.getContext(), it.functions) }
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.subscribe { CobblemonFlows.run(cobblemonResource("pokedex_data_changed_post"), it.getContext()) }
|
||||
@@ -40,6 +43,8 @@ object FlowHandler {
|
||||
CobblemonEvents.EVOLUTION_TESTED.subscribe { CobblemonFlows.run(cobblemonResource("evolution_tested"), it.context, it.functions) }
|
||||
CobblemonEvents.EVOLUTION_ACCEPTED.subscribe { CobblemonFlows.run(cobblemonResource("evolution_accepted"), it.context, it.functions) }
|
||||
CobblemonEvents.EVOLUTION_COMPLETE.subscribe { CobblemonFlows.run(cobblemonResource("evolution_completed"), it.context) }
|
||||
CobblemonEvents.FOSSIL_REVIVED.subscribe { CobblemonFlows.run(cobblemonResource("fossil_revived"), it.context) }
|
||||
CobblemonEvents.BOBBER_SPAWN_POKEMON_POST.subscribe { CobblemonFlows.run(cobblemonResource("bobber_spawn_pokemon_post"), it.context) }
|
||||
CobblemonEvents.WALLPAPER_UNLOCKED_EVENT.subscribe { CobblemonFlows.run(cobblemonResource("wallpaper_unlocked"), it.context, it.functions) }
|
||||
|
||||
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe(priority = Priority.LOW) { CobblemonFlows.run(cobblemonResource("player_logged_in"), it.context) }
|
||||
@@ -54,5 +59,3 @@ object FlowHandler {
|
||||
PlatformEvents.PLAYER_DEATH.subscribe { CobblemonFlows.run(cobblemonResource("player_died"), it.context) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+33
@@ -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.net.messages.client.data
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarkRegistrySyncPacket(marks: List<Mark>) : DataRegistrySyncPacket<Mark, MarkRegistrySyncPacket>(marks) {
|
||||
companion object {
|
||||
val ID = cobblemonResource("marks")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = MarkRegistrySyncPacket(emptyList()).apply { decodeBuffer(buffer) }
|
||||
}
|
||||
|
||||
|
||||
override val id = ID
|
||||
override fun encodeEntry(buffer: RegistryFriendlyByteBuf, entry: Mark) {
|
||||
entry.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decodeEntry(buffer: RegistryFriendlyByteBuf): Mark = Mark.decode(buffer)
|
||||
|
||||
override fun synchronizeDecoded(entries: Collection<Mark>) {
|
||||
Marks.reload(entries.associateBy { it.identifier })
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -23,7 +23,7 @@ import org.joml.Matrix3f
|
||||
* @since March 30th, 2025
|
||||
*/
|
||||
|
||||
class S2CUpdateOrientationPacket internal constructor(val orientation: Matrix3f?, val active: Boolean?, val entityId: Int) : NetworkPacket<S2CUpdateOrientationPacket> {
|
||||
class ClientboundUpdateOrientationPacket internal constructor(val orientation: Matrix3f?, val active: Boolean?, val entityId: Int) : NetworkPacket<ClientboundUpdateOrientationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeVarInt(entityId)
|
||||
@@ -36,12 +36,12 @@ class S2CUpdateOrientationPacket internal constructor(val orientation: Matrix3f?
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("s2c_update_orientation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): S2CUpdateOrientationPacket {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ClientboundUpdateOrientationPacket {
|
||||
val entityId = buffer.readVarInt()
|
||||
val valid = buffer.readBoolean()
|
||||
val orientation = if (valid) buffer.readMatrix3f() else null
|
||||
val active = if (valid) buffer.readBoolean() else null
|
||||
return S2CUpdateOrientationPacket(orientation, active, entityId)
|
||||
return ClientboundUpdateOrientationPacket(orientation, active, entityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class ActiveMarkUpdatePacket(pokemon: () -> Pokemon, value: Mark?): SingleUpdatePacket<Mark?, ActiveMarkUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(this.value) { _, v -> buffer.writeIdentifier(v.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: Mark?) {
|
||||
pokemon.activeMark = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("active_mark_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ActiveMarkUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val markIdentifier = buffer.readNullable { buffer.readIdentifier() }
|
||||
val mark = if (markIdentifier == null) null else Marks.getByIdentifier(markIdentifier)
|
||||
return ActiveMarkUpdatePacket(pokemon, mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -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.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class ClientboundUpdateRidingStatePacket(
|
||||
val entity: Int,
|
||||
val behaviour: ResourceLocation,
|
||||
val state: RidingBehaviourState? = null,
|
||||
val data: RegistryFriendlyByteBuf? = null
|
||||
) : NetworkPacket<ClientboundUpdateRidingStatePacket> {
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
if (state == null) error("Expected state to be populated for encoding")
|
||||
buffer.writeInt(entity)
|
||||
buffer.writeResourceLocation(behaviour)
|
||||
state.encode(buffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("s2c_update_ride_controller")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ClientboundUpdateRidingStatePacket {
|
||||
val entity = buffer.readInt()
|
||||
val behaviour = buffer.readResourceLocation()
|
||||
val state = RegistryFriendlyByteBuf(buffer.readBytes(buffer.readableBytes()), Minecraft.getInstance().player!!.registryAccess())
|
||||
return ClientboundUpdateRidingStatePacket(
|
||||
entity = entity,
|
||||
behaviour = behaviour,
|
||||
data = state
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarkAddUpdatePacket(pokemon: () -> Pokemon, value: Mark?): SingleUpdatePacket<Mark?, MarkAddUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(this.value) { _, v -> buffer.writeIdentifier(v.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: Mark?) {
|
||||
if (value != null) pokemon.exchangeMark(value, true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("mark_add_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarkAddUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val markIdentifier = buffer.readNullable { buffer.readIdentifier() }
|
||||
val mark = if (markIdentifier == null) null else Marks.getByIdentifier(markIdentifier)
|
||||
return MarkAddUpdatePacket(pokemon, mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarkPotentialAddUpdatePacket(pokemon: () -> Pokemon, value: Mark?): SingleUpdatePacket<Mark?, MarkPotentialAddUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(this.value) { _, v -> buffer.writeIdentifier(v.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: Mark?) {
|
||||
if (value != null) pokemon.potentialMarks.add(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("potential_mark_add_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarkPotentialAddUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val markIdentifier = buffer.readNullable { buffer.readIdentifier() }
|
||||
val mark = if (markIdentifier == null) null else Marks.getByIdentifier(markIdentifier)
|
||||
return MarkPotentialAddUpdatePacket(pokemon, mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarkRemoveUpdatePacket(pokemon: () -> Pokemon, value: Mark?): SingleUpdatePacket<Mark?, MarkRemoveUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(this.value) { _, v -> buffer.writeIdentifier(v.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: Mark?) {
|
||||
if (value != null) pokemon.exchangeMark(value, false)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("mark_remove_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarkRemoveUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val markIdentifier = buffer.readNullable { buffer.readIdentifier() }
|
||||
val mark = if (markIdentifier == null) null else Marks.getByIdentifier(markIdentifier)
|
||||
return MarkRemoveUpdatePacket(pokemon, mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarkingsUpdatePacket(pokemon: () -> Pokemon, value: List<Int>): SingleUpdatePacket<List<Int>, MarkingsUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeCollection(this.value) { pb, value -> pb.writeInt(value) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: List<Int>) {
|
||||
pokemon.markings = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("markings_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarkingsUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val markings = buffer.readList(ByteBuf::readInt).toList()
|
||||
return MarkingsUpdatePacket(pokemon, markings)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarksPotentialUpdatePacket(pokemon: () -> Pokemon, value: MutableSet<Mark>): SingleUpdatePacket<MutableSet<Mark>, MarksPotentialUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeCollection(this.value) { pb, value -> pb.writeIdentifier(value.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: MutableSet<Mark>) {
|
||||
pokemon.potentialMarks = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("potential_marks_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarksPotentialUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val identifiers = buffer.readList(ByteBuf::readIdentifier).toList()
|
||||
val potentialMarks = identifiers.map { Marks.getByIdentifier(it) }.filterNotNull().toMutableSet()
|
||||
return MarksPotentialUpdatePacket(pokemon, potentialMarks)
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.client.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class MarksUpdatePacket(pokemon: () -> Pokemon, value: MutableSet<Mark>): SingleUpdatePacket<MutableSet<Mark>, MarksUpdatePacket>(pokemon, value) {
|
||||
override val id = ID
|
||||
override fun encodeValue(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeCollection(this.value) { pb, value -> pb.writeIdentifier(value.identifier) }
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: MutableSet<Mark>) {
|
||||
pokemon.marks = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("marks_update")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): MarksUpdatePacket {
|
||||
val pokemon = decodePokemon(buffer)
|
||||
val identifiers = buffer.readList(ByteBuf::readIdentifier).toList()
|
||||
val marks = identifiers.map { Marks.getByIdentifier(it) }.filterNotNull().toMutableSet()
|
||||
return MarksUpdatePacket(pokemon, marks)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.net.messages.client.spawn
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
@@ -37,6 +38,7 @@ class SpawnPokemonPacket(
|
||||
var beamMode: Byte,
|
||||
var platform: PlatformType,
|
||||
var nickname: MutableComponent?,
|
||||
var mark: ResourceLocation?,
|
||||
var labelLevel: Int,
|
||||
var poseType: PoseType,
|
||||
var unbattlable: Boolean,
|
||||
@@ -64,6 +66,7 @@ class SpawnPokemonPacket(
|
||||
entity.beamMode.toByte(),
|
||||
entity.platform,
|
||||
entity.pokemon.nickname,
|
||||
entity.pokemon.activeMark?.identifier,
|
||||
if (Cobblemon.config.displayEntityLevelLabel) entity.entityData.get(PokemonEntity.LABEL_LEVEL) else -1,
|
||||
entity.entityData.get(PokemonEntity.POSE_TYPE),
|
||||
entity.entityData.get(PokemonEntity.UNBATTLEABLE),
|
||||
@@ -89,6 +92,7 @@ class SpawnPokemonPacket(
|
||||
buffer.writeByte(this.beamMode.toInt())
|
||||
buffer.writeEnumConstant(this.platform)
|
||||
buffer.writeNullable(this.nickname) { _, v -> buffer.writeText(v) }
|
||||
buffer.writeNullable(this.mark) { _, v -> buffer.writeResourceLocation(v) }
|
||||
buffer.writeInt(this.labelLevel)
|
||||
buffer.writeEnumConstant(this.poseType)
|
||||
buffer.writeBoolean(this.unbattlable)
|
||||
@@ -110,6 +114,7 @@ class SpawnPokemonPacket(
|
||||
form = this@SpawnPokemonPacket.formName.let { formName -> species.forms.find { it.formOnlyShowdownId() == formName }} ?: species.standardForm
|
||||
forcedAspects = this@SpawnPokemonPacket.aspects
|
||||
nickname = this@SpawnPokemonPacket.nickname
|
||||
this@SpawnPokemonPacket.mark?.let {activeMark = Marks.getByIdentifier(it) }
|
||||
PokeBalls.getPokeBall(this@SpawnPokemonPacket.caughtBall)?.let { caughtBall = it }
|
||||
}
|
||||
entity.phasingTargetId = this.phasingTargetId
|
||||
@@ -150,6 +155,7 @@ class SpawnPokemonPacket(
|
||||
val beamModeEmitter = buffer.readByte()
|
||||
val platform = buffer.readEnumConstant(PlatformType::class.java)
|
||||
val nickname = buffer.readNullable { buffer.readText().copy() }
|
||||
val mark = buffer.readNullable { buffer.readResourceLocation() }
|
||||
val labelLevel = buffer.readInt()
|
||||
val poseType = buffer.readEnumConstant(PoseType::class.java)
|
||||
val unbattlable = buffer.readBoolean()
|
||||
@@ -161,7 +167,7 @@ class SpawnPokemonPacket(
|
||||
val passengers = buffer.readVarIntArray()
|
||||
val vanillaPacket = decodeVanillaPacket(buffer)
|
||||
|
||||
return SpawnPokemonPacket(ownerId, scaleModifier, speciesId, gender, shiny, formName, aspects, battleId, phasingTargetId, beamModeEmitter, platform, nickname, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, freezeFrame, passengers, vanillaPacket)
|
||||
return SpawnPokemonPacket(ownerId, scaleModifier, speciesId, gender, shiny, formName, aspects, battleId, phasingTargetId, beamModeEmitter, platform, nickname, mark, labelLevel, poseType, unbattlable, hideLabel, caughtBall, spawnAngle, friendship, freezeFrame, passengers, vanillaPacket)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ import com.cobblemon.mod.common.util.writeMatrix3f
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import org.joml.Matrix3f
|
||||
|
||||
class C2SUpdateOrientationPacket internal constructor(val orientation: Matrix3f?) : NetworkPacket<C2SUpdateOrientationPacket> {
|
||||
class ServerboundUpdateOrientationPacket internal constructor(val orientation: Matrix3f?) : NetworkPacket<ServerboundUpdateOrientationPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeBoolean(orientation != null)
|
||||
@@ -26,9 +26,9 @@ class C2SUpdateOrientationPacket internal constructor(val orientation: Matrix3f?
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_orientation")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): C2SUpdateOrientationPacket {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateOrientationPacket {
|
||||
val orientation = if (buffer.readBoolean()) buffer.readMatrix3f() else null
|
||||
return C2SUpdateOrientationPacket(orientation)
|
||||
return ServerboundUpdateOrientationPacket(orientation)
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.server.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class ServerboundUpdateRidingStatePacket(
|
||||
val entity: Int,
|
||||
val behaviour: ResourceLocation,
|
||||
val state: RidingBehaviourState? = null,
|
||||
val data: RegistryFriendlyByteBuf? = null
|
||||
) : NetworkPacket<ServerboundUpdateRidingStatePacket> {
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
if (state == null) error("Expected state to be populated for encoding")
|
||||
buffer.writeInt(entity)
|
||||
buffer.writeResourceLocation(behaviour)
|
||||
state.encode(buffer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_ride_controller")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateRidingStatePacket {
|
||||
val entity = buffer.readInt()
|
||||
val behaviour = buffer.readResourceLocation()
|
||||
val state = RegistryFriendlyByteBuf(buffer.readBytes(buffer.readableBytes()), server()!!.registryAccess())
|
||||
return ServerboundUpdateRidingStatePacket(
|
||||
entity = entity,
|
||||
behaviour = behaviour,
|
||||
data = state
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.net.messages.server.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Handled by [SetActiveMarkHandler].
|
||||
*/
|
||||
class SetActiveMarkPacket(val uuid: UUID, val mark: Mark?) : NetworkPacket<SetActiveMarkPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(uuid)
|
||||
buffer.writeNullable(mark) { _, v -> buffer.writeIdentifier(v.identifier) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("set_active_mark")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SetActiveMarkPacket {
|
||||
val uuid = buffer.readUUID()
|
||||
val markIdentifier = buffer.readNullable { buffer.readIdentifier() }
|
||||
val mark = if (markIdentifier !== null) Marks.getByIdentifier(markIdentifier) else null
|
||||
return SetActiveMarkPacket(uuid, mark)
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.net.messages.server.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Handled by [SetMarkingsHandler].
|
||||
*/
|
||||
class SetMarkingsPacket(val uuid: UUID, val markings: List<Int>, val isParty: Boolean = true) : NetworkPacket<SetMarkingsPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeUUID(uuid)
|
||||
buffer.writeCollection(markings) { pb, value -> pb.writeInt(value) }
|
||||
buffer.writeBoolean(isParty)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("set_markings")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SetMarkingsPacket {
|
||||
val uuid = buffer.readUUID()
|
||||
val markings = buffer.readList(ByteBuf::readInt).toList()
|
||||
val isParty = buffer.readBoolean()
|
||||
return SetMarkingsPacket(uuid, markings, isParty)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-11
@@ -10,23 +10,15 @@ package com.cobblemon.mod.common.net.serverhandling.orientation
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.C2SUpdateOrientationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import kotlin.math.atan2
|
||||
|
||||
object OrientationPacketHandler : ServerNetworkPacketHandler<C2SUpdateOrientationPacket> {
|
||||
override fun handle(packet: C2SUpdateOrientationPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
object OrientationPacketHandler : ServerNetworkPacketHandler<ServerboundUpdateOrientationPacket> {
|
||||
override fun handle(packet: ServerboundUpdateOrientationPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
if (player is OrientationControllable) {
|
||||
player.orientationController.updateOrientation { _ -> packet.orientation }
|
||||
|
||||
println("Packet Received! Roll ${"%.2f".format(player.orientationController.roll)} degrees")
|
||||
|
||||
// val orientation = packet.orientation
|
||||
// val roll = orientation?.let { atan2(it.m10, it.m00) } ?: 0f
|
||||
// val rollDegrees = Math.toDegrees(roll.toDouble())
|
||||
// println("Packet Received! Roll: ${"%.2f".format(rollDegrees)} degrees")
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+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.net.serverhandling.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object ServerboundUpdateRidingStateHandler : ServerNetworkPacketHandler<ServerboundUpdateRidingStatePacket> {
|
||||
|
||||
override fun handle(packet: ServerboundUpdateRidingStatePacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val entity = player.level().getEntity(packet.entity) ?: return
|
||||
if (entity !is PokemonEntity) return
|
||||
if (entity.controllingPassenger != player) return
|
||||
val buffer = packet.data ?: return
|
||||
if (entity.riding?.key != packet.behaviour) return
|
||||
entity.ridingState?.decode(buffer)
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.pc
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object SetMarkingsHandler : ServerNetworkPacketHandler<SetMarkingsPacket> {
|
||||
|
||||
override fun handle(packet: SetMarkingsPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
val pokemonStore: PokemonStore<*> = if (packet.isParty) player.party() else player.pc()
|
||||
val pokemon = pokemonStore[packet.uuid] ?: return
|
||||
|
||||
pokemon.markings = packet.markings
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.pokemon.update
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
object SetActiveMarkHandler : ServerNetworkPacketHandler<SetActiveMarkPacket> {
|
||||
|
||||
override fun handle(packet: SetActiveMarkPacket, server: MinecraftServer, player: ServerPlayer) {
|
||||
|
||||
val pokemonStore: PokemonStore<*> = player.party()
|
||||
val pokemon = pokemonStore[packet.uuid] ?: return
|
||||
|
||||
pokemon.activeMark = packet.mark
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents.FRIENDSHIP_UPDATED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_FAINTED
|
||||
import com.cobblemon.mod.common.api.events.pokemon.*
|
||||
import com.cobblemon.mod.common.api.events.pokemon.healing.PokemonHealedEvent
|
||||
import com.cobblemon.mod.common.api.mark.Mark
|
||||
import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addPokemonFunctions
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.BenchedMove
|
||||
@@ -244,7 +246,11 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
onChange(NicknameUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
fun getDisplayName(): MutableComponent = nickname?.copy()?.takeIf { it.contents != PlainTextContents.EMPTY } ?: species.translatedName.copy()
|
||||
fun getDisplayName(showTitle: Boolean = false): MutableComponent {
|
||||
var name = nickname?.copy()?.takeIf { it.contents != PlainTextContents.EMPTY } ?: species.translatedName.copy()
|
||||
if (showTitle) activeMark?.let { name = it.getTitle(name) }
|
||||
return name
|
||||
}
|
||||
|
||||
var level = 1
|
||||
set(value) {
|
||||
@@ -504,6 +510,30 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
onChange(CosmeticItemUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
var activeMark: Mark? = null
|
||||
set(value) {
|
||||
field = value
|
||||
onChange(ActiveMarkUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
var marks: MutableSet<Mark> = mutableSetOf()
|
||||
set(value) {
|
||||
field = value
|
||||
onChange(MarksUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
var potentialMarks: MutableSet<Mark> = mutableSetOf()
|
||||
set(value) {
|
||||
field = value
|
||||
onChange(MarksPotentialUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
var markings: List<Int> = listOf(0, 0, 0, 0, 0, 0)
|
||||
set(value) {
|
||||
field = value
|
||||
onChange(MarkingsUpdatePacket({ this }, value))
|
||||
}
|
||||
|
||||
fun asRenderablePokemon() = RenderablePokemon(species, aspects)
|
||||
|
||||
/**
|
||||
@@ -588,7 +618,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open fun getStat(stat: Stat) = Cobblemon.statProvider.getStatForPokemon(this, stat)
|
||||
|
||||
/**
|
||||
@@ -633,7 +662,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
mutation: (PokemonEntity) -> Unit = {},
|
||||
): CompletableFuture<PokemonEntity> {
|
||||
|
||||
|
||||
// Handle special case of shouldered Cobblemon
|
||||
if (this.state is ShoulderedState) {
|
||||
return sendOutFromShoulder(source as ServerPlayer, level, position, battleId, doCry, illusion, mutation)
|
||||
@@ -1007,6 +1035,57 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
*/
|
||||
fun removeHeldItem(): ItemStack = this.swapHeldItem(ItemStack.EMPTY)
|
||||
|
||||
fun addPotentialMark(mark: Mark) {
|
||||
potentialMarks.add(mark)
|
||||
if (!isClient) onChange(MarkPotentialAddUpdatePacket({ this }, mark))
|
||||
}
|
||||
|
||||
fun exchangeMark(mark: Mark, give: Boolean) {
|
||||
if (give) {
|
||||
mark.replace?.takeIf { it.isNotEmpty() }?.let { replacements ->
|
||||
for (mark in replacements) Marks.getByIdentifier(mark)?.let { exchangeMark(it, false) }
|
||||
}
|
||||
|
||||
marks.add(mark)
|
||||
if (!isClient) onChange(MarkAddUpdatePacket({ this }, mark))
|
||||
}
|
||||
else {
|
||||
marks.remove(mark)
|
||||
if (activeMark == mark) activeMark = null
|
||||
if (!isClient) onChange(MarkRemoveUpdatePacket({ this }, mark))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate mark to give from list of potential marks.
|
||||
* @return True if a mark has been applied, false otherwise
|
||||
*/
|
||||
fun applyPotentialMarks(): Boolean {
|
||||
// Remove any marks that are already owned
|
||||
val potentials = potentialMarks.filterNot { mark -> marks.contains(mark) }.toMutableSet()
|
||||
|
||||
if (!potentials.isEmpty()) {
|
||||
var selectedMark: Mark? = null
|
||||
val sortedMarkGroups = potentials.groupBy { it.getChanceGroup() }.toSortedMap(compareBy { it.second })
|
||||
|
||||
for ((chanceGroup, group) in sortedMarkGroups) {
|
||||
val probability = chanceGroup.second.coerceIn(0F, 1F) * 100
|
||||
val randomValue = Random.nextDouble(0.0, 100.0)
|
||||
|
||||
if (randomValue < probability) {
|
||||
selectedMark = group.random()
|
||||
break
|
||||
}
|
||||
}
|
||||
potentialMarks = mutableSetOf()
|
||||
selectedMark?.let {
|
||||
exchangeMark(it, true)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun saveToNBT(registryAccess: RegistryAccess, nbt: CompoundTag = CompoundTag()): CompoundTag {
|
||||
return this.saveTo(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt).orThrow as CompoundTag
|
||||
}
|
||||
@@ -1107,6 +1186,12 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
this.forcedAspects = other.forcedAspects
|
||||
this.features = other.features
|
||||
this.cosmeticItem = other.cosmeticItem
|
||||
this.activeMark = other.activeMark
|
||||
this.marks.clear()
|
||||
this.marks += other.marks
|
||||
this.potentialMarks.clear()
|
||||
this.potentialMarks += other.marks
|
||||
this.markings = other.markings
|
||||
this.updateAspects()
|
||||
this.refreshOriginalTrainer()
|
||||
this.initialize()
|
||||
|
||||
-396
@@ -1,396 +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.pokemon.riding.controllers
|
||||
|
||||
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.controller.RideController
|
||||
import com.cobblemon.mod.common.api.riding.controller.posing.PoseOption
|
||||
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.pokemon.riding.states.BirdAirState
|
||||
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 kotlin.math.*
|
||||
|
||||
class BirdAirController : RideController {
|
||||
override val key = KEY
|
||||
override val poseProvider = PoseProvider(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { it.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override val condition: (PokemonEntity) -> Boolean = { true }
|
||||
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
private set
|
||||
var topSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
private set
|
||||
var glideTopSpeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.0, 1.0)".asExpression()
|
||||
private set
|
||||
// Max accel is a whole 1.0 in 3 seconds. The conversion in the function below is to convert seconds to ticks
|
||||
var accelExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
private set
|
||||
//Seconds self propelled flight (glide is not self propelled in this case)
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
private set
|
||||
//max y level for the ride
|
||||
var altitudeExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
override fun speed(entity: PokemonEntity, driver: Player): Float {
|
||||
|
||||
//Retrieve the current bird controller state and stats
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
return state.rideVel.length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(entity: PokemonEntity, driver: LivingEntity): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(entity: PokemonEntity, driver: Player, input: Vec3): Vec3 {
|
||||
var yVel = 0.0
|
||||
var leftForce = 0.0
|
||||
var upForce = 0.0
|
||||
var forwardForce = 0.0
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//Perform ride velocity update
|
||||
calculateRideSpaceVel(entity, driver, state)
|
||||
|
||||
//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.z
|
||||
forwardForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.z
|
||||
|
||||
upForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.y
|
||||
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVel.y
|
||||
}
|
||||
|
||||
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina <= 0.0) {
|
||||
upForce -= 0.3
|
||||
}
|
||||
|
||||
val altitudeLimit = getRuntime(entity).resolveDouble(altitudeExpr)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (entity.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
val velocity = Vec3(state.rideVel.x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(entity: PokemonEntity, driver: Player, deltaTime: Double): Vec3 {
|
||||
|
||||
val controller = (driver as? OrientationControllable)?.orientationController
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//TODO: Tie in handling
|
||||
val handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val rotationChangeRate = 10.0
|
||||
|
||||
if (controller != null) {
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
//for a bit of correction on the rolls influence pitch as well
|
||||
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)
|
||||
}
|
||||
|
||||
return Vec3(0.0, 0.0, 0.0)
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
yMouse: Double,
|
||||
xMouse: Double,
|
||||
yMouseSmoother: SmoothDouble,
|
||||
xMouseSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
val handling = getRuntime(entity).resolveDouble(handlingExpr)
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
val xInput = xMouseSmoother.getNewDeltaValue(xMouse * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = yMouseSmoother.getNewDeltaValue(yMouse * 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.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.length(), 0.0, topSpeed).pow(3))
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawForce, yInput, rollForce)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(entity: PokemonEntity, driver: Player): Float {
|
||||
//Retrieve stamina from state
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
return (state.stamina / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
entity: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(entity: PokemonEntity, regularGravity: Double): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(entity: PokemonEntity) = true
|
||||
|
||||
override fun rideFovMult(entity: PokemonEntity, driver: Player): Float {
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = normalizeVal(state.rideVel.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(entity: PokemonEntity): Boolean = false
|
||||
|
||||
override fun useRidingAltPose(entity: PokemonEntity, driver: Player): Boolean {
|
||||
val state = getState(entity, ::BirdAirState)
|
||||
return state.gliding
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeExpression(topSpeedExpr)
|
||||
buffer.writeExpression(glideTopSpeedExpr)
|
||||
buffer.writeExpression(accelExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(altitudeExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
topSpeedExpr = buffer.readExpression()
|
||||
glideTopSpeedExpr = buffer.readExpression()
|
||||
accelExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
altitudeExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/bird")
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(entity: PokemonEntity, driver: Player, state: BirdAirState) {
|
||||
//retrieve stats
|
||||
val topSpeed = getRuntime(entity).resolveDouble(topSpeedExpr)
|
||||
val glideTopSpeed = getRuntime(entity).resolveDouble(glideTopSpeedExpr)
|
||||
val accel = getRuntime(entity).resolveDouble(accelExpr)
|
||||
val staminaStat = getRuntime(entity).resolveDouble(staminaExpr)
|
||||
|
||||
var glideSpeedChange = 0.0
|
||||
|
||||
val currSpeed = state.rideVel.length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && state.rideVel.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && state.rideVel.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
(state.rideVel.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 )
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.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)
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
min(state.rideVel.z + ((0.0166 * 2) * glideSpeedChange), glideTopSpeed))
|
||||
}
|
||||
}
|
||||
|
||||
//Lateral movement based on driver input.
|
||||
val latTopSpeed = topSpeed / 2.0
|
||||
if (driver.xxa != 0.0f && state.stamina > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
(state.rideVel.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
state.rideVel.y,
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
lerp(state.rideVel.x, 0.0, latTopSpeed / 20.0),
|
||||
state.rideVel.y,
|
||||
state.rideVel.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 > 0.0) {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
(state.rideVel.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
state.rideVel.z)
|
||||
activeInput = true
|
||||
}
|
||||
else {
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
lerp(state.rideVel.y, 0.0, vertTopSpeed / 20.0),
|
||||
state.rideVel.z)
|
||||
}
|
||||
|
||||
//Check if the ride should be gliding
|
||||
if (activeInput && state.stamina > 0.0) {
|
||||
state.gliding = false
|
||||
}else {
|
||||
state.gliding = true
|
||||
}
|
||||
|
||||
//Only perform stamina logic if the ride does not have infinite stamina
|
||||
if (!getRuntime(entity).resolveBoolean(infiniteStamina)) {
|
||||
if (activeInput) {
|
||||
state.stamina -= (0.05 / staminaStat).toFloat()
|
||||
}
|
||||
|
||||
//Lose a base amount of stamina just for being airborne
|
||||
state.stamina -= (0.01 / staminaStat).toFloat()
|
||||
}
|
||||
else
|
||||
{
|
||||
state.stamina = 1.0f
|
||||
}
|
||||
|
||||
//air resistance
|
||||
state.rideVel = Vec3(
|
||||
state.rideVel.x,
|
||||
state.rideVel.y,
|
||||
lerp( state.rideVel.z,0.0, topSpeed / ( 20.0 * 30.0)))
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user