Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9163046b45 | ||
|
|
325d1af484 | ||
|
|
6ae71f28e6 | ||
|
|
5687a71de4 | ||
|
|
8199f8d7c2 | ||
|
|
6b39251d65 | ||
|
|
cd03e6f8c4 | ||
|
|
a1b53f90ad | ||
|
|
c0677c6353 | ||
|
|
06732e89fd | ||
|
|
9e8d6a4f39 | ||
|
|
662efa55c6 | ||
|
|
efb9e538f3 | ||
|
|
42c711cfc7 | ||
|
|
681d5f8bcc | ||
|
|
a52d8452b4 | ||
|
|
e65298b587 | ||
|
|
f8c09b8e26 | ||
|
|
5d1019afd5 | ||
|
|
eb9bd116b2 | ||
|
|
70bf4d6654 | ||
|
|
080a5b9c74 | ||
|
|
b0be0b2dca | ||
|
|
d8300436c9 |
@@ -194,6 +194,17 @@
|
||||
### Changes
|
||||
- Changed pokemon caught and seen count to update based on the current pokedex being looked
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Added config setting `maxPokedexScanningDetectionRange` to control from what distance the player can scan Pokémon using the Pokédex.
|
||||
- Added the `is_standing_on_blocks(depth, blocks...)` MoLang function, which returns whether the specified entity is standing on a specific block or set of blocks. Example usage: `q.is_standing_on_blocks(2, minecraft:sand)`
|
||||
- Added config setting `hideUnimplementedPokemonInThePokedex` which hides unimplemented Pokémon from the Pokédex when set to true.
|
||||
- Added molang particle queries for getting distance to targeted entities
|
||||
- Added debug renderer for poseable entity locators
|
||||
- Added time zone as a config option
|
||||
- Added an optional MoValue to either use system timezone when set as true, or use the supplied string as a timezone for MoLang functions `date_local_time` and `date_of`. If the timezone supplied fails to parse this function now returns `0.0`.
|
||||
|
||||
### Additions
|
||||
- Added time zone as a config option
|
||||
- Added optional boolean to use time zone for MoLang function "date_local_time" and "date_of"
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
|
||||
- Updated Sweet and Tart Apple sprites
|
||||
@@ -240,7 +251,6 @@
|
||||
- Offset in EmitterShape now ignores scale to be more like Blockbench by default. You can get this behaviour back by adding `"scale": true` in the `attachment_options` property in most EmitterShapes.
|
||||
- Not specifying a dex in `/pokedex printcalculations {player} {dex}` will now print the National Dex statistics instead of showing all dexes. `/pokedex printcalculations {player} all` is how to view all dex statistics in one command.
|
||||
- Removed Braised Vivichoke
|
||||
- Updated Pokémon state icons shown in party interfaces
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -399,6 +409,7 @@
|
||||
- Added `q.has_argument(<argument_name>, [argument_value])` MoLang function to several battle-related action effect contexts.
|
||||
- Added `q.has_argument_at(<index>, [argument_value])` MoLang function to several battle-related action effect contexts.
|
||||
- Added `q.hit_count` MoLang function to move action effect contexts.
|
||||
- Added `is_included`, `to_lower`, `to_upper`, and `string_length` as available Molang functions.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -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.duck;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface ServerEntityDuck {
|
||||
void setDriverInput(Vector3f driverInput);
|
||||
}
|
||||
@@ -12,11 +12,9 @@ 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.duck.ServerEntityDuck;
|
||||
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.ClientboundUpdateDriverInputPacket;
|
||||
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;
|
||||
@@ -28,7 +26,6 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -41,7 +38,7 @@ import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public abstract class ServerEntityMixin implements ServerEntityDuck {
|
||||
public abstract class ServerEntityMixin {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
@@ -53,16 +50,11 @@ public abstract class ServerEntityMixin implements ServerEntityDuck {
|
||||
private Matrix3f cobblemon$lastSentOrientation;
|
||||
@Unique
|
||||
private boolean cobblemon$lastSentActive;
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@Unique
|
||||
private Vector3f cobblemon$lastSentDriverInput;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At("TAIL"))
|
||||
private void cobblemon$sendChanges(CallbackInfo ci) {
|
||||
cobblemon$sendOrientationChanges();
|
||||
cobblemon$sendRidingStateChanges();
|
||||
cobblemon$sendDriverInput();
|
||||
}
|
||||
|
||||
private void cobblemon$sendRidingStateChanges() {
|
||||
@@ -90,17 +82,6 @@ public abstract class ServerEntityMixin implements ServerEntityDuck {
|
||||
cobblemon$broadcast(new ClientboundUpdateOrientationPacket(currOrientation, currActive, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$sendDriverInput() {
|
||||
if (!(this.entity instanceof ServerPlayer serverPlayer)) return;
|
||||
if(!(serverPlayer.getVehicle() instanceof PokemonEntity)) return;
|
||||
if(cobblemon$driverInput == null) return;
|
||||
|
||||
// If no change in input is detected then don't send a new packet
|
||||
if (cobblemon$driverInput.equals(cobblemon$lastSentDriverInput)) return;
|
||||
cobblemon$lastSentDriverInput = cobblemon$driverInput;
|
||||
cobblemon$broadcast(new ClientboundUpdateDriverInputPacket(cobblemon$driverInput, entity.getId()));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
if (!(entity.level() instanceof ServerLevel level)) return;
|
||||
ChunkMap chunkMap = level.getChunkSource().chunkMap;
|
||||
@@ -116,9 +97,5 @@ public abstract class ServerEntityMixin implements ServerEntityDuck {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDriverInput(Vector3f driverInput) {
|
||||
cobblemon$driverInput = driverInput;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerConnection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
@@ -19,7 +18,4 @@ import java.util.Set;
|
||||
public interface TrackedEntityAccessor {
|
||||
@Accessor("seenBy")
|
||||
Set<ServerPlayerConnection> getSeenBy();
|
||||
|
||||
@Accessor("serverEntity")
|
||||
ServerEntity getServerEntity();
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -84,13 +83,6 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateDriverInputRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(this.xxa, this.zza, this.jumping, this.isShiftKeyDown()));
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
@@ -135,7 +127,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = locator != null ? new Vec3(locator.getMatrix().getTranslation(new Vector3f())) : Vec3.ZERO;
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
@@ -30,19 +29,4 @@ public abstract class EntityMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "collide(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/Entity;onGround()Z"
|
||||
)
|
||||
)
|
||||
private boolean cobblemon$forceOnGroundForStepUp(Entity entity) {
|
||||
if (entity instanceof PokemonEntity pokemon && entity.hasControllingPassenger()) {
|
||||
return true;
|
||||
}
|
||||
return entity.onGround();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHand
|
||||
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.riding.ClientboundUpdateDriverInputHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.OpenCobblemonConfigEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
||||
@@ -84,7 +83,6 @@ 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.ClientboundUpdateDriverInputPacket
|
||||
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
|
||||
@@ -175,7 +173,6 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPa
|
||||
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.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
@@ -226,7 +223,6 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkH
|
||||
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.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
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
|
||||
@@ -469,7 +465,6 @@ object CobblemonNetwork {
|
||||
|
||||
// Riding
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateRidingStatePacket.ID, ClientboundUpdateRidingStatePacket::decode, ClientboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateDriverInputPacket.ID, ClientboundUpdateDriverInputPacket::decode, ClientboundUpdateDriverInputHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
@@ -576,7 +571,6 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
@@ -143,6 +143,12 @@ import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -168,6 +174,20 @@ object MoLangFunctions {
|
||||
val replace = params.getString(2)
|
||||
return@Function StringValue(text.replace(search, replace))
|
||||
},
|
||||
"is_included" to java.util.function.Function { params ->
|
||||
val text = params.getString(0)
|
||||
val search = params.getString(1)
|
||||
return@Function DoubleValue(text.contains(search))
|
||||
},
|
||||
"to_lower" to java.util.function.Function { params ->
|
||||
return@Function StringValue(params.getString(0).lowercase())
|
||||
},
|
||||
"to_upper" to java.util.function.Function { params ->
|
||||
return@Function StringValue(params.getString(0).uppercase())
|
||||
},
|
||||
"string_length" to java.util.function.Function { params ->
|
||||
return@Function DoubleValue(params.getString(0).length)
|
||||
},
|
||||
"is_blank" to java.util.function.Function { params ->
|
||||
val arg = params.get<MoValue>(0)
|
||||
return@Function DoubleValue((arg is StringValue && (arg.value.isBlank() || arg.value.toDoubleOrNull() == 0.0)) || (arg is DoubleValue && arg.value == 0.0))
|
||||
@@ -275,16 +295,44 @@ object MoLangFunctions {
|
||||
DoubleValue(System.currentTimeMillis())
|
||||
},
|
||||
// the rest of the world use dd/MM/yyyy grow up america (this comment was generated by copilot)
|
||||
"date_local_time" to java.util.function.Function { _ ->
|
||||
val time = System.currentTimeMillis()
|
||||
val date = java.util.Date(time)
|
||||
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
|
||||
"date_local_time" to java.util.function.Function { params ->
|
||||
val useTimeZone = params.get<MoValue>(0)
|
||||
var timezone: ZoneId? = null
|
||||
if (useTimeZone is DoubleValue){
|
||||
timezone = if (useTimeZone.value == 1.0) Cobblemon.config.timeZoneId else null
|
||||
} else if (useTimeZone is StringValue){
|
||||
try {
|
||||
timezone = ZoneId.of(useTimeZone.value)
|
||||
} catch (_: Exception) {
|
||||
Cobblemon.LOGGER.error("Error parsing timezone: ${useTimeZone.value}")
|
||||
return@Function DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
val date: LocalDateTime = if (timezone != null) LocalDateTime.now(timezone) else LocalDateTime.now()
|
||||
val formatted = DateTimeFormatter.ofPattern("dd/MM/uuuu").format(date)
|
||||
StringValue(formatted)
|
||||
},
|
||||
"date_of" to java.util.function.Function { params ->
|
||||
val time = params.getDouble(0).toLong()
|
||||
val useTimeZone = params.get<MoValue>(1)
|
||||
var timezone: ZoneId? = null
|
||||
if (useTimeZone is DoubleValue){
|
||||
timezone = if (useTimeZone.value == 1.0) Cobblemon.config.timeZoneId else null
|
||||
} else if (useTimeZone is StringValue){
|
||||
try {
|
||||
timezone = ZoneId.of(useTimeZone.value)
|
||||
} catch (_: Exception) {
|
||||
Cobblemon.LOGGER.error("Error parsing timezone: ${useTimeZone.value}")
|
||||
return@Function DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
|
||||
val date = java.util.Date(time)
|
||||
val formatted = java.text.SimpleDateFormat("DD/MM/YYYY").format(date)
|
||||
val instant: Instant = date.toInstant()
|
||||
val formatted = DateTimeFormatter.ofPattern("dd/MM/uuuu").format(LocalDateTime.ofInstant(instant,
|
||||
timezone ?: ZoneOffset.systemDefault()
|
||||
))
|
||||
StringValue(formatted)
|
||||
},
|
||||
"date_is_after" to java.util.function.Function { params ->
|
||||
@@ -646,7 +694,7 @@ object MoLangFunctions {
|
||||
map
|
||||
}
|
||||
)
|
||||
val itemStackFunctions = mutableListOf<(ItemStack, RegistryAccess) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
val itemStackFunctions = mutableListOf<(ItemStack, RegistryAccess) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ stack, registryAccess ->
|
||||
val itemRegistry = registryAccess.registryOrThrow(Registries.ITEM)
|
||||
val holder = itemRegistry.wrapAsHolder(stack.item)
|
||||
@@ -665,7 +713,7 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
val entityFunctions: MutableList<(Entity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
val entityFunctions: MutableList<(Entity) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
{ entity ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("uuid") { _ -> StringValue(entity.uuid.toString()) }
|
||||
@@ -903,7 +951,7 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
val livingEntityFunctions: MutableList<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
val livingEntityFunctions: MutableList<(LivingEntity) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf<(LivingEntity) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ entity ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
map.put("is_living_entity") { DoubleValue.ONE }
|
||||
@@ -1645,8 +1693,6 @@ object MoLangFunctions {
|
||||
map.put("get_alt_pose") { StringValue(pokemonEntity.getAltPose()) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("gliding"))) }
|
||||
map.put("is_sprinting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("sprinting"))) }
|
||||
map.put("is_drifting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("drifting"))) }
|
||||
map.put("is_powered_drifting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("powered_drifting"))) }
|
||||
map.put("in_air") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("in_air"))) }
|
||||
map.put("is_wild") { DoubleValue(pokemonEntity.ownerUUID == null) }
|
||||
map.put("is_in_party") { DoubleValue(pokemonEntity.pokemon.storeCoordinates.get()?.store is PartyStore) }
|
||||
@@ -1974,7 +2020,7 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
val pokemonPropertiesFunctions: MutableList<(PokemonProperties) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
val pokemonPropertiesFunctions: MutableList<(PokemonProperties) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
{ props ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
|
||||
@@ -2032,7 +2078,7 @@ object MoLangFunctions {
|
||||
}
|
||||
)
|
||||
|
||||
val evolutionFunctions: MutableList<(Evolution) -> HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
val evolutionFunctions: MutableList<(Evolution) -> java.util.HashMap<String, java.util.function.Function<MoParams, Any>>> = mutableListOf(
|
||||
{ evolution ->
|
||||
val map = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.air.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
|
||||
@@ -23,19 +22,15 @@ object RidingBehaviours {
|
||||
|
||||
init {
|
||||
register(BirdBehaviour.KEY, BirdBehaviour())
|
||||
register(BirdNoRollBehaviour.KEY, BirdNoRollBehaviour())
|
||||
register(DolphinBehaviour.KEY, DolphinBehaviour())
|
||||
register(HorseBehaviour.KEY, HorseBehaviour())
|
||||
register(BoatBehaviour.KEY, BoatBehaviour())
|
||||
register(GliderBehaviour.KEY, GliderBehaviour())
|
||||
register(HelicopterBehaviour.KEY, HelicopterBehaviour())
|
||||
register(JetBehaviour.KEY, JetBehaviour())
|
||||
register(JetNoRollBehaviour.KEY, JetNoRollBehaviour())
|
||||
register(BurstBehaviour.KEY, BurstBehaviour())
|
||||
register(VehicleBehaviour.KEY, VehicleBehaviour())
|
||||
register(MinekartBehaviour.KEY, MinekartBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(RocketBehaviour.KEY, RocketBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
|
||||
@@ -107,6 +107,14 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
upForce -= 0.3
|
||||
}
|
||||
|
||||
val altitudeLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
|
||||
//Only limit altitude if altitude is not infinite
|
||||
if (!vehicle.runtime.resolveBoolean(settings.infiniteAltitude)) {
|
||||
//Provide a hard limit on altitude
|
||||
upForce = if (vehicle.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce, forwardForce)
|
||||
return velocity
|
||||
@@ -121,7 +129,12 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
|
||||
var glideSpeedChange = 0.0
|
||||
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
|
||||
@@ -456,7 +469,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
|
||||
@@ -1,518 +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.behaviour.types.air
|
||||
|
||||
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.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.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
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 org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdNoRollBehaviour : RidingBehaviour<BirdNoRollSettings, BirdNoRollState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/birdnoroll")
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
|
||||
override fun getRidingStyle(settings: BirdNoRollSettings, state: BirdNoRollState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<BirdNoRollSettings, BirdNoRollState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
|
||||
override fun isActive(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
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) {
|
||||
upForce += -1.0 * sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
forwardForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
|
||||
upForce += cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
forwardForce += sin(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().y
|
||||
}
|
||||
|
||||
//Bring the ride out of the sky when stamina is depleted.
|
||||
if (state.stamina.get() <= 0.0) {
|
||||
upForce -= 0.3
|
||||
}
|
||||
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity, driver: Player) {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
|
||||
var glideSpeedChange = 0.0
|
||||
|
||||
val currSpeed = state.rideVelocity.get().length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.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 * 0.25
|
||||
|
||||
//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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
driver.jumping && state.rideVelocity.get().length() < 0.3 -> 1.0
|
||||
driver.isShiftKeyDown && state.rideVelocity.get().length() < 0.3 -> -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)
|
||||
}
|
||||
}
|
||||
|
||||
//air resistance
|
||||
if( abs(newVelocity.z) > 0) {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.0015 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
state.rideVelocity.set(newVelocity)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
//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
|
||||
//TODO: Tie handling into yaw rate
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
//This rotation limit will be used to know if the ride has exceeded it and its needs correcting.
|
||||
val rotMin = 15.0
|
||||
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
|
||||
var yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
//val pitchedYawDelt = yawDeltaDeg - trueYawDelt
|
||||
|
||||
controller.applyGlobalYaw(trueYawDelt.toFloat())
|
||||
|
||||
//Calculate correcting roll force.
|
||||
val correctionRate = 5.0
|
||||
if(abs(controller.roll) > rotLimit && state.rideVelocity.get().length() < 0.2) {
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + ((abs(controller.roll) - rotLimit) / 180 - rotLimit) * controller.roll.sign * correctionRate * deltaTime * 0.01
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, 0.0, state.currRollCorrectionForce.get())
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
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
|
||||
|
||||
//TODO: hook up handling in parity with normal bird
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
//Smooth out mouse input.
|
||||
val smoothingSpeed = 4.0
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
|
||||
val mouseYc = (mouseY).coerceIn(-60.0, 60.0)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * ( 1.0 - min(sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), 0.5))
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
|
||||
var pitchRot = yInput
|
||||
|
||||
// Pitch up globally
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
/*
|
||||
* 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: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedGlideSpeed = normalizeVal(state.rideVelocity.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: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
if (state.gliding.get()) {
|
||||
return cobblemonResource("gliding")
|
||||
}
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: BirdNoRollSettings, state: BirdNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: BirdNoRollSettings,
|
||||
state: BirdNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: BirdNoRollSettings) = BirdNoRollState()
|
||||
}
|
||||
|
||||
class BirdNoRollSettings : RidingBehaviourSettings {
|
||||
override val key = BirdNoRollBehaviour.KEY
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
//max y level for the ride
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
|
||||
var glidespeedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 2.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(glidespeedExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
glidespeedExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class BirdNoRollState : RidingBehaviourState() {
|
||||
var gliding = ridingState(false, Side.CLIENT)
|
||||
var lastGlide = ridingState(-100L, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeFloat(stamina.get())
|
||||
buffer.writeBoolean(gliding.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
gliding.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
gliding.set(false, forced = true)
|
||||
lastGlide.set(-100L, forced = true)
|
||||
currRollCorrectionForce.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "BirdNoRollState(rideVelocity=${rideVelocity.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = BirdNoRollState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.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)
|
||||
it.currRollCorrectionForce.set(this.currRollCorrectionForce.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is BirdNoRollState) return false
|
||||
if (previous.gliding.get() != gliding.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,14 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
//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
|
||||
@@ -154,11 +162,17 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val altitudeLimit = vehicle.runtime.resolveDouble(settings.jumpExpr)
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
val speed = state.rideVelocity.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) {
|
||||
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.rideVelocity.set(
|
||||
@@ -168,7 +182,7 @@ class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
min(state.rideVelocity.get().z + (accel * accelMod), topSpeed)
|
||||
)
|
||||
)
|
||||
} else if (driver.zza >= 0.0 && (state.stamina.get() == 0.0f)) {
|
||||
} else if (driver.zza >= 0.0 && (state.stamina.get() == 0.0f || pushingHeightLimit)) {
|
||||
state.rideVelocity.set(
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
@@ -413,6 +427,9 @@ class JetSettings : RidingBehaviourSettings {
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
@@ -434,6 +451,7 @@ class JetSettings : RidingBehaviourSettings {
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(infiniteAltitude)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
@@ -447,6 +465,7 @@ class JetSettings : RidingBehaviourSettings {
|
||||
minSpeed = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
infiniteAltitude = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
@@ -482,6 +501,8 @@ class JetState : RidingBehaviourState() {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
// it.currMouseXForce.set(currMouseXForce.get(), forced = true)
|
||||
// it.currMouseYForce.set(currMouseYForce.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
|
||||
@@ -1,477 +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.behaviour.types.air
|
||||
|
||||
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.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.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
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.*
|
||||
|
||||
class JetNoRollBehaviour : RidingBehaviour<JetNoRollSettings, JetNoRollState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/jetnoroll")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: JetNoRollSettings, state: JetNoRollState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<JetNoRollSettings, JetNoRollState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
|
||||
|
||||
override fun isActive(settings: JetNoRollSettings, state: JetNoRollState, 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: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
|
||||
//retrieve minSpeed
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
|
||||
//TODO: Reintroduce stamina drain once stats start to be polished and tweaked
|
||||
state.stamina.set(1.0f)
|
||||
|
||||
return state.rideVelocity.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: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
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.rideVelocity.get().z
|
||||
forwardForce = cos(Math.toRadians(controller.pitch.toDouble())) * state.rideVelocity.get().z
|
||||
}
|
||||
|
||||
//If stamina has run out then initiate forced glide down.
|
||||
upForce = if (state.stamina.get() > 0.0) upForce else -0.7
|
||||
|
||||
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: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
val speed = state.rideVelocity.get().length()
|
||||
|
||||
|
||||
//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, 0.0)
|
||||
state.rideVelocity.set(
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
state.rideVelocity.get().y,
|
||||
min(state.rideVelocity.get().z + (accel * accelMod), topSpeed)
|
||||
)
|
||||
)
|
||||
} else if (driver.zza >= 0.0 && (state.stamina.get() == 0.0f)) {
|
||||
state.rideVelocity.set(
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
state.rideVelocity.get().y,
|
||||
max(state.rideVelocity.get().z - ((accel) / 4), minSpeed)
|
||||
)
|
||||
)
|
||||
} else if (driver.zza < 0.0 && speed > minSpeed) {
|
||||
//modify deccel to be slower when at closer speeds to minimum speed
|
||||
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 4, 0.1)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
state.rideVelocity.set(
|
||||
Vec3(
|
||||
state.rideVelocity.get().x,
|
||||
state.rideVelocity.get().y,
|
||||
max(state.rideVelocity.get().z - ((accel * deccelMod) / 2), minSpeed)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
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.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
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
|
||||
|
||||
var pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
// Yaw
|
||||
val yawRot = handling * 0.5 * state.currMouseXForce.get()
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
controller.applyGlobalYaw(yawRot.toFloat())
|
||||
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
pitchRot = 0.0
|
||||
state.currMouseYForce.set(0.0)
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
}
|
||||
|
||||
val mouseRotation = Vec3(0.0, pitchRot, 0.0)
|
||||
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if (abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp(state.currMouseXForce.get(), 0.0, 0.02))
|
||||
}
|
||||
if (mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val minSpeed = vehicle.runtime.resolveDouble(settings.minSpeed)
|
||||
|
||||
//Must I ensure that topspeed is greater than minimum?
|
||||
val normalizedSpeed = normalizeSpeed(state.rideVelocity.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: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): Double {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: JetNoRollSettings, state: JetNoRollState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: JetNoRollSettings) = JetNoRollState()
|
||||
|
||||
override fun damageOnCollision(
|
||||
settings: JetNoRollSettings,
|
||||
state: JetNoRollState,
|
||||
vehicle: PokemonEntity,
|
||||
impactVec: Vec3
|
||||
): Boolean {
|
||||
val impactSpeed = impactVec.horizontalDistance().toFloat() * 10f
|
||||
return vehicle.causeFallDamage(impactSpeed, 1f, vehicle.damageSources().flyIntoWall())
|
||||
}
|
||||
}
|
||||
|
||||
class JetNoRollSettings : RidingBehaviourSettings {
|
||||
override val key = JetNoRollBehaviour.KEY
|
||||
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "1.2".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Make configurable by json
|
||||
var infiniteStamina: Expression = "false".asExpression()
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 300.0, 128.0)".asExpression()
|
||||
private set
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 140.0, 20.0)".asExpression()
|
||||
private set
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.8, 1.0)".asExpression()
|
||||
private set
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.0)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 60.0, 10.0)".asExpression()
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(gravity)
|
||||
buffer.writeExpression(minSpeed)
|
||||
buffer.writeExpression(handlingYawExpr)
|
||||
buffer.writeExpression(infiniteStamina)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
gravity = buffer.readExpression()
|
||||
minSpeed = buffer.readExpression()
|
||||
handlingYawExpr = buffer.readExpression()
|
||||
infiniteStamina = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class JetNoRollState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseXForce = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseYForce = ridingState(0.0, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeDouble(currSpeed.get())
|
||||
buffer.writeFloat(stamina.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
currSpeed.set(buffer.readDouble(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
currSpeed.set(0.0, forced = true)
|
||||
currMouseXForce.set(0.0, forced = true)
|
||||
currMouseYForce.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = JetNoRollState().also {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.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 JetNoRollState) return false
|
||||
if (previous.currSpeed != currSpeed) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
@@ -1,566 +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.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.*
|
||||
|
||||
class RocketBehaviour : RidingBehaviour<RocketSettings, RocketState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/rocket")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: RocketSettings, state: RocketState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<RocketSettings, RocketState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ ->
|
||||
return@PoseOption state.boosting.get()
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
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: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return this.poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
// Use this as a "tick" function and check to see if the driver is "boosting"
|
||||
if(vehicle.level().isClientSide) {
|
||||
|
||||
//If the forward key is not held then it cannot be boosting
|
||||
if(Minecraft.getInstance().options.keyUp.isDown()) {
|
||||
val boostKeyPressed = Minecraft.getInstance().options.keySprint.isDown()
|
||||
|
||||
//If on the previous tick the boost key was held then don't change if the ride is boosting
|
||||
if(state.boostIsToggleable.get() && boostKeyPressed) {
|
||||
//flip the boosting state if boost key is pressed
|
||||
state.boosting.set(!state.boosting.get())
|
||||
}
|
||||
|
||||
//If the boost key is not held then next tick boosting is toggleable
|
||||
state.boostIsToggleable.set(!boostKeyPressed)
|
||||
} else {
|
||||
//Turn off boost and reset boost params
|
||||
state.boostIsToggleable.set(true)
|
||||
state.boosting.set(false)
|
||||
state.canSpeedBurst.set(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
val f = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val lookYawLimit = 90.0f
|
||||
val g = Mth.clamp(f, -lookYawLimit, lookYawLimit)
|
||||
|
||||
val ticksBeforeCorrection = 40
|
||||
|
||||
if(state.prevCamYRot.get() == driver.yRot){
|
||||
state.ticksNoInput.set(state.ticksNoInput.get() + 1)
|
||||
} else {
|
||||
state.ticksNoInput.set(0)
|
||||
}
|
||||
val correctionForce = if(state.ticksNoInput.get() >= ticksBeforeCorrection && f != 0.0f && state.boosting.get()) 1f * min(sqrt(lookYawLimit / (abs(f))), 10.0f) else 0.0f
|
||||
driver.yRotO += g - f
|
||||
driver.yRot = driver.yRot + g - f //- ( clamp(f.sign * correctionForce, -abs(f), abs(f)) )
|
||||
//driver.yRot = driver.yRot + g - f - ( min )
|
||||
state.prevCamYRot.set(driver.yRot)
|
||||
driver.setYHeadRot(driver.yRot)
|
||||
}
|
||||
|
||||
|
||||
override fun rotation(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
|
||||
// Grab turningAcceleration and divide 20 twice to get
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr) / 20.0f) / 20.0f * 2
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
|
||||
val maxTurnMomentum = 80.0f / 20.0f
|
||||
|
||||
// Base boost stats off of normal turning stats
|
||||
val boostMaxTurnMomentum = maxTurnMomentum * 0.1f
|
||||
val boostTurnInput = turnInput * 0.15f
|
||||
|
||||
if(state.boosting.get()) {
|
||||
if(driver.xxa != 0.0f && abs(newMomentum + turnInput) < (boostMaxTurnMomentum)) { //If max momentum will not be exceeded then modulate
|
||||
newMomentum += boostTurnInput
|
||||
} else {
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.05)
|
||||
}
|
||||
} else {
|
||||
if(driver.xxa == 0.0f) { //If no turning input then lerp to 0
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.05)
|
||||
} else if(abs(newMomentum + turnInput) < maxTurnMomentum) { //If max momentum will not be exceeded then modulate
|
||||
newMomentum += turnInput
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state.turnMomentum.set(newMomentum.toFloat())
|
||||
driver.yRot += newMomentum.toFloat()
|
||||
return Vec2(driver.xRot, vehicle.yRot + newMomentum.toFloat())
|
||||
|
||||
}
|
||||
|
||||
|
||||
override fun velocity(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val retVel = calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
state.rideVelocity.set(retVel)
|
||||
return retVel
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 2
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 0.5 * 2
|
||||
|
||||
var newVelocity = vehicle.deltaMovement
|
||||
|
||||
// Align the direction of movement with the world coordinate space so as not to modify it through turning
|
||||
val yawAligned = Matrix3f().rotateY(vehicle.yRot.toRadians())
|
||||
newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && !state.boosting.get()) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
vehicle.deltaMovement.horizontalDistance() > topSpeed && (driver.zza.sign == newVelocity.z.sign.toFloat()) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
} else if ((state.stamina.get() > 0.0 && state.boosting.get())) {
|
||||
val boostSpeed = topSpeed * 5
|
||||
val boostAccel = if(newVelocity.length() < boostSpeed) accel * 3 else 0.0
|
||||
val forwardInput = 1.0f
|
||||
var burst = 0.0f
|
||||
|
||||
if(state.canSpeedBurst.get()) {
|
||||
burst = 0.25f
|
||||
state.canSpeedBurst.set(false)
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
newVelocity.z + (boostAccel * forwardInput.toDouble()) + burst)
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val maxVertSpeed = 0.5f
|
||||
var vertInput = 0.0
|
||||
|
||||
//If boosting then don't lose altitude
|
||||
//otherwise propel up or fall
|
||||
if (state.boosting.get() && !driver.jumping && vehicle.deltaMovement.y > (-maxVertSpeed * 0.25)) {
|
||||
vertInput = -0.7
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y + accel * vertInput,
|
||||
newVelocity.z)
|
||||
} else if(state.boosting.get() && vehicle.deltaMovement.y < maxVertSpeed) {
|
||||
vertInput = when {
|
||||
driver.jumping -> 2.0
|
||||
else -> 0.0
|
||||
}
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
(newVelocity.y + (accel * 0.5 * vertInput)),
|
||||
newVelocity.z)
|
||||
} else {
|
||||
if (driver.jumping && !(vehicle.deltaMovement.y > maxVertSpeed && (newVelocity.y.sign.toFloat() > 0.0))) {
|
||||
vertInput = 1.0
|
||||
|
||||
// Reset falldistance if upward motion is detected
|
||||
vehicle.resetFallDistance()
|
||||
} else {
|
||||
vertInput = -2.5
|
||||
}
|
||||
|
||||
if (state.stamina.get() > 0.0) {
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
(newVelocity.y + (accel * vertInput)),
|
||||
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 normalizeVal(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: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
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: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
//Retrieve stamina from state and use it to set the "stamina bar"
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
if (state.boosting.get()) {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
//val exceededSpeed = max(vehicle.deltaMovement.length() - topSpeed, 0.0)
|
||||
|
||||
//TODO: Remove this magic number and get a better comparison for boost top speed
|
||||
val normalizedBoostSpeed = normalizeVal(state.rideVelocity.get().length(), topSpeed, topSpeed * 3)
|
||||
return 1.0f + normalizedBoostSpeed.pow(2).toFloat() * 0.2f
|
||||
} else {
|
||||
return 1.0f
|
||||
}
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: RocketSettings,
|
||||
state: RocketState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: RocketSettings) = RocketState()
|
||||
}
|
||||
|
||||
class RocketSettings : RidingBehaviourSettings {
|
||||
override val key = RocketBehaviour.KEY
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 0.65, 0.3) * 0.25".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 3.0))) * 0.5".asExpression()
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 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', 'AIR', 10.0, 1.0)".asExpression()
|
||||
private set
|
||||
|
||||
// Controls the acceleration of the turning speed since the max turning speed is locked at 60 degrees/second
|
||||
// So this is a range of 60 degrees/second per second to 20. Meaning at max stats when holding a direction it
|
||||
// takes a full second to be turning at max speed.
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 60.0, 20.0)".asExpression()
|
||||
private set
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(speedExpr)
|
||||
buffer.writeExpression(accelerationExpr)
|
||||
buffer.writeExpression(staminaExpr)
|
||||
buffer.writeExpression(jumpExpr)
|
||||
buffer.writeExpression(handlingExpr)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
speedExpr = buffer.readExpression()
|
||||
accelerationExpr = buffer.readExpression()
|
||||
staminaExpr = buffer.readExpression()
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RocketState : RidingBehaviourState() {
|
||||
var boosting = ridingState(false, Side.BOTH)
|
||||
var boostIsToggleable = ridingState(false, Side.BOTH)
|
||||
var canSpeedBurst = ridingState(false, Side.BOTH)
|
||||
var prevCamYRot: SidedRidingState<Float> = ridingState(0.0f, Side.CLIENT)
|
||||
var ticksNoInput: SidedRidingState<Int> = ridingState(0, Side.CLIENT)
|
||||
val turnMomentum: SidedRidingState<Float> = ridingState(0.0f, Side.CLIENT)
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
boosting.set(false, forced = true)
|
||||
boostIsToggleable.set(false, forced = true)
|
||||
canSpeedBurst.set(true, forced = true)
|
||||
prevCamYRot.set(0.0f, forced = true)
|
||||
ticksNoInput.set(0, forced = true)
|
||||
turnMomentum.set(0.0f, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = RocketState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.boosting.set(this.boosting.get(), forced = true)
|
||||
it.boostIsToggleable.set(this.boosting.get(), forced = true)
|
||||
it.canSpeedBurst.set(this.canSpeedBurst.get(), forced = true)
|
||||
it.prevCamYRot.set(this.prevCamYRot.get(), forced = true)
|
||||
it.ticksNoInput.set(this.ticksNoInput.get(), forced = true)
|
||||
it.turnMomentum.set(this.turnMomentum.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(boosting.get())
|
||||
buffer.writeBoolean(boostIsToggleable.get())
|
||||
buffer.writeBoolean(canSpeedBurst.get())
|
||||
buffer.writeFloat(prevCamYRot.get())
|
||||
buffer.writeInt(ticksNoInput.get())
|
||||
buffer.writeFloat(turnMomentum.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
boosting.set(buffer.readBoolean(), forced = true)
|
||||
boostIsToggleable.set(buffer.readBoolean(), forced = true)
|
||||
canSpeedBurst.set(buffer.readBoolean(), forced = true)
|
||||
prevCamYRot.set(buffer.readFloat(), forced = true)
|
||||
ticksNoInput.set(buffer.readInt(), forced = true)
|
||||
turnMomentum.set(buffer.readFloat(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is RocketState) return false
|
||||
if (previous.boosting.get() != boosting.get()) return true
|
||||
if (previous.boostIsToggleable.get() != boostIsToggleable.get()) return true
|
||||
if (previous.canSpeedBurst.get() != canSpeedBurst.get()) return true
|
||||
if (previous.prevCamYRot.get() != prevCamYRot.get()) return true
|
||||
if (previous.ticksNoInput.get() != ticksNoInput.get()) return true
|
||||
if (previous.turnMomentum.get() != turnMomentum.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
): Boolean {
|
||||
if (state.activeBehaviour.get() == defaultSettings.key) return false
|
||||
if (!vehicle.onGround()) return false
|
||||
if (state.lastTransition.get() + 5 >= vehicle.level().gameTime) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
|
||||
return defaultBehaviour.isActive(defaultSettings, state.defaultBehaviourState, vehicle)
|
||||
}
|
||||
@@ -58,7 +58,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
): Boolean {
|
||||
if (state.activeBehaviour.get() == alternativeSettings.key) return false
|
||||
if (!driver.jumping) return false
|
||||
if (state.lastTransition.get() + 5 >= vehicle.level().gameTime) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
val alternativeBehaviour = RidingBehaviours.get(alternativeSettings.key)
|
||||
return alternativeBehaviour.isActive(alternativeSettings, state.alternateBehaviourState, vehicle)
|
||||
}
|
||||
|
||||
@@ -83,15 +83,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
|
||||
// Use this as a "tick" function and calculate sprinting and inAir state here
|
||||
state.sprinting.set(driver.isSprinting)
|
||||
inAirCheck(state, vehicle)
|
||||
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
fun inAirCheck(
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
) {
|
||||
// Check both vertical movement and if there are blocks below.
|
||||
val posBelow = vehicle.blockPosition().below()
|
||||
val blockStateBelow = vehicle.level().getBlockState(posBelow)
|
||||
@@ -100,10 +92,14 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
val canSupportEntity = blockStateBelow.isFaceSturdy(vehicle.level(), posBelow, Direction.UP)
|
||||
val standingOnSolid = canSupportEntity && !isAirOrLiquid
|
||||
|
||||
// val level = vehicle.level()
|
||||
// val toesBox = vehicle.boundingBox.move(0.0, -0.1, 0.0)
|
||||
|
||||
// inAir if not on the ground
|
||||
val inAir = !(vehicle.deltaMovement.y == 0.0 || standingOnSolid)
|
||||
state.inAir.set(inAir)
|
||||
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
@@ -111,7 +107,26 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) { return }
|
||||
) {
|
||||
|
||||
//Take the inverse so that it cancels out how
|
||||
//much the entity rotates.
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
val rotMod = Mth.wrapDegrees(driver.yRot - vehicle.yRot) / maxYawDiff
|
||||
|
||||
val rotAmount = 10.0f
|
||||
|
||||
//Take the inverse so that you turn more at higher speeds
|
||||
val normSpeed = 1.0f - 0.5f*normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
//driver.yRot += (entity.riding.deltaRotation.y - turnAmount)
|
||||
//driver.setYHeadRot(driver.yHeadRot + (entity.riding.deltaRotation.y) - turnAmount)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: HorseSettings,
|
||||
@@ -134,9 +149,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
var turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
val turnAmount = calcRotAmount(settings, state, vehicle, driver)
|
||||
|
||||
return Vec2(vehicle.xRot, vehicle.yRot + turnAmount * 0.5f )
|
||||
return Vec2(vehicle.xRot, vehicle.yRot + turnAmount )
|
||||
|
||||
}
|
||||
|
||||
@@ -154,9 +169,9 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * 3
|
||||
val walkHandlingBoost = 5
|
||||
val walkHandling = handling * walkHandlingBoost
|
||||
//In degrees per second
|
||||
val walkHandling = 140.0 * 2
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * 2
|
||||
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
@@ -170,14 +185,13 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
val rotDiffMod = (sqrt(abs(rotDiffNorm)) * rotDiffNorm.sign)
|
||||
|
||||
//Take the inverse so that you turn less at higher speeds
|
||||
val normSpeed = 1.0f
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
// TurnRate should always be quick if not sprinting
|
||||
val invRelSpeed = (inverseLerp(vehicle.deltaMovement.horizontalDistance(), 0.0, topSpeed ).pow(0.5) - 1.0f) * -1.0f
|
||||
val turnRate = ((handling.toFloat() / 20.0f) * max(walkHandlingBoost * invRelSpeed, 1.0)).toFloat()
|
||||
val turnRate = if(state.sprinting.get()) (handling.toFloat() / 20.0f) else (walkHandling.toFloat() / 20.0f)
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
val rotAmount = turnSpeed.coerceIn(-abs(rotDiff), abs(rotDiff))
|
||||
|
||||
return rotAmount
|
||||
@@ -204,19 +218,16 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
val walkSpeed = getWalkSpeed(vehicle)
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 1.3
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val topSpeed = if(state.sprinting.get()) rideTopSpeed else walkSpeed
|
||||
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 2
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
// Gather the previous velocity and set the horizontal fields of the velocity vector to the magnitude of the
|
||||
// ones from deltaMovement. This is important as when a collision happens the Deltamovement will reflect it
|
||||
// but rideVelocity won't.
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, 0.0, state.rideVelocity.get().z).normalize().scale(vehicle.deltaMovement.horizontalDistance())
|
||||
newVelocity = newVelocity.add(0.0, state.rideVelocity.get().y, 0.0)
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
|
||||
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
|
||||
@@ -235,14 +246,11 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
// Gravity logic
|
||||
//Gravity logic
|
||||
if (vehicle.onGround()) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
} else {
|
||||
//TODO: Should we just go back to standard minecraft gravity or do the lerp modifications prevent that?
|
||||
//I think minecrafts gravity logic is also too harsh and isn't gamefied enough for mounts maybe? Need
|
||||
//to do some testing and get other's opinions
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.8
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2
|
||||
val terminalVel = 2.0
|
||||
|
||||
val fallingForce = gravity - ( newVelocity.z.sign *gravity *(abs(newVelocity.z) / 2.0))
|
||||
@@ -254,34 +262,27 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.03 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
|
||||
//TODO: Change this so its tied to a jumping stat and representative of the amount of jumps
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround() && canJump) {
|
||||
if (driver.jumping && vehicle.onGround()) {
|
||||
val jumpForce = 1.0
|
||||
val velMag = newVelocity.length()
|
||||
|
||||
val horz = state.rideVelocity.get().horizontalDistance()
|
||||
newVelocity = newVelocity.add(0.0, jumpForce, 0.0)
|
||||
|
||||
val test = 0.0
|
||||
//Ensure this doesn't add unwanted forward velocity
|
||||
//val mag = if(newVelocity.length() < rideTopSpeed) newVelocity.length() else rideTopSpeed
|
||||
//newVelocity = newVelocity.normalize().scale(mag)
|
||||
}
|
||||
|
||||
//Zero out lateral velocity possibly picked up from a controller transition
|
||||
newVelocity = Vec3(0.0, newVelocity.y, newVelocity.z)
|
||||
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
/*
|
||||
* lerps the current val between minVal and maxVal.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minVal and 1.0 represents maxVal.
|
||||
* 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 inverseLerp(currVal: Double, minVal: Double, maxVal: Double): Double {
|
||||
require(maxVal > minVal) { "minVal must be greater than maxVal" }
|
||||
return ((currVal - minVal) / (maxVal - minVal)).coerceIn(0.0, 1.0)
|
||||
private fun normalizeVal(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)
|
||||
}
|
||||
|
||||
private fun getWalkSpeed( vehicle: PokemonEntity ): Double {
|
||||
@@ -495,6 +496,7 @@ class HorseSettings : RidingBehaviourSettings {
|
||||
jumpExpr = buffer.readExpression()
|
||||
handlingExpr = buffer.readExpression()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HorseState : RidingBehaviourState() {
|
||||
|
||||
@@ -1,563 +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.behaviour.types.land
|
||||
|
||||
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.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.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
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 org.joml.Matrix3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sign
|
||||
|
||||
class MinekartBehaviour : RidingBehaviour<MinekartSettings, MinekartState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("land/minekart")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: MinekartSettings, state: MinekartState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<MinekartSettings, MinekartState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().horizontalDistance()) > 0.0
|
||||
})
|
||||
|
||||
// val poseProvider = PoseProvider<MinekartSettings, MinekartState>(PoseType.STAND)
|
||||
// .with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: MinekartSettings, state: MinekartState, 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: MinekartSettings, state: MinekartState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
|
||||
val boostMax = vehicle.runtime.resolveFloat(settings.boostLimit)
|
||||
//TODO: should this be by how much turn has accumulated or simply time turning... or both?
|
||||
val boostPerSecond = 20.0f
|
||||
val boostLoss = 40.0f
|
||||
|
||||
if (driver.jumping && driver.zza > 0.0f) {
|
||||
if (!state.drifting.get()) {
|
||||
if (driver.xxa != 0.0f) {
|
||||
state.clockwiseDrift.set(driver.xxa.sign > 0.0)
|
||||
state.turnMomentum.set(0.0f)
|
||||
state.drifting.set(true)
|
||||
state.boost.set(0.0f)
|
||||
} else {
|
||||
//TODO: Add jumping logic
|
||||
}
|
||||
} else {
|
||||
state.boost.set((state.boost.get() + boostPerSecond / 20.0f).coerceIn(0.0f, boostMax))
|
||||
}
|
||||
} else {
|
||||
if(driver.zza <= 0.0 && state.boost.get() != 0.0f){
|
||||
state.boost.set(0.0f)
|
||||
} else if( state.boost.get() > 0.0f ) {
|
||||
state.boost.set(max(state.boost.get() - boostLoss, 0.0f))
|
||||
}
|
||||
state.drifting.set(false)
|
||||
}
|
||||
|
||||
inAirCheck(state, vehicle)
|
||||
return driver.deltaMovement.length().toFloat()
|
||||
}
|
||||
|
||||
fun inAirCheck(
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
) {
|
||||
// Check both vertical movement and if there are blocks below.
|
||||
val posBelow = vehicle.blockPosition().below()
|
||||
val blockStateBelow = vehicle.level().getBlockState(posBelow)
|
||||
val isAirOrLiquid = blockStateBelow.isAir || !blockStateBelow.fluidState.isEmpty
|
||||
|
||||
val canSupportEntity = blockStateBelow.isFaceSturdy(vehicle.level(), posBelow, Direction.UP)
|
||||
val standingOnSolid = canSupportEntity && !isAirOrLiquid
|
||||
|
||||
// inAir if not on the ground
|
||||
val inAir = !(vehicle.deltaMovement.y == 0.0 || standingOnSolid)
|
||||
state.inAir.set(inAir)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
|
||||
//TODO: maybe tie this to max turnspeeds rather than the turn acceleration
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
val driftInput = turnInput * 0.25f
|
||||
|
||||
val lowSpeedTurnBoost = (inverseLerp(vehicle.deltaMovement.horizontalDistance(), 0.0, topSpeed ).pow(0.5) - 2.0f) * -1.0f
|
||||
val forcedDriftTurnMomentum = (80.0f / 20.0f) * lowSpeedTurnBoost
|
||||
val maxTurnMomentum = (60.0f / 20.0f) * lowSpeedTurnBoost
|
||||
val maxDriftMomentum = forcedDriftTurnMomentum * 0.6f
|
||||
|
||||
if (!state.drifting.get()){
|
||||
// perform non drift turning
|
||||
if(abs(newMomentum) <= maxTurnMomentum && turnInput != 0.0 ) {
|
||||
newMomentum += turnInput
|
||||
newMomentum = min(max(newMomentum, maxTurnMomentum * -1.0), maxTurnMomentum.toDouble())
|
||||
} else {
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.15)
|
||||
}
|
||||
|
||||
state.turnMomentum.set(newMomentum.toFloat())
|
||||
driver.yRot += newMomentum.toFloat()
|
||||
return Vec2(driver.xRot, vehicle.yRot + newMomentum.toFloat())
|
||||
} else {
|
||||
// perform drift turning
|
||||
if(abs(newMomentum) <= maxDriftMomentum && driftInput != 0.0 ) {
|
||||
newMomentum += driftInput
|
||||
newMomentum = min(max(newMomentum, maxDriftMomentum * -1.0), maxDriftMomentum.toDouble())
|
||||
} else {
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.15)
|
||||
}
|
||||
|
||||
val signedDriftTurn = if(state.clockwiseDrift.get()) forcedDriftTurnMomentum * -1.0f else forcedDriftTurnMomentum
|
||||
state.turnMomentum.set(newMomentum.toFloat())
|
||||
driver.yRot += newMomentum.toFloat() + signedDriftTurn.toFloat()
|
||||
return Vec2(driver.xRot, vehicle.yRot + newMomentum.toFloat() + signedDriftTurn.toFloat())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
|
||||
return state.rideVelocity.get()
|
||||
}
|
||||
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 0.6 * 2.0
|
||||
val topSpeed = if (state.drifting.get()) rideTopSpeed * 0.7 else rideTopSpeed
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 0.3 * 3 * 2.0
|
||||
val driftAngle = 20.0f
|
||||
|
||||
//Align the direction of this vector with the vehicles current heading.
|
||||
var newVelocity = vehicle.deltaMovement
|
||||
newVelocity = newVelocity.yRot(vehicle.yRot.toRadians())
|
||||
|
||||
// rotate the angle of force if drifting
|
||||
if (state.drifting.get()) {
|
||||
val signedDriftAngle = if(state.clockwiseDrift.get()) driftAngle else driftAngle * -1.0f
|
||||
newVelocity = newVelocity.yRot(signedDriftAngle.toRadians())
|
||||
}
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && !state.inAir.get()) {
|
||||
//make sure it can't exceed top speed
|
||||
var forwardInput = when {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z <= 0.0 -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
if (!state.drifting.get() && state.boost.get() != 0.0f) {
|
||||
forwardInput = 2.0;
|
||||
}
|
||||
|
||||
// If drifting we need more acceleration due to the constant turn
|
||||
val driftAccelBoost = if (state.drifting.get()) 1.5 else 1.0
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble() * driftAccelBoost)))
|
||||
}
|
||||
|
||||
// Gravity logic
|
||||
if (vehicle.onGround()) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
} else {
|
||||
//TODO: Should we just go back to standard minecraft gravity or do the lerp modifications prevent that?
|
||||
//I think minecrafts gravity logic is also too harsh and isn't gamefied enough for mounts maybe? Need
|
||||
//to do some testing and get other's opinions
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.25 * 3.0
|
||||
val terminalVel = 2.0
|
||||
|
||||
val fallingForce = gravity - ( newVelocity.z.sign *gravity *(abs(newVelocity.z) / 2.0))
|
||||
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - fallingForce, -terminalVel), newVelocity.z)
|
||||
}
|
||||
|
||||
//ground Friction
|
||||
var friction = 0.003 * 2.0
|
||||
if (state.drifting.get()) {friction *= 0.5}
|
||||
if (!state.inAir.get()) {
|
||||
newVelocity = newVelocity.subtract(
|
||||
min(friction , abs(newVelocity.x)) * newVelocity.x.sign,
|
||||
0.0,
|
||||
min(friction , abs(newVelocity.z)) * newVelocity.z.sign
|
||||
)
|
||||
|
||||
// TEST FOR LATERAL SLIP OR WHATEVER
|
||||
//TODO: calc lateral slip and friction better!
|
||||
if (!state.drifting.get()) {
|
||||
newVelocity = newVelocity.subtract(
|
||||
min(friction * 10, abs(newVelocity.x)) * newVelocity.x.sign,
|
||||
0.0,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Change this so its tied to a jumping stat and representative of the amount of jumps
|
||||
// val canJump = vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
// //Jump the thang!
|
||||
// if (driver.jumping && vehicle.onGround() && canJump) {
|
||||
// val jumpForce = 0.5
|
||||
//
|
||||
// newVelocity = newVelocity.add(0.0, jumpForce, 0.0)
|
||||
//
|
||||
// }
|
||||
|
||||
// unrotate the angle of force if drifting
|
||||
if (state.drifting.get()) {
|
||||
val inverseSignedDriftAngle = if(state.clockwiseDrift.get()) driftAngle * -1.0f else driftAngle
|
||||
newVelocity = newVelocity.yRot(inverseSignedDriftAngle.toRadians())
|
||||
}
|
||||
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
/*
|
||||
* lerps the current val between minVal and maxVal.
|
||||
* The result is clamped between 0.0 and 1.0, where 0.0 represents minVal and 1.0 represents maxVal.
|
||||
*/
|
||||
private fun inverseLerp(currVal: Double, minVal: Double, maxVal: Double): Double {
|
||||
require(maxVal > minVal) { "minVal must be greater than maxVal" }
|
||||
return ((currVal - minVal) / (maxVal - minVal)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
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: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
var fov = 1.0f
|
||||
if(!state.drifting.get() && state.boost.get() != 0.0f) {
|
||||
//TODO: is this too abrupt? Possibly caluclate differently?
|
||||
fov = 1.2f
|
||||
}
|
||||
return fov
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
when {
|
||||
state.drifting.get() -> return cobblemonResource("drifting")
|
||||
}
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: MinekartSettings, state: MinekartState, vehicle: PokemonEntity): Double {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: MinekartSettings, state: MinekartState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
settings: MinekartSettings,
|
||||
state: MinekartState,
|
||||
vehicle: PokemonEntity
|
||||
): RideSoundSettingsList {
|
||||
return settings.rideSounds
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: MinekartSettings) = MinekartState()
|
||||
}
|
||||
|
||||
class MinekartSettings : RidingBehaviourSettings {
|
||||
override val key = MinekartBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var boostLimit = "100.0f".asExpression()
|
||||
private set
|
||||
|
||||
var speedExpr: 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 accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
private set
|
||||
|
||||
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
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
rideSounds.encode(buffer)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(boostLimit)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
canJump = buffer.readExpression()
|
||||
boostLimit = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class MinekartState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var deltaRotation = ridingState(Vec2.ZERO, Side.BOTH)
|
||||
var drifting = ridingState(false, Side.CLIENT)
|
||||
var clockwiseDrift = ridingState(false, Side.CLIENT)
|
||||
val boost: SidedRidingState<Float> = ridingState(0.0f, Side.CLIENT)
|
||||
val turnMomentum: SidedRidingState<Float> = ridingState(0.0f, Side.CLIENT)
|
||||
var inAir = ridingState(false, Side.CLIENT)
|
||||
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
currSpeed.set(0.0, forced = true)
|
||||
deltaRotation.set(Vec2.ZERO, forced = true)
|
||||
drifting.set(false, forced = true)
|
||||
clockwiseDrift.set(false, forced = true)
|
||||
boost.set(0.0f, forced = true)
|
||||
turnMomentum.set(0.0f, forced = true)
|
||||
inAir.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(drifting.get())
|
||||
buffer.writeBoolean(clockwiseDrift.get())
|
||||
buffer.writeFloat(boost.get())
|
||||
buffer.writeFloat(turnMomentum.get())
|
||||
buffer.writeBoolean(inAir.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
drifting.set(buffer.readBoolean(), forced = true)
|
||||
clockwiseDrift.set(buffer.readBoolean(), forced = true)
|
||||
boost.set(buffer.readFloat(), forced = true)
|
||||
turnMomentum.set(buffer.readFloat(), forced = true)
|
||||
inAir.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "MinekartState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = MinekartState().also {
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.deltaRotation.set(deltaRotation.get(), forced = true)
|
||||
it.drifting.set(drifting.get(), forced = true)
|
||||
it.clockwiseDrift.set(clockwiseDrift.get(), forced = true)
|
||||
it.boost.set(boost.get(), forced = true)
|
||||
it.turnMomentum.set(turnMomentum.get(), forced = true)
|
||||
it.inAir.set(inAir.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is MinekartState) return false
|
||||
if (previous.drifting.get() != drifting.get()) return true
|
||||
if (previous.clockwiseDrift.get() != clockwiseDrift.get()) return true
|
||||
if (previous.boost.get() != boost.get()) return true
|
||||
if (previous.turnMomentum.get() != turnMomentum.get()) return true
|
||||
if (previous.inAir.get() != inAir.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
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
|
||||
@@ -17,12 +16,10 @@ 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.sound.RideSoundSettingsList
|
||||
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 com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
@@ -31,15 +28,29 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sign
|
||||
|
||||
class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
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
|
||||
@@ -49,12 +60,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<VehicleSettings, VehicleState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().horizontalDistance()) > 0.0
|
||||
})
|
||||
|
||||
// val poseProvider = PoseProvider<VehicleSettings, VehicleState>(PoseType.STAND)
|
||||
// .with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
@@ -81,38 +87,18 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
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)
|
||||
|
||||
if (driver.isShiftKeyDown) {
|
||||
state.drifting.set(true)
|
||||
if(driver.zza != 0.0f) {
|
||||
state.poweredDrifting.set(true)
|
||||
} else {
|
||||
state.poweredDrifting.set(false)
|
||||
}
|
||||
} else {
|
||||
state.drifting.set(false)
|
||||
state.poweredDrifting.set(false)
|
||||
//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))
|
||||
}
|
||||
|
||||
inAirCheck(state, vehicle)
|
||||
return driver.deltaMovement.length().toFloat()
|
||||
}
|
||||
|
||||
fun inAirCheck(
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
) {
|
||||
// Check both vertical movement and if there are blocks below.
|
||||
val posBelow = vehicle.blockPosition().below()
|
||||
val blockStateBelow = vehicle.level().getBlockState(posBelow)
|
||||
val isAirOrLiquid = blockStateBelow.isAir || !blockStateBelow.fluidState.isEmpty
|
||||
|
||||
val canSupportEntity = blockStateBelow.isFaceSturdy(vehicle.level(), posBelow, Direction.UP)
|
||||
val standingOnSolid = canSupportEntity && !isAirOrLiquid
|
||||
|
||||
// inAir if not on the ground
|
||||
val inAir = !(vehicle.deltaMovement.y == 0.0 || standingOnSolid)
|
||||
state.inAir.set(inAir)
|
||||
return state.currSpeed.get().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
@@ -121,38 +107,10 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
|
||||
var newMomentum = state.turnMomentum.get().toDouble()
|
||||
|
||||
// Grab turningAcceleration and divide 20 twice to get
|
||||
val turningAcceleration = (vehicle.runtime.resolveDouble(settings.handlingExpr) * 1.5 / 20.0f) / 20.0f * 4.0
|
||||
val turnInput = (driver.xxa *-1.0f) * turningAcceleration
|
||||
|
||||
val maxTurnMomentum = 80.0f / 20.0f
|
||||
|
||||
// Base boost stats off of normal turning stats
|
||||
val driftMaxTurnMomentum = maxTurnMomentum * 3.0f
|
||||
var driftTurnInput = turnInput * 0.4f
|
||||
|
||||
if(state.drifting.get() || state.inAir.get()) {
|
||||
if( newMomentum < driftMaxTurnMomentum) {
|
||||
driftTurnInput = driftTurnInput * (vehicle.deltaMovement.horizontalDistance() / vehicle.runtime.resolveDouble(settings.speedExpr))
|
||||
newMomentum += driftTurnInput
|
||||
}
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.03)
|
||||
if( abs(newMomentum) < 0.05 ) {newMomentum = 0.0}
|
||||
} else {
|
||||
if(abs(newMomentum) <= maxTurnMomentum && turnInput != 0.0 ) {
|
||||
newMomentum += turnInput
|
||||
newMomentum.coerceIn(-maxTurnMomentum.toDouble(), maxTurnMomentum.toDouble())
|
||||
} else {
|
||||
newMomentum = lerp(newMomentum, 0.0, 0.15)
|
||||
}
|
||||
}
|
||||
|
||||
state.turnMomentum.set(newMomentum.toFloat())
|
||||
driver.yRot += newMomentum.toFloat()
|
||||
return Vec2(driver.xRot, vehicle.yRot + newMomentum.toFloat())
|
||||
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(
|
||||
@@ -162,106 +120,18 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
|
||||
return state.rideVelocity.get()
|
||||
}
|
||||
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
//val walkSpeed = getWalkSpeed(vehicle)
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr) * 0.6 * 2.0
|
||||
val topSpeed = if (state.drifting.get()) rideTopSpeed * 0.5 else rideTopSpeed
|
||||
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr) * 0.3 * 3 * 2.0
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
var newVelocity = Vec3.ZERO
|
||||
if (!state.drifting.get()) {
|
||||
newVelocity = vehicle.deltaMovement
|
||||
|
||||
newVelocity = newVelocity.yRot(vehicle.yRot.toRadians())
|
||||
|
||||
} else {
|
||||
state
|
||||
newVelocity = vehicle.deltaMovement
|
||||
|
||||
// Align the direction of movement with the world coordinate space so as not to modify it through turning
|
||||
val yawAligned = Matrix3f().rotateY(vehicle.yRot.toRadians())
|
||||
newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && !state.inAir.get()) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z <= 0.0 -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
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())
|
||||
|
||||
// Gravity logic
|
||||
if (vehicle.onGround()) {
|
||||
newVelocity = Vec3(newVelocity.x, 0.0, newVelocity.z)
|
||||
} else {
|
||||
//TODO: Should we just go back to standard minecraft gravity or do the lerp modifications prevent that?
|
||||
//I think minecrafts gravity logic is also too harsh and isn't gamefied enough for mounts maybe? Need
|
||||
//to do some testing and get other's opinions
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2 * 0.25 * 3.0
|
||||
val terminalVel = 2.0
|
||||
|
||||
val fallingForce = gravity - ( newVelocity.z.sign *gravity *(abs(newVelocity.z) / 2.0))
|
||||
newVelocity = Vec3(newVelocity.x, max(newVelocity.y - fallingForce, -terminalVel), newVelocity.z)
|
||||
}
|
||||
|
||||
//ground Friction
|
||||
var friction = 0.003 * 2.0
|
||||
if (state.drifting.get()) {friction *= 0.1}
|
||||
if (!state.inAir.get()) {
|
||||
newVelocity = newVelocity.subtract(
|
||||
min(friction , abs(newVelocity.x)) * newVelocity.x.sign,
|
||||
0.0,
|
||||
min(friction , abs(newVelocity.z)) * newVelocity.z.sign
|
||||
)
|
||||
|
||||
// TEST FOR LATERAL SLIP OR WHATEVER
|
||||
//TODO: calc lateral slip and friction better!
|
||||
if (!state.drifting.get()) {
|
||||
newVelocity = newVelocity.subtract(
|
||||
min(friction * 10, abs(newVelocity.x)) * newVelocity.x.sign,
|
||||
0.0,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Change this so its tied to a jumping stat and representative of the amount of jumps
|
||||
val canJump = vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround() && canJump) {
|
||||
val jumpForce = 0.5
|
||||
|
||||
newVelocity = newVelocity.add(0.0, jumpForce, 0.0)
|
||||
|
||||
}
|
||||
|
||||
return newVelocity
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
@@ -319,7 +189,10 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
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(
|
||||
@@ -328,7 +201,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
return regularGravity
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
@@ -354,15 +227,11 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
when {
|
||||
state.poweredDrifting.get() -> return cobblemonResource("powered_drifting")
|
||||
state.drifting.get() -> return cobblemonResource("drifting")
|
||||
}
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Double {
|
||||
return 1.0
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
|
||||
@@ -398,7 +267,7 @@ class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getRideSounds(
|
||||
@@ -418,6 +287,9 @@ class VehicleSettings : RidingBehaviourSettings {
|
||||
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
|
||||
|
||||
@@ -427,40 +299,28 @@ class VehicleSettings : RidingBehaviourSettings {
|
||||
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
|
||||
|
||||
var speedExpr: 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 accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'LAND', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 5.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
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
rideSounds.encode(buffer)
|
||||
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)
|
||||
}
|
||||
@@ -468,9 +328,15 @@ class VehicleSettings : RidingBehaviourSettings {
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
rideSounds = RideSoundSettingsList.decode(buffer)
|
||||
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()
|
||||
}
|
||||
@@ -479,36 +345,11 @@ class VehicleSettings : RidingBehaviourSettings {
|
||||
class VehicleState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var deltaRotation = ridingState(Vec2.ZERO, Side.BOTH)
|
||||
var drifting = ridingState(false, Side.CLIENT)
|
||||
var poweredDrifting = ridingState(false, Side.CLIENT)
|
||||
val turnMomentum: SidedRidingState<Float> = ridingState(0.0f, Side.CLIENT)
|
||||
var inAir = ridingState(false, Side.CLIENT)
|
||||
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
currSpeed.set(0.0, forced = true)
|
||||
deltaRotation.set(Vec2.ZERO, forced = true)
|
||||
drifting.set(false, forced = true)
|
||||
poweredDrifting.set(false, forced = true)
|
||||
turnMomentum.set(0.0f, forced = true)
|
||||
inAir.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(drifting.get())
|
||||
buffer.writeBoolean(poweredDrifting.get())
|
||||
buffer.writeFloat(turnMomentum.get())
|
||||
buffer.writeBoolean(inAir.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
drifting.set(buffer.readBoolean(), forced = true)
|
||||
poweredDrifting.set(buffer.readBoolean(), forced = true)
|
||||
turnMomentum.set(buffer.readFloat(), forced = true)
|
||||
inAir.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -520,18 +361,5 @@ class VehicleState : RidingBehaviourState() {
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.deltaRotation.set(deltaRotation.get(), forced = true)
|
||||
it.drifting.set(drifting.get(), forced = true)
|
||||
it.poweredDrifting.set(poweredDrifting.get(), forced = true)
|
||||
it.turnMomentum.set(turnMomentum.get(), forced = true)
|
||||
it.inAir.set(inAir.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is VehicleState) return false
|
||||
if (previous.drifting.get() != drifting.get()) return true
|
||||
if (previous.poweredDrifting.get() != poweredDrifting.get()) return true
|
||||
if (previous.turnMomentum.get() != turnMomentum.get()) return true
|
||||
if (previous.inAir.get() != inAir.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
@@ -20,7 +19,6 @@ import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
@@ -31,9 +29,7 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.min
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
@@ -47,7 +43,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.deltaMovement.length() > 0.1 })
|
||||
.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 {
|
||||
@@ -165,59 +161,11 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
val controller = (driver as OrientationControllable).orientationController
|
||||
|
||||
//TODO:hook up handling
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
//Interpret mouse input
|
||||
val smoothingSpeed = 4.0
|
||||
//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
|
||||
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
|
||||
val mouseYc = (mouseY).coerceIn(-60.0, 60.0)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
val yInput = mouseYSmoother.getNewDeltaValue(mouseYc * 0.1 * invertPitch, deltaTime * smoothingSpeed);
|
||||
val rollRot = xInput
|
||||
val pitchRot = yInput
|
||||
|
||||
// Roll
|
||||
// if (abs(controller.pitch + rollRot) >= 89.5 ) {
|
||||
// mouseXSmoother.reset()
|
||||
// } else {
|
||||
//
|
||||
// }
|
||||
|
||||
controller.rotateRoll(rollRot.toFloat())
|
||||
|
||||
// Yaw
|
||||
// TODO:move all magic numbers to handling expression
|
||||
val yawSpeed = handling * deltaTime * 0.25
|
||||
val yawForce = sin(controller.roll.toRadians()) * yawSpeed * ( 1.0 - min(sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), 0.5))
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
|
||||
// Pitch
|
||||
if (abs(controller.pitch + pitchRot) >= 89.5 ) {
|
||||
mouseYSmoother.reset()
|
||||
} else {
|
||||
//controller.applyGlobalPitch(pitchRot.toFloat() * -1.0f)
|
||||
controller.rotatePitch(pitchRot.toFloat())
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
@@ -347,12 +295,6 @@ class DolphinSettings : RidingBehaviourSettings {
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
var jumpExpr: Expression = "q.get_ride_stats('JUMP', 'AIR', 200.0, 128.0)".asExpression()
|
||||
var handlingExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 135.0, 45.0)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.35)".asExpression()
|
||||
var accelerationExpr: Expression = "q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 3.0)), (1.0 / (20.0 * 8.0)))".asExpression()
|
||||
var staminaExpr: Expression = "q.get_ride_stats('STAMINA', 'AIR', 120.0, 20.0)".asExpression()
|
||||
|
||||
var rideSounds: RideSoundSettingsList = RideSoundSettingsList()
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
|
||||
@@ -50,7 +50,7 @@ class RideLoopSound(val ride: PokemonEntity, val soundSettings: RideSoundSetting
|
||||
this.looping = true
|
||||
this.delay = 0
|
||||
this.volume = 0.1f
|
||||
this.attenuation = SoundInstance.Attenuation.LINEAR // This class performs its own attenuation
|
||||
this.attenuation = SoundInstance.Attenuation.NONE // This class performs its own attenuation
|
||||
if (this.isPassenger) this.relative = true
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.sign
|
||||
|
||||
/**
|
||||
* Class to handle the updating and containment of ride data used in animation.
|
||||
@@ -34,7 +33,6 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
var rotSpring: Vec3Spring = Vec3Spring()
|
||||
var rotDeltaSpring: Vec3Spring = Vec3Spring()
|
||||
var localVelocitySpring: Vec3Spring = Vec3Spring()
|
||||
var driverInputSpring: Vec3Spring = Vec3Spring()
|
||||
|
||||
fun update() {
|
||||
val activeRide = ride.hasControllingPassenger()
|
||||
@@ -138,14 +136,6 @@ class RidingAnimationData(val ride: PokemonEntity)
|
||||
/******************************************************
|
||||
* Update springs
|
||||
*****************************************************/
|
||||
val driver = ride.controllingPassenger
|
||||
val vertInput = when {
|
||||
driver != null && driver.jumping-> 1.0
|
||||
driver != null && driver.isShiftKeyDown -> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
val input = if(driver != null) Vec3(driver.xxa.toDouble() * -1, vertInput, driver.zza.toDouble()) else Vec3.ZERO
|
||||
driverInputSpring.update(input, stiffness * 2, damping)
|
||||
rotDeltaSpring.update(angDelta, stiffness, damping)
|
||||
velocitySpring.update(currentVelocity, stiffness, damping)
|
||||
rotSpring.update(currRot, stiffness, damping)
|
||||
|
||||
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.air.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
|
||||
@@ -134,34 +133,25 @@ class RideControlsOverlay : Gui(Minecraft.getInstance()) {
|
||||
// Configure what controls to show for each behaviour
|
||||
when (currentBehaviourKey) {
|
||||
BirdBehaviour.KEY -> {}
|
||||
BoatBehaviour.KEY -> {}
|
||||
BurstBehaviour.KEY -> {}
|
||||
DolphinBehaviour.KEY -> {}
|
||||
GliderBehaviour.KEY -> {}
|
||||
HelicopterBehaviour.KEY -> {}
|
||||
HorseBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
disableHorizontalMovementKeys = true
|
||||
showSneakKey = false
|
||||
}
|
||||
HoverBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
}
|
||||
BoatBehaviour.KEY -> {}
|
||||
GliderBehaviour.KEY -> {}
|
||||
HelicopterBehaviour.KEY -> {}
|
||||
JetBehaviour.KEY -> {
|
||||
showMovementKeys = false
|
||||
showSneakKey = false
|
||||
showJumpKey = false
|
||||
}
|
||||
MinekartBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
showHorizontalMouse = false
|
||||
showSneakKey = false
|
||||
}
|
||||
RocketBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
showHorizontalMouse = false
|
||||
}
|
||||
BurstBehaviour.KEY -> {}
|
||||
VehicleBehaviour.KEY -> {}
|
||||
HoverBehaviour.KEY -> {
|
||||
showVerticalMouse = false
|
||||
}
|
||||
}
|
||||
|
||||
val centerX = minecraft.window.guiScaledWidth / 2
|
||||
|
||||
@@ -1,29 +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.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.orientation.ClientboundUpdateDriverInputPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.player.RemotePlayer
|
||||
|
||||
object ClientboundUpdateDriverInputHandler : ClientNetworkPacketHandler<ClientboundUpdateDriverInputPacket> {
|
||||
override fun handle(packet: ClientboundUpdateDriverInputPacket, client: Minecraft) {
|
||||
client.executeIfPossible {
|
||||
val level = client.level ?: return@executeIfPossible
|
||||
val entity = level.getEntity(packet.entityId)
|
||||
if (entity is RemotePlayer) {
|
||||
entity.xxa = packet.driverInput.x
|
||||
entity.zza = packet.driverInput.z
|
||||
entity.jumping = packet.driverInput.y == 1.0f
|
||||
entity.isShiftKeyDown = packet.driverInput.y == -1.0f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,6 +758,8 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
yRot = Mth.lerp(state.getPartialTicks(), entity.yBodyRotO, entity.yBodyRot)
|
||||
yRot = 180f - Mth.wrapDegrees(yRot)
|
||||
}
|
||||
//For some reason locators are positioned upside-down so this fixes that
|
||||
matrixStack.mulPose(Axis.ZP.rotationDegrees(180f))
|
||||
} else if (entity is EmptyPokeBallEntity) {
|
||||
scale = 0.7F
|
||||
yRot = Mth.lerp(state.getPartialTicks(), entity.yRot, entity.yRotO)
|
||||
@@ -773,9 +775,6 @@ open class PosableModel(@Transient override val rootPart: Bone) : ModelFrame {
|
||||
matrixStack.scale(scale, scale, scale)
|
||||
matrixStack.mulPose(Axis.YP.rotationDegrees(yRot))
|
||||
|
||||
//For some reason locators are positioned upside-down so this fixes that
|
||||
matrixStack.mulPose(Axis.ZP.rotationDegrees(180f))
|
||||
|
||||
locatorAccess.update(matrixStack, entity, scale, state.locatorStates, isRoot = true)
|
||||
}
|
||||
|
||||
|
||||
@@ -255,36 +255,6 @@ abstract class PosableState : Schedulable {
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("input_right") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.driverInputSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).x
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0) * -1.0)
|
||||
}
|
||||
.addFunction("input_up") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.driverInputSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).y
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
.addFunction("input_forward") { params ->
|
||||
val lookBackTick = params.getInt(0)
|
||||
val pokemon = getEntity() as? PokemonEntity ?: return@addFunction DoubleValue(0.0)
|
||||
|
||||
val partialTickZVel = pokemon.ridingAnimationData.driverInputSpring.getInterpolated(currentPartialTicks.toDouble(), lookBackTick).z
|
||||
|
||||
val topSpeed = 1.0//pokemon.riding.getController(pokemon)?.getStat(pokemon, RidingStat.SPEED)
|
||||
//?: return@addFunction DoubleValue(0.0)
|
||||
return@addFunction DoubleValue((partialTickZVel / topSpeed).coerceIn(-1.0,1.0))
|
||||
}
|
||||
|
||||
|
||||
/** All of the MoLang functions that can be applied to something with this state. */
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.ActiveAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GolurkModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("golurk")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 3.0F
|
||||
override var portraitTranslation = Vec3(-0.3, 5.4, 0.0)
|
||||
|
||||
override var profileScale = 0.4F
|
||||
override var profileTranslation = Vec3(0.0, 1.15, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("golurk", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("golurk", "blink") }
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 20,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("golurk", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 20,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("golurk", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
transformTicks = 20,
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("golurk", "sleep"))
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(state: PosableState): ActiveAnimation? {
|
||||
return if (state.isNotPosedIn(sleep)) bedrockStateful("golurk", "faint") else null
|
||||
}
|
||||
}
|
||||
@@ -405,6 +405,7 @@ object VaryingModelRepository {
|
||||
inbuilt("lombre", :: LombreModel)
|
||||
inbuilt("ludicolo", :: LudicoloModel)
|
||||
inbuilt("golett", :: GolettModel)
|
||||
inbuilt("golurk", :: GolurkModel)
|
||||
inbuilt("stantler", :: StantlerModel)
|
||||
inbuilt("sneasel", :: SneaselModel)
|
||||
inbuilt("weavile", :: WeavileModel)
|
||||
|
||||
@@ -18,6 +18,7 @@ enum class Category(val lang: String) {
|
||||
Pokedex("pokedex"),
|
||||
Storage("storage"),
|
||||
Starter("starter"),
|
||||
System("system"),
|
||||
Interface("interface"),
|
||||
Riding("riding"),
|
||||
Debug("debug"),
|
||||
|
||||
@@ -16,8 +16,11 @@ import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.pokeball.catching.calculators.CobblemonCaptureCalculator
|
||||
import com.cobblemon.mod.common.util.adapters.CaptureCalculatorAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ZoneIdAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
|
||||
@@ -29,6 +32,7 @@ class CobblemonConfig {
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
|
||||
.registerTypeAdapter(CaptureCalculator::class.java, CaptureCalculatorAdapter)
|
||||
.registerTypeHierarchyAdapter(ZoneId::class.java, ZoneIdAdapter)
|
||||
.create()
|
||||
}
|
||||
|
||||
@@ -263,6 +267,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Pokedex, lang = "hide_unimplemented_pokemon_in_the_pokedex")
|
||||
var hideUnimplementedPokemonInThePokedex = false
|
||||
|
||||
@CobblemonConfigField(Category.System, lang = "time_zone_id")
|
||||
var timeZoneId: ZoneId = ZoneOffset.systemDefault()
|
||||
|
||||
@CobblemonConfigField(Category.Interface, lang = "summary_pokemon_follow_cursor")
|
||||
var summaryPokemonFollowCursor = true
|
||||
|
||||
|
||||
@@ -101,16 +101,9 @@ import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolut
|
||||
import com.cobblemon.mod.common.pokemon.feature.StashHandler
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.Dynamic
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
@@ -165,7 +158,10 @@ 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.Vec3
|
||||
import kotlin.math.min
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.ceil
|
||||
|
||||
@Suppress("unused")
|
||||
open class PokemonEntity(
|
||||
@@ -305,7 +301,6 @@ open class PokemonEntity(
|
||||
.also {
|
||||
it.environment.query.addFunction("passenger_count") { DoubleValue(passengers.size.toDouble()) }
|
||||
it.environment.query.addFunction("ride_velocity") { DoubleValue(getRideVelocity().length()) }
|
||||
it.environment.query.addFunction("driver_input") { DoubleValue(min(ridingAnimationData.driverInputSpring.value.length(),1.0)) }
|
||||
it.environment.query.addFunction("get_ride_stats") { params ->
|
||||
val rideStat = RidingStat.valueOf(params.getString(0).uppercase())
|
||||
val rideStyle = RidingStyle.valueOf(params.getString(1).uppercase())
|
||||
@@ -565,12 +560,9 @@ open class PokemonEntity(
|
||||
isPokemonFlying = flyDist - flyDistO > 0.005F
|
||||
isPokemonWalking = walkDist - walkDistO > 0.005F
|
||||
|
||||
if (passengers.isNotEmpty() && level().isClientSide) {
|
||||
if (passengers.isNotEmpty()) {
|
||||
rideSoundManager.tick()
|
||||
ridingAnimationData.update()
|
||||
} else if (!passengers.isNotEmpty() && level().isClientSide)
|
||||
{
|
||||
rideSoundManager.stop()
|
||||
}
|
||||
|
||||
flyDistO = flyDist
|
||||
@@ -1774,8 +1766,8 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
// Rotate velocity vector to face the current y rotation
|
||||
val f = Mth.sin(this.yRot.toRadians())
|
||||
val g = Mth.cos(this.yRot.toRadians())
|
||||
val f = Mth.sin(this.yRot * 0.017453292f)
|
||||
val g = Mth.cos(this.yRot * 0.017453292f)
|
||||
val v = Vec3(
|
||||
inp.x * g.toDouble() - inp.z * f.toDouble(),
|
||||
inp.y,
|
||||
@@ -2136,9 +2128,8 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
this.yRotO = this.yRot
|
||||
val rotation = behaviour.rotation(settings, state, this, driver)
|
||||
|
||||
this.yRotO = this.yRot
|
||||
setRot(rotation.y, rotation.x)
|
||||
this.yHeadRot = this.yRot
|
||||
this.yBodyRot = this.yRot
|
||||
|
||||
@@ -1,48 +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.net.messages.client.orientation
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.ClientboundUpdateRidingStatePacket.Companion.ID
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readMatrix3f
|
||||
import com.cobblemon.mod.common.util.writeMatrix3f
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
|
||||
/**
|
||||
* Packet sent from the server to update the current input from
|
||||
* the driver of a ridden pokemon. This data is needed for client
|
||||
* side animation data updates found in RidingAnimationData
|
||||
*
|
||||
* @author Jackowes
|
||||
* @since August 1st, 2025
|
||||
*/
|
||||
|
||||
class ClientboundUpdateDriverInputPacket internal constructor(
|
||||
val driverInput: Vector3f,
|
||||
val entityId: Int
|
||||
) : NetworkPacket<ClientboundUpdateDriverInputPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeVarInt(entityId)
|
||||
buffer.writeVector3f(driverInput)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("s2c_update_driver_input")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ClientboundUpdateDriverInputPacket {
|
||||
val entityId = buffer.readVarInt()
|
||||
val driverInput = buffer.readVector3f()
|
||||
return ClientboundUpdateDriverInputPacket(driverInput, entityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.messages.server.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class ServerboundUpdateDriverInputPacket internal constructor(
|
||||
val xxa: Float,
|
||||
val zza: Float,
|
||||
val jumping: Boolean,
|
||||
val crouching: Boolean
|
||||
) : NetworkPacket<ServerboundUpdateDriverInputPacket> {
|
||||
override val id = ID
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeFloat(xxa)
|
||||
buffer.writeFloat(zza)
|
||||
buffer.writeBoolean(jumping)
|
||||
buffer.writeBoolean(crouching)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("c2s_update_driver_input")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): ServerboundUpdateDriverInputPacket {
|
||||
val xxa = buffer.readFloat()
|
||||
val zza = buffer.readFloat()
|
||||
val jumping = buffer.readBoolean()
|
||||
val crouching = buffer.readBoolean()
|
||||
return ServerboundUpdateDriverInputPacket(xxa, zza, jumping, crouching)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.riding
|
||||
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.duck.ServerEntityDuck
|
||||
import com.cobblemon.mod.common.mixin.accessor.ChunkMapAccessor
|
||||
import com.cobblemon.mod.common.mixin.accessor.TrackedEntityAccessor
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.sign
|
||||
|
||||
object DriverInputPacketHandler : ServerNetworkPacketHandler<ServerboundUpdateDriverInputPacket> {
|
||||
|
||||
override fun handle(
|
||||
packet: ServerboundUpdateDriverInputPacket,
|
||||
server: MinecraftServer,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
val chunkMap = player.serverLevel().chunkSource.chunkMap
|
||||
val entityMap = (chunkMap as ChunkMapAccessor).entityMap
|
||||
val trackedEntity = entityMap[player.id]
|
||||
if (trackedEntity is TrackedEntityAccessor) {
|
||||
val serverEntity = trackedEntity.getServerEntity()
|
||||
if (serverEntity is ServerEntityDuck) {
|
||||
val vertInput = when {
|
||||
packet.jumping-> 1.0f
|
||||
packet.crouching -> -1.0f
|
||||
else -> 0.0f
|
||||
}
|
||||
val driverInput = Vector3f(packet.xxa.sign, vertInput, packet.zza.sign)
|
||||
serverEntity.setDriverInput(driverInput)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -93,13 +93,7 @@ class SentOutState() : ActivePokemonState() {
|
||||
this.dimension = entity.level().dimension()
|
||||
}
|
||||
|
||||
override fun getIcon(pokemon: Pokemon): ResourceLocation {
|
||||
val isBeingRidden = (pokemon.entity?.countPlayerPassengers() ?: 0) > 0
|
||||
val icon = if (isBeingRidden) "mounted" else "released"
|
||||
|
||||
return cobblemonResource("textures/gui/party/party_icon_${icon}.png")
|
||||
}
|
||||
|
||||
override fun getIcon(pokemon: Pokemon) = cobblemonResource("textures/gui/party/party_icon_released.png")
|
||||
override fun writeToNBT(nbt: CompoundTag) = null
|
||||
override fun writeToJSON(json: JsonObject) = null
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies.
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies.RunStrategy
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.MinekartSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.*
|
||||
@@ -39,19 +37,15 @@ import java.lang.reflect.Type
|
||||
object RidingBehaviourSettingsAdapter : JsonDeserializer<RidingBehaviourSettings?> {
|
||||
val types: MutableMap<ResourceLocation, Class<out RidingBehaviourSettings>> = mutableMapOf(
|
||||
BirdBehaviour.KEY to BirdSettings::class.java,
|
||||
BirdNoRollBehaviour.KEY to BirdNoRollSettings::class.java,
|
||||
DolphinBehaviour.KEY to DolphinSettings::class.java,
|
||||
HorseBehaviour.KEY to HorseSettings::class.java,
|
||||
BoatBehaviour.KEY to BoatSettings::class.java,
|
||||
GliderBehaviour.KEY to GliderSettings::class.java,
|
||||
HelicopterBehaviour.KEY to HelicopterSettings::class.java,
|
||||
JetBehaviour.KEY to JetSettings::class.java,
|
||||
JetNoRollBehaviour.KEY to JetNoRollSettings::class.java,
|
||||
BurstBehaviour.KEY to BurstSettings::class.java,
|
||||
VehicleBehaviour.KEY to VehicleSettings::class.java,
|
||||
MinekartBehaviour.KEY to MinekartSettings::class.java,
|
||||
HoverBehaviour.KEY to HoverSettings::class.java,
|
||||
RocketBehaviour.KEY to RocketSettings::class.java,
|
||||
CompositeBehaviour.KEY to CompositeSettings::class.java,
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import java.lang.reflect.Type
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
|
||||
|
||||
/**
|
||||
* A type adapter for [ZoneOffset]s.
|
||||
* This will never fail to deserialize and will instead default to the System's default time zone and log an error message.
|
||||
*
|
||||
* @author JPAK
|
||||
* @since December 26, 2024
|
||||
*/
|
||||
object ZoneIdAdapter: JsonSerializer<ZoneId>, JsonDeserializer<ZoneId> {
|
||||
override fun serialize(
|
||||
src: ZoneId,
|
||||
typeOfSrc: Type,
|
||||
context: JsonSerializationContext
|
||||
): JsonElement {
|
||||
return JsonPrimitive(src.id)
|
||||
}
|
||||
|
||||
override fun deserialize(
|
||||
json: JsonElement,
|
||||
typeOfT: Type,
|
||||
context: JsonDeserializationContext
|
||||
): ZoneId {
|
||||
return try {
|
||||
ZoneId.of(json.asString)
|
||||
} catch (_: Exception) {
|
||||
Cobblemon.LOGGER.error("Failed to load ZoneId from the ID {}, defaulting to the system time zone", json.asString)
|
||||
ZoneOffset.systemDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [
|
||||
"45*math.clamp(q.riding.velocity_forward(0)* 0.5 + q.riding.input_forward(10), -1.0, 1.0)",
|
||||
"45*q.riding.velocity_forward(0)",
|
||||
"0 - Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 + 45*math.clamp(q.riding.velocity_right(0)* 0.5 + q.riding.input_right(10)* 0.5,-1.0,1.0)"
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 + 45*q.riding.velocity_right(0)"
|
||||
],
|
||||
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
|
||||
},
|
||||
@@ -50,9 +50,9 @@
|
||||
"bones": {
|
||||
"body": {
|
||||
"rotation": [
|
||||
"2.5 + 45*math.clamp(q.riding.velocity_forward(0) + q.riding.input_forward(5),-1.0,1.0)",
|
||||
"2.5 + 45*q.riding.velocity_forward(0)",
|
||||
"- Math.Sin(((q.anim_time + 0.1) * 180 * 0.5) * 1) * 5",
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 - 45*math.clamp(q.riding.velocity_right(0) + q.riding.right(5),-1.0,1.0)"
|
||||
"Math.Sin(((q.anim_time + 0.4) * 180 * 0.5) * 1) * 5 - 45*q.riding.velocity_right(0)"
|
||||
],
|
||||
"position": ["Math.Sin((q.anim_time * 180 * 0.5) * 1) * 1.5", "7+Math.Sin((q.anim_time * 90 * 0.5) * 1) * 1.5", 0]
|
||||
},
|
||||
|
||||
@@ -407,7 +407,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "locator_seat_2",
|
||||
"name": "locator_seat_1",
|
||||
"parent": "body",
|
||||
"pivot": [0, 0, 0],
|
||||
"locators": {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
{
|
||||
"description": {
|
||||
"identifier": "geometry.golurk",
|
||||
"texture_width": 512,
|
||||
"texture_height": 256,
|
||||
"texture_width": 128,
|
||||
"texture_height": 128,
|
||||
"visible_bounds_width": 7,
|
||||
"visible_bounds_height": 7.5,
|
||||
"visible_bounds_offset": [0, 3.25, 0]
|
||||
"visible_bounds_height": 4.5,
|
||||
"visible_bounds_offset": [0, 1.75, 0]
|
||||
},
|
||||
"bones": [
|
||||
{
|
||||
@@ -18,743 +18,342 @@
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "golurk",
|
||||
"pivot": [0, 61, 0]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_pivot",
|
||||
"parent": "body",
|
||||
"pivot": [0, 68.5, 0]
|
||||
"pivot": [0, 38, 0]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "shoulder_pivot",
|
||||
"pivot": [0, 44.5, 0],
|
||||
"parent": "body",
|
||||
"pivot": [0, 21.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-18, 45, -18], "size": [36, 32, 36], "uv": [0, 0]},
|
||||
{"origin": [-18, 51, -18], "size": [36, 24, 7], "inflate": -0.25, "uv": [170, 194]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "chest_glow_red",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 63, -14.5],
|
||||
"cubes": [
|
||||
{"origin": [-18, 51, -18], "size": [36, 24, 7], "inflate": -0.3, "uv": [170, 225]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "chest_glow_off",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 63, -14.5],
|
||||
"cubes": [
|
||||
{"origin": [-18, 51, -18], "size": [36, 24, 7], "inflate": -0.3, "uv": [170, 163]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "waist",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 45.25, 0]
|
||||
},
|
||||
{
|
||||
"name": "skirt",
|
||||
"parent": "waist",
|
||||
"pivot": [0, 45.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [-14, 41, -14], "size": [28, 8, 28], "uv": [0, 96]},
|
||||
{"origin": [-14, 41, -0.5], "size": [28, 3, 1], "inflate": 0.01, "pivot": [0, 42.5, 0], "rotation": [0, -90, 0], "uv": [109, 192]},
|
||||
{"origin": [-14, 41, -0.5], "size": [28, 3, 1], "inflate": 0.01, "uv": [109, 197]},
|
||||
{"origin": [-17, 34, -17], "size": [34, 7, 34], "uv": [0, 212]},
|
||||
{"origin": [-17, 34, -0.5], "size": [34, 7, 1], "inflate": 0.01, "pivot": [0, 37.5, 0], "rotation": [0, -90, 0], "uv": [177, 145]},
|
||||
{"origin": [-17, 34, -0.5], "size": [34, 7, 1], "inflate": 0.01, "uv": [177, 154]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_base",
|
||||
"parent": "skirt",
|
||||
"pivot": [0, 34.05, 0],
|
||||
"cubes": [
|
||||
{"origin": [-12, 34.05, -12], "size": [24, 0, 24], "uv": [244, 1]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist",
|
||||
"parent": "skirt",
|
||||
"pivot": [0, 38.25, 0]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_interior",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [0, 38.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [-16, 4.25, 0], "size": [32, 34, 0], "pivot": [0, 32.25, 0], "rotation": [0, 45, 0], "uv": [447, 35]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_interior2",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [0, 38.25, 0],
|
||||
"cubes": [
|
||||
{"origin": [0, 4.25, -16], "size": [0, 34, 32], "pivot": [0, 32.25, 0], "rotation": [0, 45, 0], "uv": [447, -31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_front",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [0, 34, -12],
|
||||
"rotation": [-10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-16, 8.25, -12], "size": [32, 30, 0], "uv": [317, 1]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_back",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [0, 34, 12],
|
||||
"rotation": [10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-16, 8.25, 12], "size": [32, 30, 0], "uv": [317, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_right",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [-12, 34, 0],
|
||||
"rotation": [0, 0, 10],
|
||||
"cubes": [
|
||||
{"origin": [-12, 8.25, -16], "size": [0, 30, 32], "uv": [382, -31]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_waist_left",
|
||||
"parent": "fire_waist",
|
||||
"pivot": [12, 34, 0],
|
||||
"rotation": [0, 0, -10],
|
||||
"cubes": [
|
||||
{"origin": [12, 8.25, -16], "size": [0, 30, 32], "uv": [382, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bandage",
|
||||
"parent": "torso",
|
||||
"pivot": [-3.8, 64.6, -19],
|
||||
"rotation": [0, 0, 45],
|
||||
"cubes": [
|
||||
{"origin": [-11.8, 60.6, -20], "size": [16, 8, 2], "uv": [119, 132]}
|
||||
{"origin": [-9, 19, -9], "size": [18, 5, 18], "uv": [0, 40]},
|
||||
{"origin": [-7.5, 24, -7.5], "size": [15, 2, 15], "uv": [54, 40]},
|
||||
{"origin": [-10, 26, -10], "size": [20, 20, 20], "uv": [0, 0]},
|
||||
{"origin": [-8, 33, -11], "size": [11, 5, 1], "pivot": [-1.5, 35.5, -10.5], "rotation": [0, 0, 45], "uv": [98, 11]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "head",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 76, 0],
|
||||
"pivot": [0.5, 46, 0.5],
|
||||
"cubes": [
|
||||
{"origin": [-5, 74, -5], "size": [10, 10, 10], "uv": [136, 142]},
|
||||
{"origin": [-1.5, 82, -1], "size": [4, 5, 2], "pivot": [1, 84.5, 0.5], "rotation": [0, 0, 10], "uv": [19, 20]},
|
||||
{"origin": [-5.5, 84, 0], "size": [4, 3, 0], "pivot": [1, 84.5, 0.5], "rotation": [0, 0, 10], "uv": [26, 27]}
|
||||
{"origin": [-3, 44.75, -3], "size": [6, 6, 6], "uv": [83, 99]},
|
||||
{"origin": [-4.5, 49.5, 0.5], "size": [6, 5, 0], "pivot": [1, 50.5, 0.5], "rotation": [0, 0, 10], "uv": [47, 63]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes",
|
||||
"name": "eye_left",
|
||||
"parent": "head",
|
||||
"pivot": [0, 80, -5.01]
|
||||
"pivot": [1.4, 47.5, -2.51],
|
||||
"cubes": [
|
||||
{"origin": [0.65, 46.5, -3.01], "size": [1, 3, 1], "uv": [15, 12]},
|
||||
{"origin": [1.15, 46.5, -3.01], "size": [1, 1, 1], "uv": [4, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_left",
|
||||
"parent": "eyes",
|
||||
"pivot": [2, 80, -5.01],
|
||||
"name": "eyelid_left",
|
||||
"parent": "eye_left",
|
||||
"pivot": [1.4, 47.5, -2.41],
|
||||
"cubes": [
|
||||
{"origin": [1, 78, -5.01], "size": [2, 4, 0], "uv": [32, 0]},
|
||||
{"origin": [3, 78, -5.01], "size": [1, 2, 0], "uv": [24, 2]}
|
||||
{"origin": [0.65, 46.5, -2.91], "size": [1, 3, 1], "inflate": 0.001, "uv": [15, 0]},
|
||||
{"origin": [1.15, 46.5, -2.91], "size": [1, 1, 1], "inflate": 0.001, "uv": [0, 18]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_right",
|
||||
"parent": "eyes",
|
||||
"pivot": [-2, 80, -5.01],
|
||||
"cubes": [
|
||||
{"origin": [-3, 78, -5.01], "size": [2, 4, 0], "uv": [28, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes_red",
|
||||
"parent": "head",
|
||||
"pivot": [0, 80, -4.91]
|
||||
},
|
||||
{
|
||||
"name": "eye_red_left",
|
||||
"parent": "eyes_red",
|
||||
"pivot": [2, 80, -4.91],
|
||||
"pivot": [-1.65, 48.25, -2.51],
|
||||
"cubes": [
|
||||
{"origin": [1, 78, -4.91], "size": [2, 4, 0], "uv": [32, 4]},
|
||||
{"origin": [3, 78, -4.91], "size": [1, 2, 0], "uv": [2, 2]}
|
||||
{"origin": [-1.65, 46.5, -3.01], "size": [1, 3, 1], "uv": [0, 12]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_red_right",
|
||||
"parent": "eyes_red",
|
||||
"pivot": [-2, 80, -4.91],
|
||||
"name": "eyelid_right",
|
||||
"parent": "eye_right",
|
||||
"pivot": [-1.15, 48, -2.41],
|
||||
"cubes": [
|
||||
{"origin": [-3, 78, -4.91], "size": [2, 4, 0], "uv": [28, 4]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes_off",
|
||||
"parent": "head",
|
||||
"pivot": [0, 80, -4.91]
|
||||
},
|
||||
{
|
||||
"name": "eye_off_left",
|
||||
"parent": "eyes_off",
|
||||
"pivot": [2, 80, -4.91],
|
||||
"cubes": [
|
||||
{"origin": [1, 78, -4.91], "size": [2, 4, 0], "uv": [32, 8]},
|
||||
{"origin": [3, 78, -4.91], "size": [1, 2, 0], "uv": [2, 22]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eye_off_right",
|
||||
"parent": "eyes_off",
|
||||
"pivot": [-2, 80, -4.91],
|
||||
"cubes": [
|
||||
{"origin": [-3, 78, -4.91], "size": [2, 4, 0], "uv": [28, 8]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_left",
|
||||
"parent": "torso",
|
||||
"pivot": [25.6, 67, 0],
|
||||
"cubes": [
|
||||
{"origin": [19.1, 76.4, -2.5], "size": [9, 5, 5], "pivot": [25.6, 68.4, 0], "rotation": [0, 0, 45], "uv": [102, 236]},
|
||||
{"origin": [22.1, 81.4, -2.5], "size": [6, 5, 5], "pivot": [25.6, 68.4, 0], "rotation": [0, 0, 45], "uv": [177, 132]},
|
||||
{"origin": [16.1, 59.4, -8.5], "size": [17, 17, 17], "pivot": [25.6, 68.4, 0], "rotation": [0, 0, 45], "uv": [68, 132]},
|
||||
{"origin": [19.1, 62.4, -10.5], "size": [11, 11, 2], "pivot": [25.6, 68.4, -2], "rotation": [0, 0, 45], "uv": [0, 109]},
|
||||
{"origin": [19.1, 62.4, 8.5], "size": [11, 11, 2], "pivot": [25.6, 68.4, 17], "rotation": [0, 0, 45], "uv": [46, 191]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_glow_red_left",
|
||||
"parent": "shoulder_left",
|
||||
"pivot": [25.6, 68.4, -10.4],
|
||||
"cubes": [
|
||||
{"origin": [20.1, 63.4, -10.41], "size": [9, 9, 0], "pivot": [25.6, 68.4, -1.9], "rotation": [0, 0, 45], "uv": [200, 122]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_glow_off_left",
|
||||
"parent": "shoulder_left",
|
||||
"pivot": [25.6, 68.4, -10.4],
|
||||
"cubes": [
|
||||
{"origin": [20.1, 63.4, -10.41], "size": [9, 9, 0], "pivot": [25.6, 68.4, -1.9], "rotation": [0, 0, 45], "uv": [200, 131]}
|
||||
{"origin": [-1.65, 46.5, -2.91], "size": [1, 3, 1], "inflate": 0.001, "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
"parent": "shoulder_left",
|
||||
"pivot": [24.1, 59.4, 0],
|
||||
"cubes": [
|
||||
{"origin": [20.1, 50.4, -3], "size": [8, 14, 6], "uv": [108, 0]}
|
||||
]
|
||||
"parent": "torso",
|
||||
"pivot": [13.6, 44, 0]
|
||||
},
|
||||
{
|
||||
"name": "forearm_left",
|
||||
"name": "arm_left2",
|
||||
"parent": "arm_left",
|
||||
"pivot": [24.1, 52.4, 0],
|
||||
"pivot": [16.1, 43.9, 0],
|
||||
"cubes": [
|
||||
{"origin": [16.6, 47.4, -8], "size": [15, 5, 16], "uv": [62, 191]},
|
||||
{"origin": [13.6, 39.9, -10], "size": [21, 8, 20], "uv": [0, 68]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_base_left",
|
||||
"parent": "forearm_left",
|
||||
"pivot": [24.1, 39.95, 0],
|
||||
"cubes": [
|
||||
{"origin": [16.1, 39.95, -8], "size": [16, 0, 16], "uv": [326, 124], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_left",
|
||||
"parent": "forearm_left",
|
||||
"pivot": [24.1, 42.15, 0]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_interior_left1",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [24.1, 44.15, 0],
|
||||
"cubes": [
|
||||
{"origin": [12.6, 17.15, 0], "size": [23, 25, 0], "pivot": [24.1, 38.15, 0], "rotation": [0, -45, 0], "uv": [465, 150], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_interior_left2",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [24.1, 44.15, 0],
|
||||
"cubes": [
|
||||
{"origin": [24.1, 17.15, -11.5], "size": [0, 25, 23], "pivot": [24.1, 38.15, 0], "rotation": [0, -45, 0], "uv": [465, 101], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_front_left",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [24.1, 39.9, -8],
|
||||
"rotation": [-10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [13.1, 20.15, -8], "size": [22, 22, 0], "uv": [375, 124], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_back_left",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [24.1, 39.9, 8],
|
||||
"rotation": [10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [13.1, 20.15, 8], "size": [22, 22, 0], "uv": [375, 147], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_outer_left",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [32.1, 39.9, 0],
|
||||
"rotation": [0, 0, -10],
|
||||
"cubes": [
|
||||
{"origin": [32.1, 20.15, -11], "size": [0, 22, 22], "uv": [420, 102], "mirror": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_inner_left",
|
||||
"parent": "fire_hand_left",
|
||||
"pivot": [16.1, 39.9, 0],
|
||||
"rotation": [0, 0, 10],
|
||||
"cubes": [
|
||||
{"origin": [16.1, 20.15, -11], "size": [0, 22, 22], "uv": [420, 125], "mirror": true}
|
||||
{"origin": [11.1, 40.9, 4.5], "size": [7, 7, 2], "pivot": [13.6, 45.4, -1], "rotation": [0, 0, 45], "uv": [107, 17]},
|
||||
{"origin": [4.6, 41.4, -2.5], "size": [5, 5, 5], "pivot": [13.6, 45.4, 0], "rotation": [0, 0, 45], "uv": [102, 106]},
|
||||
{"origin": [11.1, 40.9, -6.5], "size": [7, 7, 2], "pivot": [13.6, 45.4, -1], "rotation": [0, 0, 45], "uv": [29, 63]},
|
||||
{"origin": [9.6, 39.4, -4.5], "size": [10, 10, 9], "pivot": [13.6, 45.4, 0], "rotation": [0, 0, 45], "uv": [0, 63]},
|
||||
{"origin": [16.6, 41.4, -2.5], "size": [9, 5, 5], "uv": [99, 42]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_left",
|
||||
"parent": "forearm_left",
|
||||
"pivot": [24.1, 39.9, 0],
|
||||
"parent": "arm_left2",
|
||||
"pivot": [24.85, 44, 0],
|
||||
"cubes": [
|
||||
{"origin": [19.6, 27.9, -8], "size": [9, 12, 16], "inflate": 0.02, "uv": [186, 0]},
|
||||
{"origin": [27.6, 28.9, -3.3], "size": [3, 9, 9], "pivot": [26.1, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [102, 218]}
|
||||
{"origin": [26.6, 38.4, -5.5], "size": [5, 11, 11], "uv": [38, 68]},
|
||||
{"origin": [23.6, 39.4, -4.5], "size": [3, 9, 9], "uv": [0, 96]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_glow_red_left",
|
||||
"name": "hand_left2",
|
||||
"parent": "hand_left",
|
||||
"pivot": [30.5, 34.9, 0.7],
|
||||
"pivot": [31.85, 42.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [30.51, 29.9, -2.3], "size": [0, 7, 7], "pivot": [26, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [238, 99]}
|
||||
{"origin": [32.25, 46.9, -2.75], "size": [5, 1, 5], "pivot": [34.5, 47.4, 0], "rotation": [0, -45, 0], "uv": [101, 99]},
|
||||
{"origin": [31.1, 40.9, -4.5], "size": [7, 6, 9], "uv": [27, 90]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_glow_off_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [30.5, 34.9, 0.7],
|
||||
"name": "finger_left",
|
||||
"parent": "hand_left2",
|
||||
"pivot": [38.1, 46.4, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [30.51, 29.9, -2.3], "size": [0, 7, 7], "pivot": [26, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [238, 106]}
|
||||
{"origin": [38.1, 44.4, -4.5], "size": [3, 2, 2], "inflate": 0.001, "uv": [92, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_thumb_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [19.6, 34.9, -8],
|
||||
"rotation": [-12.5, 0, 25],
|
||||
"name": "finger_left2",
|
||||
"parent": "finger_left",
|
||||
"pivot": [41.1, 46.4, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [16.6, 29.9, -10.5], "size": [6, 9, 7], "uv": [108, 20]}
|
||||
{"origin": [41.1, 44.4, -4.5], "size": [2, 2, 2], "uv": [60, 94]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_thumb_left2",
|
||||
"parent": "finger_thumb_left",
|
||||
"pivot": [19.1, 29.9, -10.5],
|
||||
"name": "finger_left3",
|
||||
"parent": "hand_left2",
|
||||
"pivot": [38.1, 46.4, -1.25],
|
||||
"cubes": [
|
||||
{"origin": [17.1, 23.9, -10.5], "size": [5, 6, 5], "uv": [0, 68]}
|
||||
{"origin": [38.1, 44.4, -2.25], "size": [3, 2, 2], "inflate": 0.001, "uv": [86, 84]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_index_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [26.6, 27.9, -6],
|
||||
"name": "finger_left4",
|
||||
"parent": "finger_left3",
|
||||
"pivot": [41.1, 46.4, -1.25],
|
||||
"cubes": [
|
||||
{"origin": [21.6, 21.9, -8], "size": [6, 6, 4], "inflate": 0.015, "uv": [132, 122]}
|
||||
{"origin": [41.1, 44.4, -2.25], "size": [3, 2, 2], "uv": [27, 86]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_index_left2",
|
||||
"parent": "finger_index_left",
|
||||
"pivot": [27.1, 21.9, -6],
|
||||
"name": "finger_left5",
|
||||
"parent": "hand_left2",
|
||||
"pivot": [38.1, 46.4, 1],
|
||||
"cubes": [
|
||||
{"origin": [22.1, 15.9, -8], "size": [5, 6, 4], "uv": [154, 96]}
|
||||
{"origin": [38.1, 44.4, 0], "size": [3, 2, 2], "inflate": 0.001, "uv": [27, 82]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_middle_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [26.6, 27.9, -2],
|
||||
"name": "finger_left6",
|
||||
"parent": "finger_left5",
|
||||
"pivot": [41.1, 46.4, 1],
|
||||
"cubes": [
|
||||
{"origin": [21.6, 21.9, -4], "size": [6, 6, 4], "inflate": 0.01, "uv": [221, 29]}
|
||||
{"origin": [41.1, 44.4, 0], "size": [2, 2, 2], "uv": [90, 36]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_middle_left2",
|
||||
"parent": "finger_middle_left",
|
||||
"pivot": [27.1, 21.9, -2],
|
||||
"name": "finger_left7",
|
||||
"parent": "hand_left2",
|
||||
"pivot": [38.1, 46.4, 3.25],
|
||||
"cubes": [
|
||||
{"origin": [22.1, 15.9, -4], "size": [5, 6, 4], "uv": [62, 78]}
|
||||
{"origin": [38.1, 44.4, 2.25], "size": [2, 2, 2], "inflate": 0.001, "uv": [0, 86]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_ring_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [26.6, 27.9, 2],
|
||||
"name": "finger_left8",
|
||||
"parent": "finger_left7",
|
||||
"pivot": [40.1, 46.4, 3.25],
|
||||
"cubes": [
|
||||
{"origin": [21.6, 21.9, 0], "size": [6, 6, 4], "inflate": 0.015, "uv": [172, 122]}
|
||||
{"origin": [40.1, 44.4, 2.25], "size": [2, 2, 2], "uv": [0, 82]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_ring_left2",
|
||||
"parent": "finger_ring_left",
|
||||
"pivot": [27.1, 21.9, 2],
|
||||
"name": "finger_left9",
|
||||
"parent": "hand_left2",
|
||||
"pivot": [35.6, 43.15, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [22.1, 15.9, 0], "size": [5, 6, 4], "uv": [62, 68]}
|
||||
{"origin": [35.1, 41.65, -5.5], "size": [3, 3, 3], "inflate": 0.001, "uv": [50, 90]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_pinky_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [26.6, 27.9, 6],
|
||||
"name": "finger_left10",
|
||||
"parent": "finger_left9",
|
||||
"pivot": [38.1, 43.15, -5.5],
|
||||
"cubes": [
|
||||
{"origin": [21.6, 21.9, 4], "size": [6, 6, 4], "inflate": 0.01, "uv": [226, 96]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_pinky_left2",
|
||||
"parent": "finger_pinky_left",
|
||||
"pivot": [27.1, 21.9, 6],
|
||||
"cubes": [
|
||||
{"origin": [22.1, 16.9, 4], "size": [5, 5, 4], "uv": [2, 79]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_fire_left",
|
||||
"parent": "forearm_left",
|
||||
"pivot": [24, 40.25, 0]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-25.6, 67, 0],
|
||||
"cubes": [
|
||||
{"origin": [-28.1, 76.4, -2.5], "size": [9, 5, 5], "pivot": [-25.6, 68.4, 0], "rotation": [0, 0, -45], "uv": [0, 236]},
|
||||
{"origin": [-28.1, 81.4, -2.5], "size": [6, 5, 5], "pivot": [-25.6, 68.4, 0], "rotation": [0, 0, -45], "uv": [155, 132]},
|
||||
{"origin": [-33.1, 59.4, -8.5], "size": [17, 17, 17], "pivot": [-25.6, 68.4, 0], "rotation": [0, 0, -45], "uv": [0, 132]},
|
||||
{"origin": [-30.1, 62.4, -10.5], "size": [11, 11, 2], "pivot": [-25.6, 68.4, -2], "rotation": [0, 0, -45], "uv": [0, 96]},
|
||||
{"origin": [-30.1, 62.4, 8.5], "size": [11, 11, 2], "pivot": [-25.6, 68.4, 17], "rotation": [0, 0, -45], "uv": [51, 132]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_glow_red_right",
|
||||
"parent": "shoulder_right",
|
||||
"pivot": [-25.6, 68.4, -10.4],
|
||||
"cubes": [
|
||||
{"origin": [-29.1, 63.4, -10.41], "size": [9, 9, 0], "pivot": [-25.6, 68.4, -1.9], "rotation": [0, 0, -45], "uv": [218, 122]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoulder_glow_off_right",
|
||||
"parent": "shoulder_right",
|
||||
"pivot": [-25.6, 68.4, -10.4],
|
||||
"cubes": [
|
||||
{"origin": [-29.1, 63.4, -10.41], "size": [9, 9, 0], "pivot": [-25.6, 68.4, -1.9], "rotation": [0, 0, -45], "uv": [218, 131]}
|
||||
{"origin": [38.1, 41.65, -5.5], "size": [3, 3, 3], "uv": [89, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arm_right",
|
||||
"parent": "shoulder_right",
|
||||
"pivot": [-24.1, 59.4, 0],
|
||||
"cubes": [
|
||||
{"origin": [-28.1, 50.4, -3], "size": [8, 14, 6], "uv": [0, 0]}
|
||||
]
|
||||
"parent": "torso",
|
||||
"pivot": [-13.6, 44, 0]
|
||||
},
|
||||
{
|
||||
"name": "forearm_right",
|
||||
"name": "arm_right2",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-24.1, 52.4, 0],
|
||||
"pivot": [-16.1, 43.9, 0],
|
||||
"cubes": [
|
||||
{"origin": [-31.6, 47.4, -8], "size": [15, 5, 16], "uv": [0, 191]},
|
||||
{"origin": [-34.6, 39.9, -10], "size": [21, 8, 20], "uv": [82, 68]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_base_right",
|
||||
"parent": "forearm_right",
|
||||
"pivot": [-24.1, 39.95, 0],
|
||||
"cubes": [
|
||||
{"origin": [-32.1, 39.95, -8], "size": [16, 0, 16], "uv": [326, 71]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_right",
|
||||
"parent": "forearm_right",
|
||||
"pivot": [-24.1, 42.15, 0]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_interior_right1",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-24.1, 44.15, 0],
|
||||
"cubes": [
|
||||
{"origin": [-35.6, 17.15, 0], "size": [23, 25, 0], "pivot": [-24.1, 38.15, 0], "rotation": [0, 45, 0], "uv": [465, 97]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_interior_right2",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-24.1, 44.15, 0],
|
||||
"cubes": [
|
||||
{"origin": [-24.1, 17.15, -11.5], "size": [0, 25, 23], "pivot": [-24.1, 38.15, 0], "rotation": [0, 45, 0], "uv": [465, 48]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_front_right",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-24.1, 39.9, -8],
|
||||
"rotation": [-10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-35.1, 20.15, -8], "size": [22, 22, 0], "uv": [375, 71]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_back_right",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-24.1, 39.9, 8],
|
||||
"rotation": [10, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-35.1, 20.15, 8], "size": [22, 22, 0], "uv": [375, 94]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_outer_right",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-32.1, 39.9, 0],
|
||||
"rotation": [0, 0, 10],
|
||||
"cubes": [
|
||||
{"origin": [-32.1, 20.15, -11], "size": [0, 22, 22], "uv": [420, 49]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire_hand_inner_right",
|
||||
"parent": "fire_hand_right",
|
||||
"pivot": [-16.1, 39.9, 0],
|
||||
"rotation": [0, 0, -10],
|
||||
"cubes": [
|
||||
{"origin": [-16.1, 20.15, -11], "size": [0, 22, 22], "uv": [420, 72]}
|
||||
{"origin": [-25.6, 41.4, -2.5], "size": [9, 5, 5], "uv": [99, 32]},
|
||||
{"origin": [-19.6, 39.4, -4.5], "size": [10, 10, 9], "pivot": [-13.6, 45.4, 0], "rotation": [0, 0, -45], "uv": [60, 0]},
|
||||
{"origin": [-18.1, 40.9, -6.5], "size": [7, 7, 2], "pivot": [-13.6, 45.4, -1], "rotation": [0, 0, -45], "uv": [0, 40]},
|
||||
{"origin": [-9.6, 41.4, -2.5], "size": [5, 5, 5], "pivot": [-13.6, 45.4, 0], "rotation": [0, 0, -45], "uv": [44, 105]},
|
||||
{"origin": [-18.1, 40.9, 4.5], "size": [7, 7, 2], "pivot": [-13.6, 45.4, -1], "rotation": [0, 0, -45], "uv": [0, 49]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_right",
|
||||
"parent": "forearm_right",
|
||||
"pivot": [-24.1, 39.9, 0],
|
||||
"parent": "arm_right2",
|
||||
"pivot": [-24.85, 44, 0],
|
||||
"cubes": [
|
||||
{"origin": [-28.6, 27.9, -8], "size": [9, 12, 16], "inflate": 0.02, "uv": [136, 0]},
|
||||
{"origin": [-30.6, 28.9, -3.3], "size": [3, 9, 9], "pivot": [-26.1, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [0, 218]}
|
||||
{"origin": [-31.6, 38.4, -5.5], "size": [5, 11, 11], "uv": [61, 57]},
|
||||
{"origin": [-26.6, 39.4, -4.5], "size": [3, 9, 9], "uv": [59, 92]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_glow_red_right",
|
||||
"name": "hand_right2",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-30.5, 34.9, 0.7],
|
||||
"pivot": [-31.85, 42.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-30.51, 29.9, -2.3], "size": [0, 7, 7], "pivot": [-26, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [224, 99]}
|
||||
{"origin": [-37.25, 46.9, -2.75], "size": [5, 1, 5], "pivot": [-34.5, 47.4, 0], "rotation": [0, 45, 0], "uv": [0, 12]},
|
||||
{"origin": [-38.1, 40.9, -4.5], "size": [7, 6, 9], "uv": [88, 84]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_glow_off_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-30.5, 34.9, 0.7],
|
||||
"name": "finger_right",
|
||||
"parent": "hand_right2",
|
||||
"pivot": [-38.1, 46.4, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-30.51, 29.9, -2.3], "size": [0, 7, 7], "pivot": [-26, 34.9, 0.7], "rotation": [-45, 0, 0], "uv": [224, 106]}
|
||||
{"origin": [-41.1, 44.4, -4.5], "size": [3, 2, 2], "inflate": 0.001, "uv": [80, 23]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_thumb_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-19.6, 34.9, -8],
|
||||
"rotation": [-12.5, 0, -25],
|
||||
"name": "finger_right2",
|
||||
"parent": "finger_right",
|
||||
"pivot": [-41.1, 46.4, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-22.6, 29.9, -10.5], "size": [6, 9, 7], "uv": [0, 20]}
|
||||
{"origin": [-43.1, 44.4, -4.5], "size": [2, 2, 2], "uv": [0, 67]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_thumb_right2",
|
||||
"parent": "finger_thumb_right",
|
||||
"pivot": [-19.1, 29.9, -10.5],
|
||||
"name": "finger_right3",
|
||||
"parent": "hand_right2",
|
||||
"pivot": [-38.1, 46.4, -1.25],
|
||||
"cubes": [
|
||||
{"origin": [-22.1, 23.9, -10.5], "size": [5, 6, 5], "uv": [82, 68]}
|
||||
{"origin": [-41.1, 44.4, -2.25], "size": [3, 2, 2], "inflate": 0.001, "uv": [80, 19]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_index_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-26.6, 27.9, -6],
|
||||
"name": "finger_right4",
|
||||
"parent": "finger_right3",
|
||||
"pivot": [-41.1, 46.4, -1.25],
|
||||
"cubes": [
|
||||
{"origin": [-27.6, 21.9, -8], "size": [6, 6, 4], "inflate": 0.015, "uv": [112, 122]}
|
||||
{"origin": [-44.1, 44.4, -2.25], "size": [3, 2, 2], "uv": [38, 72]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_index_right2",
|
||||
"parent": "finger_index_right",
|
||||
"pivot": [-27.1, 21.9, -6],
|
||||
"name": "finger_right5",
|
||||
"parent": "hand_right2",
|
||||
"pivot": [-38.1, 46.4, 1],
|
||||
"cubes": [
|
||||
{"origin": [-27.1, 15.9, -8], "size": [5, 6, 4], "uv": [136, 96]}
|
||||
{"origin": [-41.1, 44.4, 0], "size": [3, 2, 2], "inflate": 0.001, "uv": [59, 63]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_middle_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-26.6, 27.9, -2],
|
||||
"name": "finger_right6",
|
||||
"parent": "finger_right5",
|
||||
"pivot": [-41.1, 46.4, 1],
|
||||
"cubes": [
|
||||
{"origin": [-27.6, 21.9, -4], "size": [6, 6, 4], "inflate": 0.01, "uv": [177, 29]}
|
||||
{"origin": [-43.1, 44.4, 0], "size": [2, 2, 2], "uv": [0, 63]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_middle_right2",
|
||||
"parent": "finger_middle_right",
|
||||
"pivot": [-27.1, 21.9, -2],
|
||||
"name": "finger_right7",
|
||||
"parent": "hand_right2",
|
||||
"pivot": [-38.1, 46.4, 3.25],
|
||||
"cubes": [
|
||||
{"origin": [-27.1, 15.9, -4], "size": [5, 6, 4], "uv": [144, 78]}
|
||||
{"origin": [-40.1, 44.4, 2.25], "size": [2, 2, 2], "inflate": 0.001, "uv": [60, 4]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_ring_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-26.6, 27.9, 2],
|
||||
"name": "finger_right8",
|
||||
"parent": "finger_right7",
|
||||
"pivot": [-40.1, 46.4, 3.25],
|
||||
"cubes": [
|
||||
{"origin": [-27.6, 21.9, 0], "size": [6, 6, 4], "inflate": 0.015, "uv": [152, 122]}
|
||||
{"origin": [-42.1, 44.4, 2.25], "size": [2, 2, 2], "uv": [60, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_ring_right2",
|
||||
"parent": "finger_ring_right",
|
||||
"pivot": [-27.1, 21.9, 2],
|
||||
"name": "finger_right9",
|
||||
"parent": "hand_right2",
|
||||
"pivot": [-35.6, 43.15, -3.5],
|
||||
"cubes": [
|
||||
{"origin": [-27.1, 15.9, 0], "size": [5, 6, 4], "uv": [144, 68]}
|
||||
{"origin": [-38.1, 41.65, -5.5], "size": [3, 3, 3], "inflate": 0.001, "uv": [80, 32]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_pinky_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-26.6, 27.9, 6],
|
||||
"name": "finger_right10",
|
||||
"parent": "finger_right9",
|
||||
"pivot": [-38.1, 43.15, -5.5],
|
||||
"cubes": [
|
||||
{"origin": [-27.6, 21.9, 4], "size": [6, 6, 4], "inflate": 0.01, "uv": [206, 96]}
|
||||
{"origin": [-41.1, 41.65, -5.5], "size": [3, 3, 3], "uv": [54, 49]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_pinky_right2",
|
||||
"parent": "finger_pinky_right",
|
||||
"pivot": [-27.1, 21.9, 6],
|
||||
"cubes": [
|
||||
{"origin": [-27.1, 16.9, 4], "size": [5, 5, 4], "uv": [84, 79]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_fire_right",
|
||||
"parent": "forearm_right",
|
||||
"pivot": [-24, 40.25, 0]
|
||||
},
|
||||
{
|
||||
"name": "seat_1_locator",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 77, 9],
|
||||
"locators": {
|
||||
"seat_1": [0, 77, 10]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seat_2_locator",
|
||||
"parent": "torso",
|
||||
"pivot": [-14, 77, 13],
|
||||
"locators": {
|
||||
"seat_2": [-14, 77, 13]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seat_3_locator",
|
||||
"parent": "torso",
|
||||
"pivot": [14, 77, 13],
|
||||
"locators": {
|
||||
"seat_3": [14, 77, 13]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "legs",
|
||||
"parent": "shoulder_pivot",
|
||||
"pivot": [0, 37, 0]
|
||||
},
|
||||
{
|
||||
"name": "leg_left",
|
||||
"parent": "legs",
|
||||
"pivot": [9.5, 37, 0],
|
||||
"parent": "body",
|
||||
"pivot": [5, 20, 0],
|
||||
"cubes": [
|
||||
{"origin": [4, 27, -5.5], "size": [11, 11, 11], "uv": [188, 28]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "knee_left",
|
||||
"parent": "leg_left",
|
||||
"pivot": [9.5, 28, -0.25],
|
||||
"cubes": [
|
||||
{"origin": [6, 23, -3.5], "size": [7, 7, 7], "uv": [172, 50]}
|
||||
{"origin": [2.5, 14, -2.5], "size": [5, 7, 5], "uv": [24, 105]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "leg_left2",
|
||||
"parent": "knee_left",
|
||||
"pivot": [9.5, 22.5, 0],
|
||||
"parent": "leg_left",
|
||||
"pivot": [5, 15, -0.25],
|
||||
"cubes": [
|
||||
{"origin": [3, 16, -6.5], "size": [13, 8, 13], "uv": [201, 56]},
|
||||
{"origin": [0, 8, -8.5], "size": [19, 8, 17], "uv": [72, 166]}
|
||||
{"origin": [3.5, 10, -2.25], "size": [3, 5, 4], "uv": [74, 92]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "foot_left",
|
||||
"parent": "leg_left2",
|
||||
"pivot": [9.5, 8, -2],
|
||||
"pivot": [5, 9.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [1, 0, -9.5], "size": [17, 8, 18], "uv": [154, 96]},
|
||||
{"origin": [1, 0, -14.5], "size": [17, 6, 5], "uv": [208, 85]}
|
||||
{"origin": [1.5, 7, -3.5], "size": [7, 4, 7], "uv": [98, 0]},
|
||||
{"origin": [0.5, 2, -4.5], "size": [9, 5, 9], "uv": [86, 70]},
|
||||
{"origin": [1, 0, -7.5], "size": [8, 2, 11], "uv": [80, 19]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "leg_right",
|
||||
"parent": "legs",
|
||||
"pivot": [-9.5, 37, 0],
|
||||
"parent": "body",
|
||||
"pivot": [-5, 20, 0],
|
||||
"cubes": [
|
||||
{"origin": [-15, 27, -5.5], "size": [11, 11, 11], "uv": [144, 28]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "knee_right",
|
||||
"parent": "leg_right",
|
||||
"pivot": [-9.5, 28, -0.25],
|
||||
"cubes": [
|
||||
{"origin": [-13, 23, -3.5], "size": [7, 7, 7], "uv": [144, 50]}
|
||||
{"origin": [-7.5, 14, -2.5], "size": [5, 7, 5], "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "leg_right2",
|
||||
"parent": "knee_right",
|
||||
"pivot": [-9.5, 22.5, 0],
|
||||
"parent": "leg_right",
|
||||
"pivot": [-5, 15, -0.25],
|
||||
"cubes": [
|
||||
{"origin": [-16, 16, -6.5], "size": [13, 8, 13], "uv": [162, 64]},
|
||||
{"origin": [-19, 8, -8.5], "size": [19, 8, 17], "uv": [0, 166]}
|
||||
{"origin": [-6.5, 10, -2.25], "size": [3, 5, 4], "uv": [54, 40]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "foot_right",
|
||||
"parent": "leg_right2",
|
||||
"pivot": [-9.5, 8, -2],
|
||||
"pivot": [-5, 10.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-18, 0, -9.5], "size": [17, 8, 18], "uv": [84, 96]},
|
||||
{"origin": [-18, 0, -14.5], "size": [17, 6, 5], "uv": [164, 85]}
|
||||
{"origin": [-8.5, 7, -3.5], "size": [7, 4, 7], "uv": [82, 57]},
|
||||
{"origin": [-9.5, 2, -4.5], "size": [9, 5, 9], "uv": [0, 82]},
|
||||
{"origin": [-9, 0, -7.5], "size": [8, 2, 11], "uv": [59, 79]}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -18,32 +18,19 @@
|
||||
{
|
||||
"name": "body",
|
||||
"parent": "cyclizar",
|
||||
"pivot": [0, 11, 3.5]
|
||||
"pivot": [0, 0, 0]
|
||||
},
|
||||
{
|
||||
"name": "hips",
|
||||
"parent": "body",
|
||||
"pivot": [0, 13.4, 5.75]
|
||||
},
|
||||
{
|
||||
"name": "torso",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 13.4, 5.75],
|
||||
"cubes": [
|
||||
{"origin": [-3, 10.75, -4], "size": [6, 7, 11], "inflate": 0.01, "uv": [40, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "seat_1_locator",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 17.75, 2],
|
||||
"locators": {
|
||||
"seat_1": [0, 17.75, 2]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seat",
|
||||
"parent": "torso",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 17.75, 4.5],
|
||||
"rotation": [22.5, 0, 0],
|
||||
"cubes": [
|
||||
@@ -53,8 +40,8 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torso2",
|
||||
"parent": "torso",
|
||||
"name": "torso",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 14, -3.05],
|
||||
"cubes": [
|
||||
{"origin": [-3.5, 10.75, -10.5], "size": [7, 7, 8], "uv": [40, 54]}
|
||||
@@ -62,7 +49,7 @@
|
||||
},
|
||||
{
|
||||
"name": "neck",
|
||||
"parent": "torso2",
|
||||
"parent": "torso",
|
||||
"pivot": [0, 14, -9.35],
|
||||
"rotation": [82.5, 0, 0],
|
||||
"cubes": [
|
||||
@@ -247,8 +234,184 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"name": "arm_left",
|
||||
"parent": "torso",
|
||||
"pivot": [3.25, 13.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [1.75, 7.25, -6.75], "size": [3, 8, 4], "uv": [13, 116]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "elbow_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [3.25, 7.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [1.75, 0.55, -6.25], "size": [3, 7, 3], "inflate": 0.25, "uv": [44, 81]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_left",
|
||||
"parent": "elbow_left",
|
||||
"pivot": [3.25, 0.55, -5],
|
||||
"cubes": [
|
||||
{"origin": [1.25, -0.95, -7.75], "size": [4, 3, 4], "inflate": 0.01, "uv": [74, 98]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fingers_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [3.25, 0.05, -7.5]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_left2",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [2, 1.05, -7.75],
|
||||
"rotation": [0, 22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [1, -0.95, -9.25], "size": [1, 2, 3], "uv": [54, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_left3",
|
||||
"parent": "finger_left_left2",
|
||||
"pivot": [1.5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [1.5, -0.95, -11.25], "size": [0, 2, 2], "uv": [36, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [3.25, 0.3, -7],
|
||||
"cubes": [
|
||||
{"origin": [2.25, -0.7, -8.75], "size": [2, 2, 2], "inflate": 0.25, "uv": [108, 33]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left2",
|
||||
"parent": "middle_fingers_left",
|
||||
"pivot": [3.25, 1.53333, -9.01667],
|
||||
"cubes": [
|
||||
{"origin": [2.25, -0.7, -10.25], "size": [2, 2, 1], "inflate": 0.26, "uv": [18, 111]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left3",
|
||||
"parent": "middle_fingers_left2",
|
||||
"pivot": [3.25, 1.05, -10.5],
|
||||
"cubes": [
|
||||
{"origin": [3.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [40, 112]},
|
||||
{"origin": [2.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [112, 41]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_left",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [4.5, 1.05, -7.75],
|
||||
"rotation": [0, -22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [4.5, -0.95, -9.25], "size": [1, 2, 3], "uv": [62, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_left4",
|
||||
"parent": "finger_left_left",
|
||||
"pivot": [5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [5, -0.95, -11.25], "size": [0, 2, 2], "uv": [44, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arm_right",
|
||||
"parent": "torso",
|
||||
"pivot": [-3.25, 13.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [-4.75, 7.25, -6.75], "size": [3, 8, 4], "uv": [29, 116]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "elbow_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-3.25, 7.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [-4.75, 0.55, -6.25], "size": [3, 7, 3], "inflate": 0.25, "uv": [0, 101]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_right",
|
||||
"parent": "elbow_right",
|
||||
"pivot": [-3.25, 0.55, -5],
|
||||
"cubes": [
|
||||
{"origin": [-5.25, -0.95, -7.75], "size": [4, 3, 4], "inflate": 0.01, "uv": [100, 22]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fingers_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-3.25, 0.05, -7.5]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_right2",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-2, 1.05, -7.75],
|
||||
"rotation": [0, -22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, -0.95, -9.25], "size": [1, 2, 3], "uv": [106, 106]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_right3",
|
||||
"parent": "finger_left_right2",
|
||||
"pivot": [-1.5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, -0.95, -11.25], "size": [0, 2, 2], "uv": [119, 93]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-3.25, 0.3, -7],
|
||||
"cubes": [
|
||||
{"origin": [-4.25, -0.7, -8.75], "size": [2, 2, 2], "inflate": 0.25, "uv": [108, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right2",
|
||||
"parent": "middle_fingers_right",
|
||||
"pivot": [-3.25, 1.53333, -9.01667],
|
||||
"cubes": [
|
||||
{"origin": [-4.25, -0.7, -10.25], "size": [2, 2, 1], "inflate": 0.26, "uv": [106, 66]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right3",
|
||||
"parent": "middle_fingers_right2",
|
||||
"pivot": [-3.25, 1.05, -10.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [28, 112]},
|
||||
{"origin": [-2.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [123, 93]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_left",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-4.5, 1.05, -7.75],
|
||||
"rotation": [0, 22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, -0.95, -9.25], "size": [1, 2, 3], "uv": [28, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_left2",
|
||||
"parent": "finger_right_left",
|
||||
"pivot": [-5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [-5, -0.95, -11.25], "size": [0, 2, 2], "uv": [32, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tail",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 14.5, 6.75],
|
||||
"rotation": [17.5, 0, 0],
|
||||
"cubes": [
|
||||
@@ -297,194 +460,13 @@
|
||||
},
|
||||
{
|
||||
"name": "tail_wheel",
|
||||
"parent": "torso",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 14.5, 5.75],
|
||||
"rotation": [7.5, 0, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, 1.5, 1.75], "size": [4, 16, 16], "inflate": 0.02, "uv": [0, 0]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ftorso2",
|
||||
"parent": "hips",
|
||||
"pivot": [0, 14, -3.05]
|
||||
},
|
||||
{
|
||||
"name": "arm_left",
|
||||
"parent": "ftorso2",
|
||||
"pivot": [3.25, 13.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [1.75, 7.25, -6.75], "size": [3, 8, 4], "uv": [13, 116]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "elbow_left",
|
||||
"parent": "arm_left",
|
||||
"pivot": [3.25, 7.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [1.75, 0.55, -6.25], "size": [3, 7, 3], "inflate": 0.25, "uv": [44, 81]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_left",
|
||||
"parent": "elbow_left",
|
||||
"pivot": [3.25, 0.55, -5],
|
||||
"cubes": [
|
||||
{"origin": [1.25, -0.95, -7.75], "size": [4, 3, 4], "inflate": 0.01, "uv": [74, 98]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fingers_left",
|
||||
"parent": "hand_left",
|
||||
"pivot": [3.25, 0.05, -7.5]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_right",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [2, 1.05, -7.75],
|
||||
"rotation": [0, 22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [1, -0.95, -9.25], "size": [1, 2, 3], "uv": [54, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_right2",
|
||||
"parent": "finger_left_right",
|
||||
"pivot": [1.5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [1.5, -0.95, -11.25], "size": [0, 2, 2], "uv": [36, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [3.25, 0.3, -7],
|
||||
"cubes": [
|
||||
{"origin": [2.25, -0.7, -8.75], "size": [2, 2, 2], "inflate": 0.25, "uv": [108, 33]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left2",
|
||||
"parent": "middle_fingers_left",
|
||||
"pivot": [3.25, 1.53333, -9.01667],
|
||||
"cubes": [
|
||||
{"origin": [2.25, -0.7, -10.25], "size": [2, 2, 1], "inflate": 0.26, "uv": [18, 111]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_left3",
|
||||
"parent": "middle_fingers_left2",
|
||||
"pivot": [3.25, 1.05, -10.5],
|
||||
"cubes": [
|
||||
{"origin": [3.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [40, 112]},
|
||||
{"origin": [2.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [112, 41]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_left",
|
||||
"parent": "fingers_left",
|
||||
"pivot": [4.5, 1.05, -7.75],
|
||||
"rotation": [0, -22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [4.5, -0.95, -9.25], "size": [1, 2, 3], "uv": [62, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_left_left2",
|
||||
"parent": "finger_left_left",
|
||||
"pivot": [5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [5, -0.95, -11.25], "size": [0, 2, 2], "uv": [44, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arm_right",
|
||||
"parent": "ftorso2",
|
||||
"pivot": [-3.25, 13.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [-4.75, 7.25, -6.75], "size": [3, 8, 4], "uv": [29, 116]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "elbow_right",
|
||||
"parent": "arm_right",
|
||||
"pivot": [-3.25, 7.05, -4.75],
|
||||
"cubes": [
|
||||
{"origin": [-4.75, 0.55, -6.25], "size": [3, 7, 3], "inflate": 0.25, "uv": [0, 101]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hand_right",
|
||||
"parent": "elbow_right",
|
||||
"pivot": [-3.25, 0.55, -5],
|
||||
"cubes": [
|
||||
{"origin": [-5.25, -0.95, -7.75], "size": [4, 3, 4], "inflate": 0.01, "uv": [100, 22]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fingers_right",
|
||||
"parent": "hand_right",
|
||||
"pivot": [-3.25, 0.05, -7.5]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_left",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-2, 1.05, -7.75],
|
||||
"rotation": [0, -22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-2, -0.95, -9.25], "size": [1, 2, 3], "uv": [106, 106]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_left2",
|
||||
"parent": "finger_right_left",
|
||||
"pivot": [-1.5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [-1.5, -0.95, -11.25], "size": [0, 2, 2], "uv": [119, 93]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-3.25, 0.3, -7],
|
||||
"cubes": [
|
||||
{"origin": [-4.25, -0.7, -8.75], "size": [2, 2, 2], "inflate": 0.25, "uv": [108, 29]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right2",
|
||||
"parent": "middle_fingers_right",
|
||||
"pivot": [-3.25, 1.53333, -9.01667],
|
||||
"cubes": [
|
||||
{"origin": [-4.25, -0.7, -10.25], "size": [2, 2, 1], "inflate": 0.26, "uv": [106, 66]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "middle_fingers_right3",
|
||||
"parent": "middle_fingers_right2",
|
||||
"pivot": [-3.25, 1.05, -10.5],
|
||||
"cubes": [
|
||||
{"origin": [-3.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [28, 112]},
|
||||
{"origin": [-2.75, -0.95, -12.5], "size": [0, 2, 2], "uv": [123, 93]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_right",
|
||||
"parent": "fingers_right",
|
||||
"pivot": [-4.5, 1.05, -7.75],
|
||||
"rotation": [0, 22.5, 0],
|
||||
"cubes": [
|
||||
{"origin": [-5.5, -0.95, -9.25], "size": [1, 2, 3], "uv": [28, 107]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finger_right_right2",
|
||||
"parent": "finger_right_right",
|
||||
"pivot": [-5, 1.05, -9.25],
|
||||
"cubes": [
|
||||
{"origin": [-5, -0.95, -11.25], "size": [0, 2, 2], "uv": [32, 112]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "leg_left_rotate",
|
||||
"parent": "body",
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
{
|
||||
"portraitScale": 1.66,
|
||||
"portraitTranslation": [-0.14, -0.74, 0],
|
||||
"profileScale": 1,
|
||||
"profileTranslation": [0.0, 0.24, 0.0],
|
||||
"rootBone": "golurk",
|
||||
"firstPersonCameraOffset": {
|
||||
"seat_1": [0, 0.25, 0]
|
||||
},
|
||||
"thirdPersonCameraOffset": {
|
||||
"seat_1": [0, 5, 8],
|
||||
"seat_1_reverse": [0, 3, 8]
|
||||
},
|
||||
"animations": {
|
||||
"faint": "q.bedrock_primary('golurk', 'faint', q.curve('one'))",
|
||||
"cry": "q.bedrock_stateful('golurk', 'cry')",
|
||||
"recoil": "q.bedrock_stateful('golurk', 'recoil')"
|
||||
},
|
||||
"poses": {
|
||||
"battle-standing": {
|
||||
"poseTypes": ["STAND"],
|
||||
"isBattle": true,
|
||||
"animations": ["q.look('head')", "q.bedrock('golurk', 'battle_idle')"]
|
||||
},
|
||||
"standing": {
|
||||
"poseTypes": ["STAND", "NONE", "PORTRAIT", "PROFILE"],
|
||||
"isBattle": false,
|
||||
"animations": ["q.look('head')", "q.bedrock('golurk', 'ground_idle')"]
|
||||
},
|
||||
"walk": {
|
||||
"poseName": "walk",
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"condition": "!q.in_air && !q.is_sprinting",
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('golurk', 'ground_walk')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('golurk', 'ride_ground_run')"
|
||||
}
|
||||
],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"run": {
|
||||
"poseName": "run",
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"condition": "!q.in_air && q.is_sprinting",
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('golurk', 'ground_run')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('golurk', 'ride_ground_run')"
|
||||
}
|
||||
],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"hover": {
|
||||
"poseTypes": ["HOVER"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')", "q.bedrock('golurk', 'air_idle')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('golurk', 'ride_air_idle')"
|
||||
}
|
||||
],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"fly": {
|
||||
"poseTypes": ["FLY"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')", "q.bedrock('golurk', 'air_fly')",
|
||||
{
|
||||
"condition": "q.is_ridden",
|
||||
"animation": "q.bedrock('golurk', 'ride_air_fly')"
|
||||
}
|
||||
],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"sleep": {
|
||||
"poseTypes": ["SLEEP"],
|
||||
"animations": ["q.bedrock('golurk', 'sleep')"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +1,41 @@
|
||||
{
|
||||
"portraitScale": 1.5,
|
||||
"portraitTranslation": [0, 0.5, 0],
|
||||
"profileScale": 0.5,
|
||||
"profileTranslation": [0, 0.25, -5],
|
||||
"rootBone": "cyclizar",
|
||||
"firstPersonCameraOffset": {
|
||||
"seat_1": [0, 0.25, 0]
|
||||
},
|
||||
"thirdPersonCameraOffset": {
|
||||
"seat_1": [0, 2.5, 5],
|
||||
"seat_1_reverse": [0, 2.5, 5]
|
||||
},
|
||||
"portraitScale": 1.78,
|
||||
"portraitTranslation": [-0.95,0.48,0],
|
||||
"profileScale": 0.76,
|
||||
"profileTranslation": [0,0.54,0],
|
||||
"animations": {
|
||||
"cry": "q.bedrock_stateful('cyclizar', 'cry')"
|
||||
},
|
||||
"poses": {
|
||||
"portrait": {
|
||||
"poseTypes": ["PORTRAIT", "PROFILE"],
|
||||
"isBattle": false,
|
||||
"animations": ["q.look('head')", "q.bedrock('cyclizar', 'ground_idle')"],
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"]
|
||||
},
|
||||
"ride_jump": {
|
||||
"poseTypes": ["WALK","STAND", "FLOAT", "NONE"],
|
||||
"isBattle": false,
|
||||
"condition": "q.in_air && q.is_ridden",
|
||||
"animations": ["q.look('head')", "q.bedrock('cyclizar', 'ride_jump')"],
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"standing": {
|
||||
"poseTypes": ["STAND", "NONE"],
|
||||
"isBattle": false,
|
||||
"animations": ["q.look('head')", "q.bedrock('cyclizar', 'ground_idle')"],
|
||||
"condition": "!q.is_ridden",
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('cyclizar', 'blink')"
|
||||
]
|
||||
},
|
||||
"walking": {
|
||||
"poseTypes": ["WALK", "SWIM"],
|
||||
"animations": ["q.look('head')", "q.bedrock('cyclizar', 'ground_walk')"],
|
||||
"condition": "!q.is_ridden",
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"]
|
||||
},
|
||||
"mount_idle": {
|
||||
"poseTypes": ["STAND"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cyclizar', 'ride_drift')"
|
||||
],
|
||||
"condition": "q.is_ridden && !q.in_air",
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"]
|
||||
},
|
||||
"mount_walk": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cyclizar', 'ride_ground_run')",
|
||||
"q.bedrock('cyclizar', 'ground_run')"
|
||||
],
|
||||
"condition": "q.is_ridden && !q.is_sprinting && !q.in_air && !q.is_drifting && !q.is_powered_drifting",
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"mount_drift": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cyclizar', 'ride_ground_run')",
|
||||
"q.bedrock('cyclizar', 'ride_drift')"
|
||||
],
|
||||
"condition": "q.is_ridden && !q.is_sprinting && !q.in_air && q.is_drifting && !q.is_powered_drifting",
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"mount_powered_drift": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head')",
|
||||
"q.bedrock('cyclizar', 'ride_ground_run')",
|
||||
"q.bedrock('cyclizar', 'ride_drift')",
|
||||
"q.bedrock('cyclizar', 'ride_drift_legs')",
|
||||
"q.bedrock('cyclizar', 'ride_drift_override')"
|
||||
],
|
||||
"condition": "q.is_ridden && !q.is_sprinting && !q.in_air && !q.is_drifting && q.is_powered_drifting",
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"],
|
||||
"transformTicks": 5,
|
||||
"transformToTicks": 5
|
||||
},
|
||||
"mount_run": {
|
||||
"poseTypes": ["WALK"],
|
||||
"isBattle": false,
|
||||
"condition": "!q.in_air && q.is_sprinting",
|
||||
"animations": ["q.look('head')", "q.bedrock('cyclizar', 'ground_run')"],
|
||||
"quirks": ["q.bedrock_quirk('cyclizar', 'blink')"]
|
||||
"poses": {
|
||||
"standing": {
|
||||
"poseTypes": [
|
||||
"STAND",
|
||||
"NONE",
|
||||
"PORTRAIT",
|
||||
"PROFILE"
|
||||
],
|
||||
"isBattle": false,
|
||||
"animations": [
|
||||
"q.look('head', 1, 1, 25, -45, 45, -45)",
|
||||
"q.bedrock('cyclizar', 'grounded')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('cyclizar', 'blink')"
|
||||
]
|
||||
},
|
||||
"walking": {
|
||||
"poseTypes": [
|
||||
"WALK",
|
||||
"SWIM"
|
||||
],
|
||||
"animations": [
|
||||
"q.look('head', 1, 1, 25, -45, 45, -45)",
|
||||
"q.bedrock('cyclizar', 'grounded')",
|
||||
"q.quadruped_walk(0.66, 0.6, 'arm_left', 'arm_right', 'leg_left_rotate', 'leg_right_rotate')"
|
||||
],
|
||||
"quirks": [
|
||||
"q.bedrock_quirk('cyclizar', 'blink')"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,54 +6,22 @@
|
||||
"aspects": [],
|
||||
"poser": "cobblemon:golurk",
|
||||
"model": "cobblemon:golurk.geo",
|
||||
"texture": {
|
||||
"frames": [
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_1.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_2.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_3.png"
|
||||
],
|
||||
"fps": 10,
|
||||
"loop": true
|
||||
},
|
||||
"texture": "cobblemon:textures/pokemon/0623_golurk/golurk.png",
|
||||
"layers": [
|
||||
{
|
||||
"name": "color",
|
||||
"texture": {
|
||||
"frames": [
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_emissive_1.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_emissive_2.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_emissive_3.png"
|
||||
],
|
||||
"fps": 10,
|
||||
"loop": true
|
||||
},
|
||||
"texture": "cobblemon:textures/pokemon/0623_golurk/golurk_emissive.png",
|
||||
"emissive": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aspects": ["shiny"],
|
||||
"texture": {
|
||||
"frames": [
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_1.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_2.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_3.png"
|
||||
],
|
||||
"fps": 10,
|
||||
"loop": true
|
||||
},
|
||||
"texture": "cobblemon:textures/pokemon/0623_golurk/golurk_shiny.png",
|
||||
"layers": [
|
||||
{
|
||||
"name": "color",
|
||||
"texture": {
|
||||
"frames": [
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_emissive_1.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_emissive_2.png",
|
||||
"cobblemon:textures/pokemon/0623_golurk/golurk_shiny_emissive_3.png"
|
||||
],
|
||||
"fps": 10,
|
||||
"loop": true
|
||||
},
|
||||
"texture": "cobblemon:textures/pokemon/0623_golurk/golurk_shiny_emissive.png",
|
||||
"emissive": true
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2382,6 +2382,7 @@
|
||||
"cobblemon.config.ui.category.interface": "Interface",
|
||||
"cobblemon.config.ui.category.riding": "Riding",
|
||||
"cobblemon.config.ui.category.debug": "Debug",
|
||||
"cobblemon.config.ui.category.system": "System",
|
||||
|
||||
"cobblemon.config.ui.max_pokemon_level": "Max Pokémon Level",
|
||||
"cobblemon.config.ui.max_pokemon_level.tooltip": "The maximum level Pokémon can get to.",
|
||||
@@ -2564,6 +2565,8 @@
|
||||
"cobblemon.config.ui.despawner_max_age_ticks.tooltip": "The age (in game ticks) a Pokémon must reach before it can be despawned at the near distance boundary.",
|
||||
"cobblemon.config.ui.enable_debug_keys": "Enable Debug Keys",
|
||||
"cobblemon.config.ui.enable_debug_keys.tooltip": "Enables additional commands and chat logging to assist with implementing Pokémon (see the wiki for a list of commands).",
|
||||
"cobblemon.config.ui.time_zone_id": "Time Zone Id",
|
||||
"cobblemon.config.ui.time_zone_id.tooltip": "Time Zone to use for some MoLangs and IRL time zone dates. Server Side only.",
|
||||
|
||||
"cobblemon.config.ui.allow_starter_on_join": "Allow Starter on Join",
|
||||
"cobblemon.config.ui.prompt_starter_once_only": "Prompt Starter Once Only",
|
||||
|
||||
@@ -1175,14 +1175,6 @@
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/saucer_flight_loop",
|
||||
"attenuation_distance": 64.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.rocket": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/rocket_flight_loop",
|
||||
"attenuation_distance": 48.0
|
||||
}
|
||||
]
|
||||
|
||||
|
Before Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 441 B |
|
Before Width: | Height: | Size: 384 B After Width: | Height: | Size: 530 B |
|
Before Width: | Height: | Size: 345 B After Width: | Height: | Size: 541 B |
|
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 252 B |
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 252 B After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 529 B |
|
Before Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 538 B |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
@@ -2,7 +2,7 @@
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"rolls": 3,
|
||||
"bonus_rolls": 0.0,
|
||||
"entries": [
|
||||
{
|
||||
@@ -12,8 +12,8 @@
|
||||
"add": false,
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 3.0,
|
||||
"min": 9.0
|
||||
"max": 1.0,
|
||||
"min": 3.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
@@ -29,12 +29,28 @@
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 1.0,
|
||||
"min": 3.0
|
||||
"min": 1.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
],
|
||||
"name": "cobblemon:rare_candy",
|
||||
"name": "cobblemon:exp_candy_m",
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"functions": [
|
||||
{
|
||||
"add": false,
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 1.0,
|
||||
"min": 1.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
],
|
||||
"name": "minecraft:golden_apple",
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"rolls": 6,
|
||||
"bonus_rolls": 0.0,
|
||||
"entries": [
|
||||
{
|
||||
@@ -12,8 +12,8 @@
|
||||
"add": false,
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 6.0,
|
||||
"min": 18.0
|
||||
"max": 1.0,
|
||||
"min": 3.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
@@ -28,13 +28,29 @@
|
||||
"add": false,
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 3.0,
|
||||
"min": 5.0
|
||||
"max": 1.0,
|
||||
"min": 2.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
],
|
||||
"name": "cobblemon:rare_candy",
|
||||
"name": "cobblemon:exp_candy_m",
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"functions": [
|
||||
{
|
||||
"add": false,
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"max": 1.0,
|
||||
"min": 2.0
|
||||
},
|
||||
"function": "minecraft:set_count"
|
||||
}
|
||||
],
|
||||
"name": "minecraft:golden_apple",
|
||||
"weight": 10
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,7 +2,7 @@ t.wander_control = q.entity.get_wander_control_memory();
|
||||
t.wander_control.reset();
|
||||
|
||||
t.wander_control.set_allow_land((q.entity.behaviour.moving.walk.can_walk && !q.entity.behaviour.moving.walk.avoids_land) || (!q.entity.behaviour.moving.walk.can_walk && q.entity.behaviour.moving.fly.can_fly));
|
||||
t.wander_control.set_allow_water(q.entity.behaviour.moving.swim.can_swim && !q.entity.behaviour.moving.swim.avoids_water);
|
||||
t.wander_control.set_allow_water(q.entity.behaviour.moving.swim.can_swim_in_water && !q.entity.behaviour.moving.swim.avoids_water);
|
||||
t.wander_control.set_allow_air(q.entity.behaviour.moving.fly.can_fly && !q.entity.behaviour.moving.walk.can_walk);
|
||||
|
||||
t.wander_control.set_walk_speed(0.35);
|
||||
@@ -96,10 +96,24 @@
|
||||
"key": "cobblemon:composite",
|
||||
"transitionStrategy": "cobblemon:strategy/jump",
|
||||
"defaultBehaviour": {
|
||||
"key": "cobblemon:land/horse"
|
||||
"key": "cobblemon:land/horse",
|
||||
"gravity": "q.gravity * (0.1 + (q.passenger_count - 1) * 0.1)",
|
||||
"speed": "Math.clamp(q.entity.velocity.horizontal_magnitude + 0.33, 0, 1)",
|
||||
"jumpVector": [
|
||||
0,
|
||||
"0.3*q.jump_strength/50",
|
||||
"-1 * 0.5*q.jump_strength/50"
|
||||
]
|
||||
},
|
||||
"alternateBehaviour": {
|
||||
"key": "cobblemon:air/bird",
|
||||
"gravity": "q.gravity * (0.1 + (q.passenger_count - 1) * 0.1)",
|
||||
"speed": "Math.clamp(q.entity.velocity.horizontal_magnitude + 0.33, 0, 1)",
|
||||
"jumpVector": [
|
||||
0,
|
||||
"0.3*q.jump_strength/50",
|
||||
0
|
||||
],
|
||||
"rideSounds": [
|
||||
{
|
||||
"soundLocation": "cobblemon:ride.loop.leather",
|
||||
|
||||
@@ -60,64 +60,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"displayName": "Speed",
|
||||
"description": "Its top speed",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"displayName": "Acceleration",
|
||||
"description": "How fast it can speed up",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"SKILL": {
|
||||
"displayName": "Handling",
|
||||
"description": "How fast it can turn",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"JUMP": {
|
||||
"displayName": "Altitude",
|
||||
"description": "How high it can jump",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"STAMINA": {
|
||||
"displayName": "Fuel/Stamina",
|
||||
"description": "How long it can sprint",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"behaviour": {
|
||||
"key": "cobblemon:liquid/dolphin"
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"drops": {
|
||||
"amount": 4,
|
||||
"entries": [
|
||||
@@ -266,5 +208,26 @@
|
||||
"legacy:toxic"
|
||||
],
|
||||
"preEvolution": "seel",
|
||||
"evolutions": []
|
||||
"evolutions": [],
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"ranges": "15-30"
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"ranges": "25-50"
|
||||
},
|
||||
"SKILL": {
|
||||
"ranges": "15-30"
|
||||
},
|
||||
"JUMP": {
|
||||
"ranges": "20-40"
|
||||
},
|
||||
"STAMINA": {
|
||||
"ranges": "30-60"
|
||||
}
|
||||
},
|
||||
"seats": [],
|
||||
"behaviour": null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,101 +43,16 @@
|
||||
"catchRate": 90,
|
||||
"eggCycles": 25,
|
||||
"baseFriendship": 50,
|
||||
"baseScale": 1.0,
|
||||
"baseScale": 1.65,
|
||||
"hitbox": {
|
||||
"width": 1.4,
|
||||
"height": 3.5,
|
||||
"fixed": false
|
||||
},
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"displayName": "Speed",
|
||||
"description": "Its top speed",
|
||||
"ranges": {
|
||||
"LAND": "10-50",
|
||||
"AIR": "50-100"
|
||||
}
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"displayName": "Acceleration",
|
||||
"description": "How fast it can speed up",
|
||||
"ranges": {
|
||||
"LAND": "50-100",
|
||||
"AIR": "50-100"
|
||||
}
|
||||
},
|
||||
"SKILL": {
|
||||
"displayName": "Handling",
|
||||
"description": "How fast it can turn",
|
||||
"ranges": {
|
||||
"LAND": "50-100",
|
||||
"AIR": "50-100"
|
||||
}
|
||||
},
|
||||
"JUMP": {
|
||||
"displayName": "Altitude",
|
||||
"description": "How high it can fly",
|
||||
"ranges": {
|
||||
"LAND": "50-100",
|
||||
"AIR": "50-100"
|
||||
}
|
||||
},
|
||||
"STAMINA": {
|
||||
"displayName": "Fuel/Stamina",
|
||||
"description": "How long it can stay off the ground",
|
||||
"ranges": {
|
||||
"LAND": "50-100",
|
||||
"AIR": "50-100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"behaviour": {
|
||||
"key": "cobblemon:composite",
|
||||
"transitionStrategy": "cobblemon:strategy/jump",
|
||||
"defaultBehaviour": {
|
||||
"key": "cobblemon:land/horse",
|
||||
"canJump": false
|
||||
},
|
||||
"alternateBehaviour": {
|
||||
"key": "cobblemon:air/rocket",
|
||||
"rideSounds": [
|
||||
{
|
||||
"soundLocation": "cobblemon:ride.loop.rocket",
|
||||
"volumeExpr": "math.pow(math.min((q.driver_input() / 1.5) + (q.ride_velocity() / 1.5), 1.0),2)",
|
||||
"pitchExpr": "math.max(1.0 ,0.2 + math.pow(math.min(q.driver_input() / 1.5, 1.0),2))",
|
||||
"playForNonPassengers": true,
|
||||
"muffleEnabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 0
|
||||
},
|
||||
"poseOffsets": [
|
||||
{
|
||||
"poseTypes": [
|
||||
"FLY"
|
||||
],
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.0,
|
||||
"z": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"behaviour": {
|
||||
"moving": {
|
||||
"walk": {
|
||||
"walkSpeed": 0.35
|
||||
"walkSpeed": 0.25
|
||||
},
|
||||
"swim": {
|
||||
"avoidsWater": true,
|
||||
|
||||
@@ -47,64 +47,6 @@
|
||||
"height": 1.3,
|
||||
"fixed": false
|
||||
},
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"displayName": "Speed",
|
||||
"description": "Its top speed",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"displayName": "Acceleration",
|
||||
"description": "How fast it can speed up",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"SKILL": {
|
||||
"displayName": "Handling",
|
||||
"description": "How fast it can turn",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"JUMP": {
|
||||
"displayName": "Altitude",
|
||||
"description": "How high it can jump",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"STAMINA": {
|
||||
"displayName": "Fuel/Stamina",
|
||||
"description": "How long it can sprint",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"behaviour": {
|
||||
"key": "cobblemon:land/vehicle"
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"drops": {
|
||||
"amount": 1,
|
||||
"entries": [
|
||||
|
||||
@@ -55,64 +55,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"riding": {
|
||||
"stats": {
|
||||
"SPEED": {
|
||||
"displayName": "Speed",
|
||||
"description": "Its top speed",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"ACCELERATION": {
|
||||
"displayName": "Acceleration",
|
||||
"description": "How fast it can speed up",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"SKILL": {
|
||||
"displayName": "Handling",
|
||||
"description": "How fast it can turn",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"JUMP": {
|
||||
"displayName": "Altitude",
|
||||
"description": "How high it can jump",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
},
|
||||
"STAMINA": {
|
||||
"displayName": "Fuel/Stamina",
|
||||
"description": "How long it can sprint",
|
||||
"ranges": {
|
||||
"LAND": "50-100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"behaviour": {
|
||||
"key": "cobblemon:land/minekart"
|
||||
},
|
||||
"seats": [
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"offset": {
|
||||
"x": 0,
|
||||
"y": 0.4,
|
||||
"z": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"drops": {
|
||||
"amount": 4,
|
||||
"entries": [
|
||||
|
||||