mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-09 09:48:53 -05:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96079065b6 | ||
|
|
86f91ed77a |
No files matched your search
@@ -2,47 +2,19 @@
|
||||
## [1.7.2 (MONTH Xth, YEAR)](#1-7-2)
|
||||
|
||||
### Additions
|
||||
- Added riding statistics: `Distance by Pokémon on Land`, `Distance by Pokémon in Air` and `Distance by Pokémon in Liquid`.
|
||||
- Added the Partner Mark, which party Pokémon have a very small chance to earn as the player walks, provided they have enough friendship.
|
||||
- Added trades for Saccharine Saplings, Hearty Grains, Chipped Pot, and Masterpiece Teacup to the Wandering Trader.
|
||||
- Added brewing recipe for Throat Spray.
|
||||
- Added new effects
|
||||
- Mental Restoration: Reduces "Time Since Last Rest" statistic, which controls Insomnia, by half a minute per second per effect level
|
||||
- Negative Effect Cleanse: Removes all negative effects
|
||||
- Effect Cleanse: Removes all effects
|
||||
- Added more seasonings for sinister tea
|
||||
- Mental Herb - Mental Restoration I for 10 seconds
|
||||
- White Herb - Negative Effect Cleanse
|
||||
- Milk - Effect Cleanse
|
||||
- Moomoo Milk - Effect Cleanse
|
||||
|
||||
### Changes
|
||||
- Ride sounds have been separated into stereo for passengers and mono for other players. Riding will now sound more spacious.
|
||||
|
||||
### Fixes
|
||||
- Fixed orientation not getting reset after crashing while flying and getting back on the Pokémon.
|
||||
- Fixed Furfrou not being trimmable on NeoForge.
|
||||
- Fixed shiny Pokémon not respecting the silent flag on spawn.
|
||||
- Fixed honey from Saccharine Leaves being harvestable at less than the max age.
|
||||
- Items given from interacting with Saccharine Leaves are placed in the active hotbar slot if possible.
|
||||
- Fix all Pokémon being saved to chunks and never despawning.
|
||||
- Fixed PokeSnacks crashing if there was no available spawn.
|
||||
- Fixed Pokémon spawn influences not being specific to regional forms
|
||||
- Fixed crashing when viewing another player in spectator mode
|
||||
- Fixed missing apricorn textures for Adorn blocks
|
||||
- Fixed crashing when riding due to malformed json file, instead resetting it
|
||||
- Fixed mochi items consuming two items at a time
|
||||
- Fix item interaction sometimes not working properly when playing on servers.
|
||||
- Fixed Soothe Bell not being properly tagged as a held item.
|
||||
- Fixed Mint Leaves not being usable for filling the Resurrection Machine.
|
||||
- Added Saccharine Boats and Saccharine Boat with Chests to relevant boat tags.
|
||||
|
||||
### Developer
|
||||
- Changed the `owner` parameter in the `OwnerQueryRequirement` interface from `ServerPlayer` to `Player`. This method is now also called on the client to verify whether a Pokémon interaction succeeded, so make sure to update your implementations to handle both server and client contexts.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
|
||||
### Particles
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
package com.cobblemon.mod.common.bridges;
|
||||
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface SoundBufferLibraryDuck {
|
||||
|
||||
CompletableFuture<AudioStream> getStreamWithLoopPoints(ResourceLocation audioLocation, int loopStart, int loopEnd);
|
||||
|
||||
CompletableFuture<AudioStream> getStreamWithIntro(ResourceLocation introLocation, ResourceLocation endLocation, boolean isLoop);
|
||||
|
||||
CompletableFuture<AudioStream> getStreamWithIntro(ResourceLocation introLocation, ResourceLocation endLocation, int loopStart, int loopEnd);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface SoundDuck {
|
||||
|
||||
int getLoopStart();
|
||||
|
||||
int getLoopEnd();
|
||||
|
||||
ResourceLocation getIntro();
|
||||
|
||||
void setLoopStart(int startInSamples);
|
||||
|
||||
void setLoopEnd(int endInSamples);
|
||||
|
||||
void setIntro(ResourceLocation intro);
|
||||
|
||||
boolean hasLoopPoints();
|
||||
|
||||
boolean hasIntro();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.sounds.Music;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(Minecraft.class)
|
||||
public class MinecraftMixin {
|
||||
|
||||
/** Used by MusicManager to dispatch the music to play. */
|
||||
@WrapOperation(
|
||||
method = "getSituationalMusic",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/biome/Biome;getBackgroundMusic()Ljava/util/Optional;")
|
||||
)
|
||||
public Optional<Music> getBackgroundMusic(Biome instance, Operation<Optional<Music>> original) {
|
||||
return original.call(instance);
|
||||
}
|
||||
}
|
||||
@@ -11,15 +11,11 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -93,32 +89,4 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "checkRidingStatistics", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;getVehicle()Lnet/minecraft/world/entity/Entity;"))
|
||||
public Entity cobblemon$checkRidingStatistics(ServerPlayer player, Operation<Entity> original, @Local int distance) {
|
||||
var entity = original.call(player);
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
var ridingController = pokemonEntity.getRidingController();
|
||||
if (ridingController == null) return entity;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return entity;
|
||||
|
||||
var ridingStyle = activeContext.getStyle();
|
||||
CobblemonStats.CobblemonStat stat = switch (ridingStyle) {
|
||||
case RidingStyle.LAND -> CobblemonStats.RIDING_LAND;
|
||||
case RidingStyle.AIR -> CobblemonStats.RIDING_AIR;
|
||||
case RidingStyle.LIQUID -> CobblemonStats.RIDING_LIQUID;
|
||||
default -> null;
|
||||
};
|
||||
|
||||
if (stat != null) {
|
||||
player.awardStat(CobblemonStats.getStat(stat), distance);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.client.sound.streams.CompoundAudioStream;
|
||||
import com.cobblemon.mod.common.client.sound.streams.LoopPointAudioStream;
|
||||
import com.cobblemon.mod.common.duck.SoundBufferLibraryDuck;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.JOrbisAudioStream;
|
||||
import net.minecraft.client.sounds.LoopingAudioStream;
|
||||
import net.minecraft.client.sounds.SoundBufferLibrary;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceProvider;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
@Mixin(SoundBufferLibrary.class)
|
||||
public class SoundBufferLibraryMixin implements SoundBufferLibraryDuck {
|
||||
|
||||
@Shadow
|
||||
private ResourceProvider resourceManager;
|
||||
|
||||
/**
|
||||
* Creates a LoopPointAudioStream with defined loop points.
|
||||
*
|
||||
* @param audioLocation The audio file to open for stream.
|
||||
* @param loopStart The starting point of the stream's loop.
|
||||
* @param loopEnd The ending point of the stream's loop.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<AudioStream> getStreamWithLoopPoints(ResourceLocation audioLocation, int loopStart, int loopEnd) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
InputStream introStream = this.resourceManager.open(audioLocation);
|
||||
return new LoopPointAudioStream(JOrbisAudioStream::new, introStream, loopStart, loopEnd);
|
||||
} catch (IOException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
}, Util.nonCriticalIoPool());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CompoundAudioStream from a JOrbisAudioStream intro and LoopPointAudioStream end.
|
||||
*
|
||||
* @param introLocation The audio file to open for the intro stream.
|
||||
* @param endLocation The audio file to open for the end stream.
|
||||
* @param loopStart The starting point of the ending LoopPointAudioStream's loop.
|
||||
* @param loopEnd The ending point of the ending LoopPointAudioStream's loop.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<AudioStream> getStreamWithIntro(ResourceLocation introLocation, ResourceLocation endLocation, int loopStart, int loopEnd) {
|
||||
return createCompoundStream(
|
||||
introLocation,
|
||||
endLocation,
|
||||
(inputStream) -> new LoopPointAudioStream(JOrbisAudioStream::new, inputStream, loopStart, loopEnd)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CompoundAudioStream from a JOrbisAudioStream intro and a JOrbisAudioStream or LoopingAudioStream end.
|
||||
*
|
||||
* @param introLocation The audio file to open for the intro stream.
|
||||
* @param endLocation The audio file to open for the end stream.
|
||||
* @param isLoop Whether the end stream loops (LoopingAudioStream) or not (JOrbisAudioStream).
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<AudioStream> getStreamWithIntro(ResourceLocation introLocation, ResourceLocation endLocation, boolean isLoop) {
|
||||
return createCompoundStream(
|
||||
introLocation,
|
||||
endLocation,
|
||||
!isLoop ? JOrbisAudioStream::new : (inputStream) -> new LoopingAudioStream(JOrbisAudioStream::new, inputStream)
|
||||
);
|
||||
}
|
||||
|
||||
private CompletableFuture<AudioStream> createCompoundStream(ResourceLocation introLocation, ResourceLocation endLocation, LoopingAudioStream.AudioStreamProvider endProvider) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
InputStream introInputStream = this.resourceManager.open(introLocation);
|
||||
InputStream endInputStream = this.resourceManager.open(endLocation);
|
||||
|
||||
AudioStream introStream = new JOrbisAudioStream(introInputStream);
|
||||
AudioStream endStream = endProvider.create(endInputStream);
|
||||
return new CompoundAudioStream(introStream, endStream);
|
||||
} catch (Exception e) {
|
||||
Cobblemon.LOGGER.error(e.getMessage());
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
}, Util.nonCriticalIoPool());
|
||||
}
|
||||
}
|
||||
@@ -8,24 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideAttenuationModel;
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideLoopSound;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundBufferLibraryDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import net.minecraft.client.resources.sounds.Sound;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.TickableSoundInstance;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.ChannelAccess;
|
||||
import net.minecraft.client.sounds.SoundBufferLibrary;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
@@ -36,10 +30,12 @@ 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;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Mixin(SoundEngine.class)
|
||||
public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
@@ -124,23 +120,4 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
cb.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatch custom stream for sounds that have an intro. WrapOperation because the Fabric API has its own Redirect that we don't want to use. */
|
||||
@WrapOperation(method = "play", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/sounds/SoundBufferLibrary;getStream(Lnet/minecraft/resources/ResourceLocation;Z)Ljava/util/concurrent/CompletableFuture;"))
|
||||
public CompletableFuture<AudioStream> getStream(SoundBufferLibrary bufferLibrary, ResourceLocation id, boolean looping, Operation<CompletableFuture<AudioStream>> original, SoundInstance soundInstance) {
|
||||
SoundDuck soundDuck = (SoundDuck)soundInstance.getSound();
|
||||
SoundBufferLibraryDuck libraryDuck = (SoundBufferLibraryDuck)bufferLibrary;
|
||||
if (soundDuck.hasIntro() && soundDuck.hasLoopPoints() && looping) {
|
||||
return libraryDuck.getStreamWithIntro(soundDuck.getIntro(), id, soundDuck.getLoopStart(), soundDuck.getLoopEnd());
|
||||
}
|
||||
else if (soundDuck.hasIntro()) {
|
||||
return libraryDuck.getStreamWithIntro(soundDuck.getIntro(), id, looping);
|
||||
}
|
||||
else if (soundDuck.hasLoopPoints() && looping) {
|
||||
return libraryDuck.getStreamWithLoopPoints(id, soundDuck.getLoopStart(), soundDuck.getLoopEnd());
|
||||
}
|
||||
else {
|
||||
return original.call(bufferLibrary, id, looping);
|
||||
}
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.SoundDuck;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||
import net.minecraft.client.resources.sounds.Sound;
|
||||
import net.minecraft.client.resources.sounds.SoundEventRegistrationSerializer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@Mixin(SoundEventRegistrationSerializer.class)
|
||||
public class SoundEventRegistrationSerializerMixin {
|
||||
|
||||
/** Injects custom fields into Sound resource for loop behavior. */
|
||||
@ModifyReturnValue(method = "getSound", at = @At("RETURN"))
|
||||
private Sound getSound(Sound original, JsonObject json) {
|
||||
int loopStart = GsonHelper.getAsInt(json, "loopStart", 0);
|
||||
int loopEnd = GsonHelper.getAsInt(json, "loopEnd", 0);
|
||||
ResourceLocation intro = ResourceLocation.parse(GsonHelper.getAsString(json, "intro", ""));
|
||||
((SoundDuck)original).setLoopStart(loopStart);
|
||||
((SoundDuck)original).setLoopEnd(loopEnd);
|
||||
((SoundDuck)original).setIntro(intro);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.SoundDuck;
|
||||
import net.minecraft.client.resources.sounds.Sound;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
import static net.minecraft.client.resources.sounds.Sound.SOUND_LISTER;
|
||||
|
||||
@Mixin(Sound.class)
|
||||
public abstract class SoundMixin implements SoundDuck {
|
||||
|
||||
int loopStart = 0;
|
||||
|
||||
int loopEnd = 0;
|
||||
|
||||
ResourceLocation intro = null;
|
||||
|
||||
@Override
|
||||
public ResourceLocation getIntro() {
|
||||
return SOUND_LISTER.idToFile(this.intro);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoopStart() {
|
||||
return loopStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoopEnd() {
|
||||
return loopEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoopStart(int startInSamples) {
|
||||
this.loopStart = startInSamples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoopEnd(int endInSamples) {
|
||||
this.loopEnd = endInSamples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntro(ResourceLocation intro) {
|
||||
this.intro = intro;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLoopPoints() {
|
||||
return (this.loopEnd >= 0 && this.loopStart >= 0) && (this.loopEnd + this.loopStart != 0) && (loopStart < loopEnd || loopStart == 0 || loopEnd == 0);
|
||||
}
|
||||
// this is used to determine if the LoopPointAudioStream is necessary or if the legacy LoopingAudioStream can be used
|
||||
|
||||
@Override
|
||||
public boolean hasIntro() {
|
||||
return this.intro != null && !this.intro.getPath().isBlank();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.StructureProcessorListBridge;
|
||||
import com.cobblemon.mod.common.bridges.StructureProcessorListBridge;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class AbstractClientPlayerMixin {
|
||||
cir.setReturnValue(usageContext.getFovMultiplier());
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
AbstractClientPlayer player = (AbstractClientPlayer) (Object) this;
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
@@ -42,8 +42,8 @@ import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
|
||||
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
|
||||
@@ -76,7 +76,12 @@ import com.cobblemon.mod.common.config.LastChangedVersion
|
||||
import com.cobblemon.mod.common.config.constraint.IntConstraint
|
||||
import com.cobblemon.mod.common.config.starter.StarterConfig
|
||||
import com.cobblemon.mod.common.data.CobblemonDataProvider
|
||||
import com.cobblemon.mod.common.events.*
|
||||
import com.cobblemon.mod.common.events.AdvancementHandler
|
||||
import com.cobblemon.mod.common.events.EntityCallbackHandler
|
||||
import com.cobblemon.mod.common.events.CallbackHandler
|
||||
import com.cobblemon.mod.common.events.PokedexHandler
|
||||
import com.cobblemon.mod.common.events.ServerTickHandler
|
||||
import com.cobblemon.mod.common.events.StatHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
@@ -189,6 +194,7 @@ object Cobblemon {
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerDataComponents()
|
||||
implementation.registerBlocks()
|
||||
implementation.registerArmorMaterials()
|
||||
implementation.registerItems()
|
||||
implementation.registerEntityTypes()
|
||||
implementation.registerEntityAttributes()
|
||||
@@ -201,7 +207,6 @@ object Cobblemon {
|
||||
implementation.registerEntityDataSerializers()
|
||||
implementation.registerCriteria()
|
||||
implementation.registerEntitySubPredicates()
|
||||
implementation.registerMobEffects()
|
||||
DispenserBehaviorRegistry.registerDispenserBehaviors()
|
||||
|
||||
DropEntry.register("command", CommandDropEntry::class.java)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.item.ArmorItem
|
||||
import net.minecraft.world.item.ArmorMaterial
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.crafting.Ingredient
|
||||
|
||||
@Suppress("unused")
|
||||
object CobblemonArmorMaterials :
|
||||
PlatformRegistry<Registry<ArmorMaterial>, ResourceKey<Registry<ArmorMaterial>>, ArmorMaterial>() {
|
||||
|
||||
override val registry: Registry<ArmorMaterial> = BuiltInRegistries.ARMOR_MATERIAL
|
||||
override val resourceKey: ResourceKey<Registry<ArmorMaterial>> = Registries.ARMOR_MATERIAL
|
||||
|
||||
@JvmField
|
||||
val MALICIOUS_ARMOR = cosmeticMaterial("malicious_armor")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = cosmeticMaterial("heavy_duty_boots")
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = cosmeticMaterial("protective_pads")
|
||||
@JvmField
|
||||
val ASSAULT_VEST = cosmeticMaterial("assault_vest")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = cosmeticMaterial("mystic_water")
|
||||
@JvmField
|
||||
val BLACK_BELT = cosmeticMaterial("black_belt")
|
||||
|
||||
private fun cosmeticMaterial(name: String): ArmorMaterial {
|
||||
val armorMaterial = ArmorMaterial(
|
||||
mapOf(
|
||||
ArmorItem.Type.HELMET to 0,
|
||||
ArmorItem.Type.CHESTPLATE to 0,
|
||||
ArmorItem.Type.LEGGINGS to 0,
|
||||
ArmorItem.Type.BOOTS to 0,
|
||||
),
|
||||
0,
|
||||
SoundEvents.ARMOR_EQUIP_GENERIC,
|
||||
{ Ingredient.EMPTY },
|
||||
listOf(ArmorMaterial.Layer(cobblemonResource(name), "", true)),
|
||||
0.0f,
|
||||
0.0f,
|
||||
)
|
||||
|
||||
return create(name, armorMaterial)
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,8 @@ interface CobblemonImplementation {
|
||||
|
||||
fun registerEntityDataSerializers()
|
||||
|
||||
fun registerArmorMaterials()
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
@@ -117,11 +119,6 @@ interface CobblemonImplementation {
|
||||
|
||||
fun registerEntitySubPredicates()
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
fun registerMobEffects()
|
||||
|
||||
|
||||
/**
|
||||
* Add a feature to the current platform implementation.
|
||||
|
||||
@@ -44,16 +44,21 @@ import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.food.FoodProperties
|
||||
import net.minecraft.world.item.ArmorItem
|
||||
import net.minecraft.world.item.ArmorMaterial
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.HangingSignItem
|
||||
import net.minecraft.world.item.Item
|
||||
@@ -501,8 +506,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val RAZOR_CLAW = noSettingsItem("razor_claw")
|
||||
@JvmField val RAZOR_FANG = noSettingsItem("razor_fang")
|
||||
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
|
||||
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
|
||||
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
|
||||
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
|
||||
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
|
||||
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
|
||||
@@ -892,7 +895,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val WATER_STONE = noSettingsItem("water_stone")
|
||||
|
||||
val wearables = mutableListOf<WearableItem>()
|
||||
//Wearable items (these items should have a corresponding 3D model)
|
||||
|
||||
// Wearable items (these items should have a corresponding 3D model)
|
||||
@JvmField val BLACK_GLASSES = wearableItem("black_glasses")
|
||||
@JvmField val CHOICE_BAND = wearableItem("choice_band")
|
||||
@JvmField val CHOICE_SPECS = wearableItem("choice_specs")
|
||||
@@ -903,6 +907,20 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val ROCKY_HELMET = wearableItem("rocky_helmet")
|
||||
@JvmField val SAFETY_GOGGLES = wearableItem("safety_goggles")
|
||||
@JvmField val WISE_GLASSES = wearableItem("wise_glasses")
|
||||
@JvmField val SHELL_HELMET = wearableItem("shell_helmet")
|
||||
|
||||
@JvmField
|
||||
val MALICIOUS_ARMOR = armorItem("malicious_armor", CobblemonArmorMaterials.MALICIOUS_ARMOR, ArmorItem.Type.CHESTPLATE)
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = armorItem("heavy_duty_boots", CobblemonArmorMaterials.HEAVY_DUTY_BOOTS, ArmorItem.Type.BOOTS)
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = armorItem("protective_pads", CobblemonArmorMaterials.PROTECTIVE_PADS, ArmorItem.Type.CHESTPLATE)
|
||||
@JvmField
|
||||
val ASSAULT_VEST = armorItem("assault_vest", CobblemonArmorMaterials.ASSAULT_VEST, ArmorItem.Type.CHESTPLATE)
|
||||
@JvmField
|
||||
val MYSTIC_WATER = armorItem("mystic_water", CobblemonArmorMaterials.MYSTIC_WATER, ArmorItem.Type.CHESTPLATE)
|
||||
@JvmField
|
||||
val BLACK_BELT = armorItem("black_belt", CobblemonArmorMaterials.BLACK_BELT, ArmorItem.Type.CHESTPLATE)
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
@@ -912,14 +930,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val AIR_BALLOON = heldItem("air_balloon")
|
||||
@JvmField
|
||||
val ASSAULT_VEST = heldItem("assault_vest")
|
||||
@JvmField
|
||||
val BIG_ROOT = compostableBlockItem("big_root", CobblemonBlocks.BIG_ROOT, 0.30f)
|
||||
@JvmField
|
||||
val BINDING_BAND = heldItem("binding_band")
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@@ -966,8 +980,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val HARD_STONE = heldItem("hard_stone")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@@ -992,8 +1004,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MYSTIC_WATER = heldItem("mystic_water")
|
||||
@JvmField
|
||||
val NEVER_MELT_ICE = heldItem("never_melt_ice")
|
||||
@JvmField
|
||||
val POISON_BARB = heldItem("poison_barb")
|
||||
@@ -1012,8 +1022,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val PSYCHIC_SEED = heldItem("psychic_seed")
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = heldItem("protective_pads")
|
||||
@JvmField
|
||||
val PUNCHING_GLOVE = heldItem("punching_glove")
|
||||
@JvmField
|
||||
val QUICK_CLAW = heldItem("quick_claw")
|
||||
@@ -1491,9 +1499,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun wearableItem(name: String, heldItemRemappedName: String? = null): CobblemonItem = create(
|
||||
private fun wearableItem(
|
||||
name: String,
|
||||
heldItemRemappedName: String? = null,
|
||||
equipmentSlot: EquipmentSlot = EquipmentSlot.HEAD,
|
||||
): CobblemonItem = create(
|
||||
name,
|
||||
WearableItem(name).also {
|
||||
WearableItem(name, equipmentSlot).also {
|
||||
wearables.add(it)
|
||||
if (heldItemRemappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, heldItemRemappedName)
|
||||
@@ -1501,6 +1513,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
}
|
||||
)
|
||||
|
||||
private fun armorItem(
|
||||
name: String,
|
||||
armorMaterial: ArmorMaterial,
|
||||
armorType: ArmorItem.Type,
|
||||
durability: Int? = null,
|
||||
): ArmorItem {
|
||||
var properties = Properties()
|
||||
if (durability != null) properties = properties.durability(durability)
|
||||
val armorMaterialHolder = BuiltInRegistries.ARMOR_MATERIAL.wrapAsHolder(armorMaterial)
|
||||
|
||||
val armorItem = ArmorItem(armorMaterialHolder, armorType, properties)
|
||||
|
||||
return create(name, armorItem)
|
||||
}
|
||||
|
||||
private fun campfirePotItem(block: Block, color: CampfirePotColor): CampfirePotItem {
|
||||
val item = create("campfire_pot_${color.suffix}", CampfirePotItem(block, color))
|
||||
campfire_pots.add(item)
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.cooking.effects.CleanseAllEffect
|
||||
import com.cobblemon.mod.common.api.cooking.effects.CleanseNegativeEffect
|
||||
import com.cobblemon.mod.common.api.cooking.effects.MentalRestorationEffect
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
|
||||
object CobblemonMobEffects : PlatformRegistry<Registry<MobEffect>, ResourceKey<Registry<MobEffect>>, MobEffect>() {
|
||||
override val registry: Registry<MobEffect> = BuiltInRegistries.MOB_EFFECT
|
||||
override val resourceKey: ResourceKey<Registry<MobEffect>> = Registries.MOB_EFFECT
|
||||
|
||||
@JvmField
|
||||
val CLEANSE_NEGATIVE = create("cleanse_negative", CleanseNegativeEffect())
|
||||
|
||||
@JvmField
|
||||
val MENTAL_RESTORATION = create("mental_restoration", MentalRestorationEffect())
|
||||
|
||||
@JvmField
|
||||
val CLEANSE_ALL = create("cleanse_all", CleanseAllEffect())
|
||||
}
|
||||
@@ -21,12 +21,15 @@ import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallb
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.PokemonInteractionsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.debug.OpenRidingStatsDebugGUIHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.*
|
||||
import com.cobblemon.mod.common.client.net.effect.PokeSnackBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
@@ -34,7 +37,11 @@ import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.*
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.UpdatePastureConflictFlagHandler
|
||||
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
|
||||
@@ -52,7 +59,14 @@ import com.cobblemon.mod.common.client.net.storage.party.SetPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.party.SetPartyReferenceHandler
|
||||
import com.cobblemon.mod.common.client.net.storage.pc.*
|
||||
import com.cobblemon.mod.common.client.net.toast.ToastPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.*
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeAcceptanceChangedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCancelledHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeCompletedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferExpiredHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
@@ -69,12 +83,20 @@ import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.debug.RequestOpenRidingStatsDebugGUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.*
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SaccharineLogBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
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.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonUnpasturedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.UpdatePastureConflictFlagPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedRegisterPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.AddEvolutionPacket
|
||||
@@ -94,19 +116,43 @@ import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePart
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.MoveClientPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.party.SetPartyReferencePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.ClosePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.InitializePCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.MoveClientPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.OpenPCPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.RenamePCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCBoxPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangePCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCompletedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferExpiredPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotificationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestMoveSwapPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.RequestPlayerInteractionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SelectStarterPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.SendOutPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamLeavePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.DamageOnCollisionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
@@ -131,7 +177,11 @@ import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPack
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.StartScanningPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.interact.InteractPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.ServerboundUpdateRidingStatePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetActiveMarkPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetItemHiddenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetMarkingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePacket
|
||||
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
|
||||
@@ -142,11 +192,21 @@ import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokem
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.ReleasePartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.SwapPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.*
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.AcceptTradeRequestPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.CancelTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.ChangeTradeAcceptancePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.OfferTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.PerformTradePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.DamageOnCollisionPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
@@ -172,7 +232,11 @@ import com.cobblemon.mod.common.net.serverhandling.pasture.UnpasturePokemonHandl
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.FinishScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokedex.scanner.StartScanningHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.interact.InteractPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.ServerboundUpdateRidingStateHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetActiveMarkHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetItemHiddenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
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.riding.ServerboundUpdateRiderRotationHandler
|
||||
@@ -186,7 +250,12 @@ import com.cobblemon.mod.common.net.serverhandling.storage.party.MovePartyPokemo
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.ReleasePCPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.party.SwapPartyPokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.pc.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.*
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.AcceptTradeRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.CancelTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.ChangeTradeAcceptanceHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.OfferTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.PerformTradeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.trade.UpdateTradeOfferHandler
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -332,7 +401,6 @@ object CobblemonNetwork {
|
||||
// Data registries
|
||||
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
|
||||
list.add(PacketRegisterInfo(PokemonInteractionsSyncPacket.ID, PokemonInteractionsSyncPacket::decode, PokemonInteractionsSyncHandler))
|
||||
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking.effects
|
||||
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.effect.MobEffectCategory
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CleanseAllEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
|
||||
override fun isInstantenous() = true
|
||||
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
|
||||
target.removeAllEffects()
|
||||
}
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking.effects
|
||||
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.effect.MobEffectCategory
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CleanseNegativeEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
|
||||
override fun isInstantenous() = true
|
||||
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
|
||||
val snapshot = target.activeEffects.toList()
|
||||
for (ei in snapshot) {
|
||||
if (ei.effect.value().category == MobEffectCategory.HARMFUL) {
|
||||
target.removeEffect(ei.effect)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking.effects
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.stats.Stats
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.effect.MobEffectCategory
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class MentalRestorationEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xAA66FF) {
|
||||
override fun applyEffectTick(entity: LivingEntity, amplifier: Int): Boolean {
|
||||
if (entity is ServerPlayer) {
|
||||
val stats = entity.stats
|
||||
val statType = Stats.CUSTOM.get(Stats.TIME_SINCE_REST)
|
||||
val current = stats.getValue(statType)
|
||||
val reduction = 31 * (amplifier + 1)// reduce by half a minute every second per level (30 ticks removed per tick + 1 to account for the tick passing)
|
||||
val newValue = Math.max(current - reduction, 0)
|
||||
stats.setValue(entity, statType, newValue)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
+2
-7
@@ -12,10 +12,10 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.requirements.PokemonPropertiesRequirement
|
||||
@@ -51,12 +51,7 @@ object PokemonInteractions : JsonDataRegistry<PokemonInteractionSet> {
|
||||
val speciesInteractions = mutableListOf<PokemonInteractionSet>()
|
||||
val generalInteractions = mutableListOf<PokemonInteractionSet>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
PokemonInteractionsSyncPacket(
|
||||
speciesInteractions,
|
||||
generalInteractions,
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, PokemonInteractionSet>) {
|
||||
speciesInteractions.clear()
|
||||
|
||||
+19
-88
@@ -15,10 +15,11 @@ import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonRequirementAdapter
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.giveOrDropItemStack
|
||||
import com.cobblemon.mod.common.util.withPlayerValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundSource
|
||||
@@ -27,83 +28,30 @@ import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
/**
|
||||
* A
|
||||
*/
|
||||
data class PokemonInteractionSet(
|
||||
val requirements: List<Requirement> = listOf(),
|
||||
val interactions: List<PokemonInteraction> = listOf(),
|
||||
) {
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeCollection(requirements) { it, requirement ->
|
||||
CobblemonRequirementAdapter.encode(requirement, it)
|
||||
}
|
||||
buffer.writeCollection(interactions) { it, interaction ->
|
||||
interaction.encode(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): PokemonInteractionSet {
|
||||
val requirements = buffer.readList { it ->
|
||||
CobblemonRequirementAdapter.decode(it)
|
||||
}
|
||||
val interactions = buffer.readList { it ->
|
||||
PokemonInteraction.decode(it)
|
||||
}
|
||||
|
||||
return PokemonInteractionSet(
|
||||
requirements,
|
||||
interactions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val interactions: List<PokemonInteraction> = listOf()
|
||||
)
|
||||
data class PokemonInteraction(
|
||||
val grouping: ResourceLocation,
|
||||
val requirements: List<Requirement> = listOf(),
|
||||
val effects: List<InteractionEffect> = listOf(),
|
||||
val cooldown: ExpressionLike = "0".asExpressionLike()
|
||||
) {
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(grouping)
|
||||
buffer.writeCollection(requirements) { it, requirement ->
|
||||
CobblemonRequirementAdapter.encode(requirement, it)
|
||||
}
|
||||
buffer.writeExpressionLike(cooldown)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: FriendlyByteBuf): PokemonInteraction {
|
||||
val grouping = buffer.readResourceLocation()
|
||||
val requirements = buffer.readList { it ->
|
||||
CobblemonRequirementAdapter.decode(it)
|
||||
}
|
||||
|
||||
// No need to sync these for now
|
||||
val effects = emptyList<InteractionEffect>()
|
||||
val cooldown = buffer.readExpressionLike()
|
||||
|
||||
return PokemonInteraction(
|
||||
grouping,
|
||||
requirements,
|
||||
effects,
|
||||
cooldown,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
interface InteractionEffect {
|
||||
fun applyEffect(pokemon: PokemonEntity, player: ServerPlayer)
|
||||
}
|
||||
|
||||
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
|
||||
class DropItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
|
||||
override fun applyEffect(
|
||||
pokemon: PokemonEntity,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
|
||||
"Cannot load item with id: $item"
|
||||
)
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
|
||||
val stack = ItemStack(item)
|
||||
stack.count = amount?.randomOrNull() ?: 1
|
||||
if (stack.isEmpty)
|
||||
@@ -120,14 +68,12 @@ class DropItemEffect(val item: ResourceLocation, val amount: IntRange?) : Intera
|
||||
}
|
||||
}
|
||||
|
||||
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?) : InteractionEffect {
|
||||
class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?): InteractionEffect {
|
||||
override fun applyEffect(
|
||||
pokemon: PokemonEntity,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException(
|
||||
"Cannot load item with id: $item"
|
||||
)
|
||||
val item = player.registryAccess().registryOrThrow(Registries.ITEM).get(item) ?: throw IllegalArgumentException("Cannot load item with id: $item")
|
||||
val stack = ItemStack(item)
|
||||
stack.count = amount?.randomOrNull() ?: 1
|
||||
if (stack.isEmpty)
|
||||
@@ -140,29 +86,14 @@ class GiveItemEffect(val item: ResourceLocation, val amount: IntRange?) : Intera
|
||||
}
|
||||
}
|
||||
|
||||
class PlaySoundEffect(
|
||||
val sound: ResourceLocation,
|
||||
val soundSource: SoundSource?,
|
||||
val playAround: Boolean = true,
|
||||
val distance: Double = 64.0,
|
||||
val volume: Float = 1.0F,
|
||||
val pitch: Float = 1.0F
|
||||
) : InteractionEffect {
|
||||
class PlaySoundEffect(val sound: ResourceLocation, val soundSource: SoundSource?, val playAround: Boolean = true, val distance: Double = 64.0, val volume: Float = 1.0F, val pitch: Float = 1.0F): InteractionEffect {
|
||||
override fun applyEffect(
|
||||
pokemon: PokemonEntity,
|
||||
player: ServerPlayer
|
||||
) {
|
||||
val packet = UnvalidatedPlaySoundS2CPacket(
|
||||
sound,
|
||||
soundSource ?: SoundSource.NEUTRAL,
|
||||
pokemon.x,
|
||||
pokemon.y,
|
||||
pokemon.z,
|
||||
volume,
|
||||
pitch
|
||||
)
|
||||
val packet = UnvalidatedPlaySoundS2CPacket(sound, soundSource ?: SoundSource.NEUTRAL, pokemon.x, pokemon.y, pokemon.z, volume, pitch)
|
||||
if (playAround) {
|
||||
packet.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
|
||||
packet.sendToPlayersAround( pokemon.x, pokemon.y, pokemon.z, distance, pokemon.level().dimension())
|
||||
} else {
|
||||
packet.sendToPlayer(player)
|
||||
}
|
||||
@@ -173,7 +104,7 @@ class PlaySoundEffect(
|
||||
}
|
||||
}
|
||||
|
||||
class ShrinkItemEffect(val amount: Int = 1) : InteractionEffect {
|
||||
class ShrinkItemEffect(val amount: Int = 1): InteractionEffect {
|
||||
override fun applyEffect(
|
||||
pokemon: PokemonEntity,
|
||||
player: ServerPlayer
|
||||
@@ -189,7 +120,7 @@ class ShrinkItemEffect(val amount: Int = 1) : InteractionEffect {
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptEffect(val script: ExpressionLike) : InteractionEffect {
|
||||
class ScriptEffect(val script: ExpressionLike): InteractionEffect {
|
||||
override fun applyEffect(
|
||||
pokemon: PokemonEntity,
|
||||
player: ServerPlayer
|
||||
|
||||
@@ -779,20 +779,6 @@ object MoLangFunctions {
|
||||
battleStartResult.ifSuccessful { returnValue = it.struct }
|
||||
return@put returnValue
|
||||
}
|
||||
map.put("get_custom_stat") { params ->
|
||||
val statName = params.getString(0)
|
||||
|
||||
val resourceLocation = ResourceLocation.tryParse(statName) ?: return@put DoubleValue.ZERO
|
||||
val statResourceLocation = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation) ?: return@put DoubleValue.ZERO
|
||||
|
||||
val exists = net.minecraft.stats.Stats.CUSTOM.contains(statResourceLocation)
|
||||
if (!exists) return@put DoubleValue.ZERO
|
||||
|
||||
val stat = net.minecraft.stats.Stats.CUSTOM.get(statResourceLocation)
|
||||
val value = player.stats.getValue(stat)
|
||||
|
||||
DoubleValue(value)
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
@@ -1753,35 +1739,22 @@ object MoLangFunctions {
|
||||
pokemon.removeCosmeticItem()
|
||||
}
|
||||
map.put("add_marks") { params ->
|
||||
var appliedMark = false
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
if (mark != null) {
|
||||
pokemon.exchangeMark(mark, true)
|
||||
appliedMark = true
|
||||
}
|
||||
if (mark != null) pokemon.exchangeMark(mark, true)
|
||||
}
|
||||
|
||||
DoubleValue(appliedMark)
|
||||
}
|
||||
map.put("add_marks_with_chance") { params ->
|
||||
var appliedMark = false
|
||||
for (param in params.params) {
|
||||
val identifier = param.asString().asIdentifierDefaultingNamespace()
|
||||
val mark = Marks.getByIdentifier(identifier)
|
||||
|
||||
mark?.let {
|
||||
val probability = it.chance.coerceIn(0F, 1F) * 100
|
||||
val randomValue = Random.nextDouble(0.0, 100.0)
|
||||
if (randomValue < probability) {
|
||||
pokemon.exchangeMark(it, true)
|
||||
appliedMark = true
|
||||
}
|
||||
if (randomValue < probability) pokemon.exchangeMark(it, true)
|
||||
}
|
||||
}
|
||||
|
||||
DoubleValue(appliedMark)
|
||||
}
|
||||
map.put("add_potential_marks") { params ->
|
||||
for (param in params.params) {
|
||||
|
||||
+4
-3
@@ -24,14 +24,15 @@ import net.minecraft.world.entity.LivingEntity
|
||||
interface EntityQueryRequirement : Requirement {
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
val queriedEntity = pokemon.entity ?: pokemon.getOwnerPlayer() ?: return false
|
||||
return this.check(queriedEntity)
|
||||
return this.check(pokemon, queriedEntity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [LivingEntity] satisfies the requirement.
|
||||
* Checks if the given [Pokemon] & [LivingEntity] satisfies the requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param queriedEntity The [LivingEntity] that can be compared in context of a [Level].
|
||||
* @return If the requirement was satisfied.
|
||||
*/
|
||||
fun check(queriedEntity: LivingEntity): Boolean
|
||||
fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean
|
||||
}
|
||||
+4
-5
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
|
||||
/**
|
||||
* A [Requirement] that expects a [LivingEntity] to be attached to the [Pokemon].
|
||||
@@ -27,7 +26,7 @@ interface OwnerQueryRequirement : Requirement {
|
||||
override fun check(pokemon: Pokemon): Boolean {
|
||||
val owner = pokemon.getOwnerEntity() ?: return false
|
||||
return when (owner) {
|
||||
is Player -> {
|
||||
is ServerPlayer -> {
|
||||
this.checkPlayer(pokemon, owner)
|
||||
}
|
||||
is NPCEntity -> {
|
||||
@@ -38,13 +37,13 @@ interface OwnerQueryRequirement : Requirement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] & [Player] satisfies the requirement.
|
||||
* Checks if the given [Pokemon] & [ServerPlayer] satisfies the requirement.
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @param owner The [Player] that owns this [Pokemon].
|
||||
* @param owner The [ServerPlayer] that owns this [Pokemon].
|
||||
* @return If the requirement was satisfied.
|
||||
*/
|
||||
fun checkPlayer(pokemon: Pokemon, owner: Player): Boolean
|
||||
fun checkPlayer(pokemon: Pokemon, owner: ServerPlayer): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the given [Pokemon] & [NPCEntity] satisfies the requirement.
|
||||
|
||||
@@ -12,7 +12,6 @@ package com.cobblemon.mod.common.api.riding.sound
|
||||
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.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getIsSubmerged
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance
|
||||
@@ -66,21 +65,6 @@ class RideLoopSound(val ride: PokemonEntity, val soundSettings: RideSoundSetting
|
||||
return
|
||||
}
|
||||
|
||||
// Mute the sound if it's not meant to play for the passenger
|
||||
if (this.isPassenger && !this.soundSettings.playForPassengers) {
|
||||
this.volume = 0.0f
|
||||
return
|
||||
}
|
||||
|
||||
// Mute sounds when submerged unless they support underwater sounds, underwater sounds don't play above water
|
||||
if (this.ride.getIsSubmerged() && !this.soundSettings.submerged) {
|
||||
this.volume = 0.0f
|
||||
return
|
||||
} else if (!this.ride.getIsSubmerged() && this.soundSettings.submerged) {
|
||||
this.volume = 0.0f
|
||||
return
|
||||
}
|
||||
|
||||
// Perform data driven pitch and volume calculation
|
||||
this.volume = ((soundSettings.volumeExpr.let { ride.runtime.resolveDouble(it) })).toFloat()
|
||||
this.volume *= this.fade
|
||||
|
||||
-8
@@ -27,9 +27,7 @@ data class RideSoundSettings(
|
||||
val soundLocation: ResourceLocation,
|
||||
@SerializedName("volumeExpr") private val _volumeExpr: Expression? = "1.0".asExpression(),
|
||||
@SerializedName("pitchExpr") private val _pitchExpr: Expression? = "1.0".asExpression(),
|
||||
val playForPassengers: Boolean = true,
|
||||
val playForNonPassengers: Boolean = false,
|
||||
val submerged: Boolean = false,
|
||||
val muffleEnabled: Boolean = false,
|
||||
@SerializedName("attenuationModel") private val _attenuationModel: RideAttenuationModel? = RideAttenuationModel.NONE
|
||||
): Encodable {
|
||||
@@ -48,9 +46,7 @@ data class RideSoundSettings(
|
||||
buffer.writeResourceLocation(soundLocation)
|
||||
buffer.writeExpression(volumeExpr)
|
||||
buffer.writeExpression(pitchExpr)
|
||||
buffer.writeBoolean(playForPassengers)
|
||||
buffer.writeBoolean(playForNonPassengers)
|
||||
buffer.writeBoolean(submerged)
|
||||
buffer.writeBoolean(muffleEnabled)
|
||||
buffer.writeEnum(attenuationModel)
|
||||
}
|
||||
@@ -61,9 +57,7 @@ data class RideSoundSettings(
|
||||
val soundLocation = buffer.readResourceLocation()
|
||||
val volumeExpr = buffer.readExpression()
|
||||
val pitchExpr = buffer.readExpression()
|
||||
val playForPassengers = buffer.readBoolean()
|
||||
val playForNonPassengers = buffer.readBoolean()
|
||||
val submerged = buffer.readBoolean()
|
||||
val muffleEnabled = buffer.readBoolean()
|
||||
val attenuationModel = buffer.readEnum(RideAttenuationModel::class.java)
|
||||
|
||||
@@ -71,9 +65,7 @@ data class RideSoundSettings(
|
||||
soundLocation,
|
||||
volumeExpr,
|
||||
pitchExpr,
|
||||
playForPassengers,
|
||||
playForNonPassengers,
|
||||
submerged,
|
||||
muffleEnabled,
|
||||
attenuationModel
|
||||
)
|
||||
|
||||
@@ -44,7 +44,11 @@ abstract class SpawnAction<R>(
|
||||
|
||||
spawnablePosition.applyInfluences { it.affectAction(this) }
|
||||
val result = run()
|
||||
future.complete(result)
|
||||
if (result != null) {
|
||||
future.complete(result)
|
||||
} else {
|
||||
future.completeExceptionally(Exception("Nothing was spawned."))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
+3
-10
@@ -61,9 +61,7 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
|
||||
|
||||
if (detailSpecies != null && baitEVStat != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
val evYieldValue = formData.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
return when {
|
||||
evYieldValue > 0 -> {
|
||||
markUsed()
|
||||
@@ -85,9 +83,7 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
|
||||
|
||||
if (detailSpecies != null && baitTypingEffect != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
val isMatchingType = formData.types.contains(baitTypingEffect)
|
||||
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
|
||||
return when {
|
||||
isMatchingType -> {
|
||||
markUsed()
|
||||
@@ -104,9 +100,6 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
|
||||
if (detailSpecies != null) {
|
||||
val detailAspects = detail.pokemon.aspects
|
||||
val formData = detailSpecies.getForm(detailAspects)
|
||||
|
||||
// Collect all the egg group effects
|
||||
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
|
||||
|
||||
@@ -118,7 +111,7 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
|
||||
return@firstOrNull false
|
||||
}
|
||||
formData.eggGroups.contains(eggGroup)
|
||||
detailSpecies.eggGroups.contains(eggGroup)
|
||||
}
|
||||
|
||||
if (matchingEffect != null) {
|
||||
|
||||
@@ -8,58 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.stats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.stats.StatFormatter
|
||||
|
||||
object CobblemonStats {
|
||||
val stats = mutableMapOf<String, CobblemonStat>()
|
||||
val stats = mutableMapOf<String, ResourceLocation>()
|
||||
|
||||
@JvmField
|
||||
var CAPTURED: CobblemonStat = CobblemonStat("captured")
|
||||
@JvmField
|
||||
val SHINIES_CAPTURED: CobblemonStat = CobblemonStat("shinies_captured")
|
||||
@JvmField
|
||||
val RELEASED: CobblemonStat = CobblemonStat("released")
|
||||
@JvmField
|
||||
val EVOLVED: CobblemonStat = CobblemonStat("evolved")
|
||||
@JvmField
|
||||
val LEVEL_UP: CobblemonStat = CobblemonStat("level_up")
|
||||
@JvmField
|
||||
val BATTLES_WON: CobblemonStat = CobblemonStat("battles_won")
|
||||
@JvmField
|
||||
val BATTLES_LOST: CobblemonStat = CobblemonStat("battles_lost")
|
||||
@JvmField
|
||||
val BATTLES_FLED: CobblemonStat = CobblemonStat("battles_fled")
|
||||
@JvmField
|
||||
val BATTLES_TOTAL: CobblemonStat = CobblemonStat("battles_total")
|
||||
@JvmField
|
||||
val DEX_ENTRIES: CobblemonStat = CobblemonStat("dex_entries")
|
||||
@JvmField
|
||||
val EGGS_COLLECTED: CobblemonStat = CobblemonStat("eggs_collected")
|
||||
@JvmField
|
||||
val EGGS_HATCHED: CobblemonStat = CobblemonStat("eggs_hatched")
|
||||
@JvmField
|
||||
val TRADED: CobblemonStat = CobblemonStat("traded")
|
||||
@JvmField
|
||||
val FOSSILS_REVIVED: CobblemonStat = CobblemonStat("fossils_revived")
|
||||
@JvmField
|
||||
val TIMES_RIDDEN: CobblemonStat = CobblemonStat("times_ridden")
|
||||
@JvmField
|
||||
val ROD_CASTS: CobblemonStat = CobblemonStat("rod_casts")
|
||||
@JvmField
|
||||
val REEL_INS: CobblemonStat = CobblemonStat("reel_ins")
|
||||
@JvmField
|
||||
val POKEMON_INTERACTED_WITH: CobblemonStat = CobblemonStat("pokemon_interacted_with")
|
||||
@JvmField
|
||||
val RIDING_LAND: CobblemonStat = CobblemonStat("riding_land", StatFormatter.DISTANCE)
|
||||
@JvmField
|
||||
val RIDING_AIR: CobblemonStat = CobblemonStat("riding_air", StatFormatter.DISTANCE)
|
||||
@JvmField
|
||||
val RIDING_LIQUID: CobblemonStat = CobblemonStat("riding_liquid", StatFormatter.DISTANCE)
|
||||
|
||||
//TODO block, stats (interact, gimmi)
|
||||
var CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "captured") //makeCustomStat("captured", StatFormatter.DEFAULT)
|
||||
val SHINIES_CAPTURED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "shinies_captured") //makeCustomStat("shinies_captured", StatFormatter.DEFAULT)
|
||||
val RELEASED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "released") //makeCustomStat("released", StatFormatter.DEFAULT)
|
||||
val EVOLVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "evolved") //makeCustomStat("evolved", StatFormatter.DEFAULT)
|
||||
val LEVEL_UP: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "level_up") //makeCustomStat("level_up", StatFormatter.DEFAULT)
|
||||
val BATTLES_WON: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_won") //makeCustomStat("battles_won", StatFormatter.DEFAULT)
|
||||
val BATTLES_LOST: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_lost") //makeCustomStat("battles_lost", StatFormatter.DEFAULT)
|
||||
val BATTLES_FLED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_fled") //makeCustomStat("battles_fled", StatFormatter.DEFAULT)
|
||||
val BATTLES_TOTAL: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "battles_total") //makeCustomStat("battles_total", StatFormatter.DEFAULT)
|
||||
val DEX_ENTRIES: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "dex_entries") //makeCustomStat("dex_entries", StatFormatter.DEFAULT)
|
||||
val EGGS_COLLECTED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_collected") //makeCustomStat("eggs_collected", StatFormatter.DEFAULT)
|
||||
val EGGS_HATCHED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "eggs_hatched") //makeCustomStat("eggs_hatched", StatFormatter.DEFAULT)
|
||||
val TRADED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "traded") //makeCustomStat("traded", StatFormatter.DEFAULT)
|
||||
val FOSSILS_REVIVED: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "fossils_revived") //makeCustomStat("fossils_revived", StatFormatter.DEFAULT)
|
||||
val TIMES_RIDDEN: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "times_ridden")
|
||||
val ROD_CASTS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "rod_casts")
|
||||
val REEL_INS: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "reel_ins")
|
||||
val POKEMON_INTERACTED_WITH: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", "pokemon_interacted_with") //makeCustomStat("pokemon_interacted_with", StatFormatter.DEFAULT)
|
||||
//TODO block, stats (interact, gimmi), riding (styles?)
|
||||
|
||||
fun registerStats() {
|
||||
stats["captured"] = CAPTURED
|
||||
@@ -80,22 +52,5 @@ object CobblemonStats {
|
||||
stats["rod_casts"] = ROD_CASTS
|
||||
stats["reel_ins"] = REEL_INS
|
||||
stats["pokemon_interacted_with"] = POKEMON_INTERACTED_WITH
|
||||
stats["riding_land"] = RIDING_LAND
|
||||
stats["riding_air"] = RIDING_AIR
|
||||
stats["riding_liquid"] = RIDING_LIQUID
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getStat(cobblemonStat: CobblemonStat) : ResourceLocation {
|
||||
val resourceLocation = cobblemonStat.resourceLocation
|
||||
val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)
|
||||
if (stat == null) {
|
||||
Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation)
|
||||
}
|
||||
return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation")
|
||||
}
|
||||
|
||||
data class CobblemonStat(val path: String, val formatter: StatFormatter = StatFormatter.DEFAULT) {
|
||||
val resourceLocation: ResourceLocation = ResourceLocation.fromNamespaceAndPath("cobblemon", path);
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,6 @@ object BattleBuilder {
|
||||
val side1Theme = players[0].getBattleTheme()
|
||||
val side2Theme = players[2].getBattleTheme()
|
||||
|
||||
// the music that's played for a side is driven by the opposite leader's theme
|
||||
side1Actors.forEach { it.battleTheme = side2Theme }
|
||||
side2Actors.forEach { it.battleTheme = side1Theme }
|
||||
|
||||
|
||||
@@ -192,7 +192,6 @@ object CobblemonClient {
|
||||
}
|
||||
}
|
||||
}
|
||||
BattleMusicController.onTick()
|
||||
ClientPlayerIcon.onTick()
|
||||
PartyOverlayDataControl.tick(event.client.isPaused)
|
||||
}
|
||||
|
||||
+1
-6
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController
|
||||
import com.cobblemon.mod.common.client.sound.instances.BattleMusicInstance
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.ost.BattleThemes
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
|
||||
@@ -27,12 +26,8 @@ object BattleMusicHandler : ClientNetworkPacketHandler<BattleMusicPacket> {
|
||||
override fun handle(packet: BattleMusicPacket, client: Minecraft) {
|
||||
val soundManager = client.soundManager
|
||||
val currMusic = BattleMusicController.music
|
||||
|
||||
// TODO to support legacy behavior, use ResourceLocation for BattleTrackConfig THEN SoundEvent
|
||||
|
||||
val newMusic = packet.music?.let {
|
||||
val location = BattleThemes.getByIdentifier(it)?.dispatchTrack()? ?: it
|
||||
val event = SoundEvent.createVariableRangeEvent(location)
|
||||
val event = SoundEvent.createVariableRangeEvent(it)
|
||||
BattleMusicInstance(event, packet.volume, packet.pitch)
|
||||
}
|
||||
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.net.data
|
||||
|
||||
import com.cobblemon.mod.common.api.interaction.PokemonInteractions
|
||||
import com.cobblemon.mod.common.api.net.ClientNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PokemonInteractionsSyncPacket
|
||||
import net.minecraft.client.Minecraft
|
||||
|
||||
object PokemonInteractionsSyncHandler : ClientNetworkPacketHandler<PokemonInteractionsSyncPacket> {
|
||||
|
||||
override fun handle(
|
||||
packet: PokemonInteractionsSyncPacket,
|
||||
client: Minecraft,
|
||||
) {
|
||||
PokemonInteractions.speciesInteractions.clear()
|
||||
PokemonInteractions.speciesInteractions.addAll(packet.speciesInteractions)
|
||||
PokemonInteractions.generalInteractions.clear()
|
||||
PokemonInteractions.generalInteractions.addAll(packet.generalInteractions)
|
||||
}
|
||||
}
|
||||
+5
-21
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.persisted
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
import java.io.BufferedReader
|
||||
import java.io.BufferedWriter
|
||||
@@ -33,14 +31,7 @@ object ClientPersistedData {
|
||||
fun readSnapshotsData() : SnapshotAcknowledgementData? {
|
||||
if (snapshotsPath.exists()) {
|
||||
BufferedReader(InputStreamReader(FileInputStream(snapshotsPath.toFile()))).use { reader ->
|
||||
try {
|
||||
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
|
||||
} catch (exception: Exception) {
|
||||
LOGGER.error("Failed to load snapshots.json... Resetting File")
|
||||
val data = SnapshotAcknowledgementData(Cobblemon.VERSION, false)
|
||||
writeSnapshotsData(data)
|
||||
return data
|
||||
}
|
||||
return gson.fromJson(reader, SnapshotAcknowledgementData::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,23 +46,16 @@ object ClientPersistedData {
|
||||
fun readRidingPerspectivesData() : RidingPerspectiveData? {
|
||||
if (ridingPerspectivesPath.exists()) {
|
||||
BufferedReader(InputStreamReader(FileInputStream(ridingPerspectivesPath.toFile()))).use { reader ->
|
||||
try {
|
||||
return gson.fromJson(reader, RidingPerspectiveData::class.java)
|
||||
} catch (exception: Exception) {
|
||||
LOGGER.error("Failed to load riding_perspectives.json... Resetting File")
|
||||
val data = RidingPerspectiveData()
|
||||
saveRidingPerspectivesData(data)
|
||||
return data
|
||||
}
|
||||
return gson.fromJson(reader, RidingPerspectiveData::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun saveRidingPerspectivesData(data: RidingPerspectiveData) {
|
||||
fun saveRidingPerspectivesData() {
|
||||
ridingPerspectivesPath.toFile().parentFile.mkdirs()
|
||||
BufferedWriter(FileWriter(ridingPerspectivesPath.toFile())).use { writer -> gson.toJson(data, writer) }
|
||||
BufferedWriter(FileWriter(ridingPerspectivesPath.toFile())).use { writer -> gson.toJson(ridingPerspectives, writer) }
|
||||
}
|
||||
|
||||
data class SnapshotAcknowledgementData(val version: String, val dontShowAgain: Boolean)
|
||||
@@ -80,7 +64,7 @@ object ClientPersistedData {
|
||||
) {
|
||||
fun updatePerspective(key: ResourceLocation, cameraType: CameraType) {
|
||||
perspectives[key] = cameraType
|
||||
saveRidingPerspectivesData(this)
|
||||
saveRidingPerspectivesData()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,6 @@
|
||||
package com.cobblemon.mod.common.client.sound
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.instances.BattleMusicInstance
|
||||
import com.cobblemon.mod.common.ost.BattleMusicCue
|
||||
import com.cobblemon.mod.common.ost.BattleThemeConfig
|
||||
import com.cobblemon.mod.common.util.pauseSounds
|
||||
import com.cobblemon.mod.common.util.resumeSounds
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -25,15 +23,6 @@ import net.minecraft.sounds.SoundEvents
|
||||
*/
|
||||
object BattleMusicController {
|
||||
|
||||
/** The active [BattleThemeConfig] for dispatching [BattleMusicInstance]s and subscribing to [BattleMusicCue]s. */
|
||||
private var config: BattleThemeConfig? = null
|
||||
|
||||
/** The queued [BattleMusicCue]. */
|
||||
private var queuedCue: BattleMusicCue? = null
|
||||
|
||||
/** The active [BattleMusicCue]. */
|
||||
private var activeCue: BattleMusicCue? = null
|
||||
|
||||
/** The last [BattleMusicInstance] played. */
|
||||
var music = BattleMusicInstance(SoundEvents.EMPTY, 0.0F, 0.0F)
|
||||
private set
|
||||
@@ -67,13 +56,4 @@ object BattleMusicController {
|
||||
/** Fade out and end the current [BattleMusicInstance]. */
|
||||
fun endMusic() = music.setFade()
|
||||
|
||||
/** Processes the [queuedCue]. */
|
||||
private fun processCue(cue: BattleMusicCue) {
|
||||
|
||||
}
|
||||
|
||||
/** */
|
||||
fun onTick() {
|
||||
|
||||
}
|
||||
}
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
package com.cobblemon.mod.common.client.sound.streams
|
||||
|
||||
import net.minecraft.client.sounds.AudioStream
|
||||
import java.nio.ByteBuffer
|
||||
import javax.sound.sampled.AudioFormat
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
/**
|
||||
* An [AudioStream] composed of multiple streams stitched together.
|
||||
*
|
||||
* Bytes of audio are read according to the active stream's implementation of [AudioStream.read].
|
||||
*
|
||||
* @param streams The [AudioStream]s to chain sequentially. Each stream must share the same [AudioFormat].
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since October 19th, 2025
|
||||
*/
|
||||
class CompoundAudioStream @Throws(IllegalArgumentException::class) constructor(vararg streams: AudioStream): AudioStream {
|
||||
|
||||
private val streams = streams.iterator()
|
||||
|
||||
/** The [AudioStream] currently playing. */
|
||||
private var runningStream: AudioStream = this.streams.next()
|
||||
|
||||
private val format = this.runningStream.format
|
||||
|
||||
override fun getFormat() = format
|
||||
|
||||
init {
|
||||
/* Enqueuing buffers of different formats to the same source is not permissible in OpenAL 1.1 standard. */
|
||||
streams.filterNot { runningStream.format.matches(it.format) }.takeIf { it.isNotEmpty() }?.let { incompatibleStreams ->
|
||||
val message = StringBuilder("Cannot compose CompoundAudioStream from streams of different formats:\n${runningStream.format}")
|
||||
incompatibleStreams.forEach {
|
||||
message.append("\n${it.format}")
|
||||
}
|
||||
throw IllegalArgumentException(message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads [size] bytes of PCM, from the current [runningStream], for 1 second worth of audio. */
|
||||
override fun read(size: Int): ByteBuffer? {
|
||||
var buffer = this.runningStream.read(size)
|
||||
if (!buffer.hasRemaining() && this.streams.hasNext()) {
|
||||
this.runningStream.close()
|
||||
this.runningStream = this.streams.next()
|
||||
buffer = this.runningStream.read(size)
|
||||
}
|
||||
return buffer // it's fine if the buffer is not completely full - the stream will sound seamless
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
this.runningStream.close()
|
||||
while (streams.hasNext()) streams.next().close()
|
||||
}
|
||||
}
|
||||
-286
@@ -1,286 +0,0 @@
|
||||
package com.cobblemon.mod.common.client.sound.streams
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.mojang.blaze3d.audio.Channel
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.client.sounds.AudioStream
|
||||
import net.minecraft.client.sounds.LoopingAudioStream
|
||||
import org.lwjgl.BufferUtils
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import javax.sound.sampled.AudioFormat
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* An [AudioStream] divided into an intro substream and a loop substream, determined by loop points provided with the Sound resource.
|
||||
*
|
||||
* Similar to [LoopingAudioStream], the loop will play indefinitely until stopped.
|
||||
*
|
||||
* @param provider Provider for creating the internal [AudioStream] that decodes the audio.
|
||||
* @param primaryInputStream The initial [InputStream] of the encoded audio to play.
|
||||
* @param loopStart The starting point of the main audio loop in SAMPLES. If 0, loop will run from start until the [loopEnd].
|
||||
* @param loopEnd The ending point of the main audio loop in SAMPLES. If 0, loop will run to completion.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since October 19th, 2025
|
||||
*/
|
||||
class LoopPointAudioStream @Throws(IllegalArgumentException::class) constructor(
|
||||
private val provider: LoopingAudioStream.AudioStreamProvider,
|
||||
primaryInputStream: InputStream,
|
||||
loopStart: Int = 0,
|
||||
loopEnd: Int = 0
|
||||
): AudioStream {
|
||||
|
||||
private val DEBUG_FLAG = true
|
||||
|
||||
/** Amount of buffers of decoded PCM, from the start of the loop, to cache. */
|
||||
private val CACHE_LIMIT = Channel.QUEUED_BUFFER_COUNT // CACHE_LIMIT matches the number of buffers pre-read before feeding to OpenAL
|
||||
|
||||
/** Buffers of PCM that start the loop. */
|
||||
private val bufferCache = mutableListOf<ByteBuffer>() // cache size: 4 buffers, each of size ~176400 (70kb of cache) which is fine
|
||||
|
||||
/** The total number of bytes saved in the [bufferCache]. */
|
||||
private var cacheSize = 0
|
||||
|
||||
/** The number of buffers read from the [bufferCache] */
|
||||
private var bufferCounter = 0
|
||||
|
||||
/** The bytes bytween the end of the cache and the start of the rewinded [decoderStream]. */
|
||||
private var preliminaryBuffer: ByteBuffer? = null
|
||||
|
||||
/** Whether the [preliminaryBuffer] has been read on this pass. */
|
||||
private var readPrem: Boolean = false
|
||||
|
||||
/** The OGG Vorbis. This is encoded audio. */
|
||||
private lateinit var encodedStream: BufferedInputStream
|
||||
|
||||
/** The Vorbis decoder. This decodes PCM from the [encodedStream] on calls to [AudioStream.read]. */
|
||||
private lateinit var decoderStream: AudioStream
|
||||
|
||||
/** The starting point of the loop in BYTES. */
|
||||
private var loopStart by Delegates.notNull<Int>()
|
||||
|
||||
/** The ending point of the loop in BYTES. */
|
||||
private var loopEnd by Delegates.notNull<Int>()
|
||||
|
||||
/** Whether this is the first pass of the [encodedStream] and we haven't looped yet. */
|
||||
private var firstPass = true
|
||||
|
||||
/** Whether [decoderStream] has been rewinded to [loopStart]. */
|
||||
private var loopPrepared = false
|
||||
|
||||
/** The total number of bytes that have been read from the decoded stream. */
|
||||
private var runningRead = 0
|
||||
|
||||
init {
|
||||
if (loopStart > 0 && loopEnd > 0 && loopEnd < loopStart) throw IllegalArgumentException("Invalid loop points: non-zero end precedes non-zero start")
|
||||
if (loopStart < 0 || loopEnd < 0) throw IllegalArgumentException("Invalid loop points: only non-negative values allowed")
|
||||
|
||||
this.encodedStream = BufferedInputStream(primaryInputStream)
|
||||
this.encodedStream.mark(Int.Companion.MAX_VALUE)
|
||||
this.buildDecoderStream()
|
||||
|
||||
this.loopStart = this.samplesToBytes(loopStart)
|
||||
this.loopEnd = this.samplesToBytes(loopEnd)
|
||||
}
|
||||
|
||||
override fun getFormat(): AudioFormat? {
|
||||
return this.decoderStream.format
|
||||
}
|
||||
|
||||
/** Reads 1 second worth of PCM (bytes) for an OpenAL buffer (this will be AT LEAST 176400 bytes for stereo audio formats) */
|
||||
override fun read(size: Int): ByteBuffer? {
|
||||
|
||||
// if decoderStream has not finished rewinding, there's a problem
|
||||
if (!this.firstPass && !this.loopPrepared) {
|
||||
Cobblemon.LOGGER.warn("Decoder not rewinded!")
|
||||
}
|
||||
|
||||
this.debug("read " + size + " | runningRead: " + this.runningRead + " | loopStart: " + this.loopStart + " | loopEnd: " + this.loopEnd)
|
||||
|
||||
val buffer = this.getCachedOrRawBuffer(size)
|
||||
val sizeAfterRead = this.runningRead + buffer.remaining()
|
||||
|
||||
// if this read reaches the end loop point
|
||||
if (loopEnd > 0 && sizeAfterRead >= this.loopEnd) {
|
||||
val remainderBeforeEnd = this.loopEnd - this.runningRead
|
||||
// limit buffer if it goes past the loop point (cached buffers don't apply as they are always within the loop points)
|
||||
if (buffer.remaining() > remainderBeforeEnd)
|
||||
{
|
||||
this.debug("limit and reset read")
|
||||
buffer.limit(remainderBeforeEnd)
|
||||
}
|
||||
else {
|
||||
this.debug("reset read")
|
||||
}
|
||||
this.resetLoop()
|
||||
}
|
||||
// if loopEnd is 0 and the entire stream is read, or exaggerated and the stream is exhausted before reaching the point
|
||||
else if (!buffer.hasRemaining()) {
|
||||
this.debug("exhaustive read")
|
||||
this.resetLoop()
|
||||
}
|
||||
// standard read
|
||||
else {
|
||||
this.debug("standard read")
|
||||
this.runningRead += buffer.remaining();
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a [ByteBuffer] of varying size from the [bufferCache] if this is not the [firstPass] and a cached buffer
|
||||
* is available, or reads approximately [size] bytes from the [decoderStream].
|
||||
*/
|
||||
private fun getCachedOrRawBuffer(size: Int): ByteBuffer {
|
||||
val cacheExists = CACHE_LIMIT > 0 && !this.bufferCache.isEmpty() && this.bufferCounter < this.bufferCache.size
|
||||
|
||||
// get buffer from cache
|
||||
if (cacheExists && !this.firstPass) {
|
||||
val toReturn = this.bufferCache.get(this.bufferCounter++)
|
||||
this.debug("get cached buffer: " + toReturn.remaining())
|
||||
return toReturn
|
||||
}
|
||||
// TODO coalesce this with bufferCache
|
||||
else if (!this.readPrem && this.preliminaryBuffer != null && !this.firstPass) {
|
||||
this.readPrem = true
|
||||
val toReturn = this.preliminaryBuffer!!
|
||||
this.debug("read prem buffer: " + toReturn.remaining())
|
||||
return toReturn
|
||||
}
|
||||
// decode a buffer of approximate size
|
||||
else {
|
||||
val toReturn = this.decoderStream.read(size)
|
||||
this.debug("read raw: " + toReturn.remaining())
|
||||
this.cacheBuffer(toReturn)
|
||||
return toReturn
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches [buffer] in the [bufferCache] during the [firstPass] if the [CACHE_LIMIT] has not been reached and the buffer
|
||||
* contains bytes within the [loopStart] and the [loopEnd] boundaries.
|
||||
*/
|
||||
private fun cacheBuffer(buffer: ByteBuffer) {
|
||||
val canCacheBuffer = CACHE_LIMIT > 0 && loopStart > 0 && this.bufferCache.size < CACHE_LIMIT && this.firstPass
|
||||
val canStartCaching = this.runningRead + buffer.remaining() > this.loopStart
|
||||
if (!canCacheBuffer || !canStartCaching) return
|
||||
|
||||
// offset used - so that only the tail of a buffer that contains the loopStart point is cached
|
||||
val remainderBeforeStart = Math.max(this.loopStart - this.runningRead, 0)
|
||||
var remainderBeforeEnd = 0
|
||||
|
||||
// only cache the head of a buffer that goes past the loopEnd point
|
||||
if (loopEnd > 0 && buffer.remaining() + this.runningRead > this.loopEnd) {
|
||||
remainderBeforeEnd = this.loopEnd - this.runningRead - remainderBeforeStart
|
||||
// NOTE: read will resetLoop and stop caching if CACHE_LIMIT has not been reached but loopEnd has
|
||||
}
|
||||
// otherwise, cache the entire remainder of the buffer
|
||||
else {
|
||||
remainderBeforeEnd = buffer.remaining() - remainderBeforeStart
|
||||
}
|
||||
|
||||
if (remainderBeforeEnd <= 0) return
|
||||
|
||||
// copy to avoid mutating provided buffer
|
||||
val buffed = BufferUtils.createByteBuffer(remainderBeforeEnd)
|
||||
buffed.put(0, buffer, remainderBeforeStart, remainderBeforeEnd)
|
||||
buffed.rewind()
|
||||
|
||||
this.debug("cache buffer | remainderBeforeStart: " + remainderBeforeStart + " | remainderBeforeEnd: " + remainderBeforeEnd + " | size: " + buffed.remaining())
|
||||
|
||||
this.bufferCache.add(buffed)
|
||||
this.cacheSize += buffed.remaining()
|
||||
|
||||
this.debug("cacheSize: " + cacheSize + " bufferCacheSize: " + this.bufferCache.size)
|
||||
}
|
||||
|
||||
/** Converts PCM samples to bytes. */
|
||||
private fun samplesToBytes(sampleAmount: Int): Int {
|
||||
val format = this.format ?: return 0
|
||||
return sampleAmount * format.getSampleSizeInBits() / 8 * format.getChannels()
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind [decoderStream] to start from [loopStart].
|
||||
*
|
||||
* NOTE: Assumes that [bufferCache] is finalized.
|
||||
*/
|
||||
private fun resetLoop() {
|
||||
// reset state info
|
||||
this.loopPrepared = false
|
||||
this.runningRead = this.loopStart
|
||||
this.bufferCounter = 0
|
||||
this.firstPass = false
|
||||
|
||||
this.debug("reset")
|
||||
|
||||
// if the entire loop is small enough to fit the cache, skip rewinding the decoderStream
|
||||
if (this.bufferCache.size > 0 && this.bufferCache.size < CACHE_LIMIT) {
|
||||
this.debug("comprehensive cache")
|
||||
this.loopPrepared = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Seeking is implemented agnostic of the OGG Vorbis decoder. Seek to the loop start by decoding PCM in bulk from
|
||||
the beginning of the OGG Vorbis up until the desired sample offset is reached. Then for playing the loop, continue
|
||||
streaming decoded PCM into OpenAL buffers.
|
||||
*/
|
||||
this.decoderStream.close()
|
||||
this.encodedStream.reset()
|
||||
this.buildDecoderStream()
|
||||
|
||||
// if loopStart is 0, there's no cache, so loop starts by reading from the new decoderStream
|
||||
if (this.bufferCache.size == 0) {
|
||||
this.debug("nonexistent cache")
|
||||
this.loopPrepared = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
After the first pass, encodedStream will have the entire Vorbis OGG buffered and there won't be any subsequent reads
|
||||
from disk. However, there's still latency in decoding a lot of PCM. This needs to be done asynchronously, otherwise
|
||||
the client will momentarily freeze each time the loop resets. In the unlikely case that the decoderStream is not
|
||||
rewinded by the time the Channel needs to read a buffer, it will be read from bufferCache.
|
||||
*/
|
||||
CompletableFuture.supplyAsync<Any?>({
|
||||
try {
|
||||
val decoderStart = this.loopStart + this.cacheSize
|
||||
val buffer = decoderStream.read(decoderStart)
|
||||
|
||||
// because the deecoderStream will only read an approximation, need to account for additional bytes
|
||||
if (this.preliminaryBuffer == null && buffer.remaining() > decoderStart) {
|
||||
this.debug("rewind buffer size: " + buffer.remaining() + " overshot by: " + (buffer.remaining() - decoderStart))
|
||||
this.preliminaryBuffer = BufferUtils.createByteBuffer(buffer.remaining() - decoderStart)
|
||||
this.preliminaryBuffer!!.put(0, buffer, decoderStart, buffer.remaining() - decoderStart)
|
||||
this.preliminaryBuffer!!.rewind()
|
||||
// decoderStream.read is deterministic, so this should only be set once
|
||||
}
|
||||
this.readPrem = false
|
||||
this.loopPrepared = true
|
||||
this.debug("decoderStream rewinded")
|
||||
return@supplyAsync null
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}, Util.nonCriticalIoPool())
|
||||
}
|
||||
|
||||
private fun buildDecoderStream() {
|
||||
this.decoderStream = provider.create(LoopingAudioStream.NoCloseBuffer(this.encodedStream))
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
this.decoderStream.close()
|
||||
this.encodedStream.close() // closes the InputStream used
|
||||
}
|
||||
|
||||
private fun debug(log: String) {
|
||||
if (this.DEBUG_FLAG) Cobblemon.LOGGER.error(log)
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -802,14 +802,13 @@ class PokeRodFishingBobberEntity(type: EntityType<out PokeRodFishingBobberEntity
|
||||
|
||||
spawnAction.complete()
|
||||
val result = spawnAction.future
|
||||
val resultingSpawn = result.get()
|
||||
|
||||
if (resultingSpawn == null) {
|
||||
if (result.isCompletedExceptionally) {
|
||||
noBite(player)
|
||||
return false
|
||||
}
|
||||
|
||||
var spawnedPokemon: PokemonEntity? = null
|
||||
val resultingSpawn = result.get()
|
||||
|
||||
if (resultingSpawn is EntitySpawnResult) {
|
||||
for (entity in resultingSpawn.entities) {
|
||||
|
||||
@@ -1208,13 +1208,14 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
if (hand == InteractionHand.MAIN_HAND) {
|
||||
if (player.isShiftKeyDown && player is ServerPlayer) {
|
||||
if (hand == InteractionHand.MAIN_HAND && player is ServerPlayer) {
|
||||
if (player.isShiftKeyDown) {
|
||||
showInteractionWheel(player, itemStack)
|
||||
return InteractionResult.sidedSuccess(level().isClientSide)
|
||||
}
|
||||
else if (this.ownerUUID == player.uuid && this.attemptItemInteraction(player, player.getItemInHand(hand))) {
|
||||
return InteractionResult.sidedSuccess(level().isClientSide)
|
||||
else if (pokemon.getOwnerPlayer() == player) {
|
||||
// TODO #105
|
||||
if (this.attemptItemInteraction(player, player.getItemInHand(hand))) return InteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1281,7 +1282,7 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
override fun shouldBeSaved(): Boolean {
|
||||
if (ownerUUID == null && !pokemon.isNPCOwned() && (Cobblemon.config.savePokemonToWorld || isPersistenceRequired)) {
|
||||
if (ownerUUID == null && !pokemon.isNPCOwned() && (Cobblemon.config.savePokemonToWorld || isPersistenceRequired || this.pokemon.canDropHeldItem)) {
|
||||
CobblemonEvents.POKEMON_ENTITY_SAVE_TO_WORLD.postThen(PokemonEntitySaveToWorldEvent(this)) {
|
||||
return true
|
||||
}
|
||||
@@ -1390,24 +1391,18 @@ open class PokemonEntity(
|
||||
return bagItemLike.handleInteraction(player, battlePokemon, stack)
|
||||
}
|
||||
|
||||
if (this.isBusy) {
|
||||
if (player !is ServerPlayer || this.isBusy) {
|
||||
return false
|
||||
}
|
||||
|
||||
val interaction = PokemonInteractions.findInteraction(this)
|
||||
|
||||
if (interaction != null && !pokemon.isOnInteractionCooldown(interaction.grouping)) {
|
||||
if (player is ServerPlayer) {
|
||||
interaction.effects.forEach { it.applyEffect(this, player) }
|
||||
pokemon.interactionCooldowns.put(interaction.grouping, runtime.resolveInt(interaction.cooldown))
|
||||
}
|
||||
|
||||
interaction.effects.forEach { it.applyEffect(this, player) }
|
||||
pokemon.interactionCooldowns.put(interaction.grouping, runtime.resolveInt(interaction.cooldown))
|
||||
return true
|
||||
}
|
||||
|
||||
if (player !is ServerPlayer) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Evolution item logic
|
||||
if (pokemon.getOwnerPlayer() == player) {
|
||||
val context = ItemInteractionEvolution.ItemInteractionContext(stack, player.level())
|
||||
|
||||
@@ -30,13 +30,21 @@ import com.cobblemon.mod.common.api.events.battles.BattleStartedEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleVictoryEvent
|
||||
import com.cobblemon.mod.common.api.events.fishing.PokerodCastEvent
|
||||
import com.cobblemon.mod.common.api.events.fishing.PokerodReelEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.*
|
||||
import com.cobblemon.mod.common.api.events.pokemon.CollectEggEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.HatchEggEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.LevelUpEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.PokemonCapturedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.PokemonGainedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.RidePokemonEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.TradeEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
|
||||
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats.getStat
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
|
||||
object StatHandler : EventHandler {
|
||||
override fun registerListeners() {
|
||||
@@ -92,13 +100,13 @@ object StatHandler : EventHandler {
|
||||
|
||||
fun onBattleStart(event : BattleStartedEvent) {
|
||||
event.battle.players.forEach { player ->
|
||||
player.awardStat(getStat(Cobblemon.statistics.BATTLES_TOTAL))
|
||||
player.awardStat(this.getStat(getStat(Cobblemon.statistics.BATTLES_TOTAL)))
|
||||
}
|
||||
}
|
||||
|
||||
fun onDexEntryGain(event : PokemonGainedEvent) {
|
||||
val player = event.pokemon.getOwnerPlayer()
|
||||
player?.awardStat(getStat(Cobblemon.statistics.DEX_ENTRIES))
|
||||
player?.awardStat(getStat(getStat(Cobblemon.statistics.DEX_ENTRIES)))
|
||||
}
|
||||
|
||||
fun onCollectEgg(event : CollectEggEvent) {
|
||||
@@ -131,4 +139,12 @@ object StatHandler : EventHandler {
|
||||
fun onReelIn(event : PokerodReelEvent) {
|
||||
event.player.awardStat(getStat(Cobblemon.statistics.REEL_INS))
|
||||
}
|
||||
|
||||
fun getStat(resourceLocation: ResourceLocation) : ResourceLocation {
|
||||
val stat = BuiltInRegistries.CUSTOM_STAT.get(resourceLocation)
|
||||
if (stat == null) {
|
||||
Cobblemon.LOGGER.error("Could not find stat with id {}", resourceLocation)
|
||||
}
|
||||
return stat ?: throw NullPointerException("Could not find stat with id $resourceLocation")
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,10 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.item.Equipable
|
||||
|
||||
class WearableItem(val name: String): CobblemonItem(Properties()), Equipable {
|
||||
class WearableItem(
|
||||
val name: String,
|
||||
val armorEquipmentSlot: EquipmentSlot = EquipmentSlot.HEAD,
|
||||
): CobblemonItem(Properties()), Equipable {
|
||||
companion object {
|
||||
const val MODEL_PATH = "item/wearable"
|
||||
}
|
||||
@@ -21,5 +24,7 @@ class WearableItem(val name: String): CobblemonItem(Properties()), Equipable {
|
||||
fun getModel3d(): ResourceLocation = cobblemonResource("${MODEL_PATH}/${this.name}")
|
||||
fun getModel2d(): ResourceLocation = cobblemonResource(this.name)
|
||||
|
||||
override fun getEquipmentSlot(): EquipmentSlot { return EquipmentSlot.HEAD }
|
||||
override fun getEquipmentSlot(): EquipmentSlot {
|
||||
return armorEquipmentSlot
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,9 @@ class MochiItem(stat: Stats): EVIncreaseItem(stat, 4) {
|
||||
}
|
||||
|
||||
pokemon.feedPokemon(1)
|
||||
|
||||
|
||||
stack.consume(1, player)
|
||||
|
||||
return super.applyToPokemon(player, stack, pokemon)
|
||||
}
|
||||
}
|
||||
+3
-10
@@ -35,16 +35,9 @@ class SinisterTeaItem : Item(
|
||||
val effectsComponent = stack.get(CobblemonItemComponents.MOB_EFFECTS)
|
||||
|
||||
if (effectsComponent != null) {
|
||||
for (raw in effectsComponent.mobEffects) {
|
||||
val inst = MobEffectInstance(raw)
|
||||
val holder = inst.effect
|
||||
val effect = holder.value()
|
||||
|
||||
if (effect.isInstantenous) {
|
||||
effect.applyInstantenousEffect(user as? Player, null, user, inst.amplifier, 1.0)
|
||||
} else {
|
||||
user.addEffect(inst)
|
||||
}
|
||||
for (effect in effectsComponent.mobEffects) {
|
||||
val effectCopy = MobEffectInstance(effect)
|
||||
user.addEffect(effectCopy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -20,10 +20,8 @@ import net.minecraft.resources.ResourceLocation
|
||||
*
|
||||
* Handled by [com.cobblemon.mod.common.client.net.battle.BattleMusicHandler].
|
||||
*
|
||||
* @property music The location of a [SoundEvent], or the location of the []to dispatch a sound from, to play during a battle.
|
||||
* If null, gracefully ends the currently playing sound.
|
||||
*
|
||||
* @property restartExisting If true and [music] matches the location of the currently playing sound, will restart from the beginning.
|
||||
* @property music The location of the sound to play during a battle. If null, gracefully ends the currently playing sound.
|
||||
* @property restartExisting If true and the location of [music] matches the currently playing sound, will restart from the beginning.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since April 20th, 2023
|
||||
|
||||
-48
@@ -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.data
|
||||
|
||||
import com.cobblemon.mod.common.api.interaction.PokemonInteractionSet
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class PokemonInteractionsSyncPacket(
|
||||
val speciesInteractions: List<PokemonInteractionSet>,
|
||||
val generalInteractions: List<PokemonInteractionSet>,
|
||||
) : NetworkPacket<PokemonInteractionsSyncPacket> {
|
||||
override val id = ID
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeCollection(speciesInteractions) { it, speciesInteraction ->
|
||||
speciesInteraction.encode(it)
|
||||
}
|
||||
buffer.writeCollection(generalInteractions) { it, generalInteraction ->
|
||||
generalInteraction.encode(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("pokemon_interactions_sync")
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): PokemonInteractionsSyncPacket {
|
||||
val speciesInteractions = buffer.readList { it ->
|
||||
PokemonInteractionSet.decode(it)
|
||||
}
|
||||
val generalInteractions = buffer.readList { it ->
|
||||
PokemonInteractionSet.decode(it)
|
||||
}
|
||||
|
||||
return PokemonInteractionsSyncPacket(
|
||||
speciesInteractions,
|
||||
generalInteractions,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
package com.cobblemon.mod.common.net.messages.client.data
|
||||
|
||||
class SoundTrackConfigRegistrySyncPacket {
|
||||
}
|
||||
+1
-3
@@ -21,9 +21,7 @@ class PokemonStateUpdatePacket(pokemon: () -> Pokemon?, value: PokemonState): Si
|
||||
value.writeToBuffer(buffer)
|
||||
}
|
||||
|
||||
override fun set(pokemon: Pokemon, value: PokemonState) {
|
||||
pokemon.state = value
|
||||
}
|
||||
override fun set(pokemon: Pokemon, value: PokemonState) { pokemon.state = value }
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("state_update")
|
||||
|
||||
+10
-24
@@ -13,24 +13,30 @@ import com.cobblemon.mod.common.api.mark.Marks
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.client.CobblemonClient
|
||||
import com.cobblemon.mod.common.entity.PlatformType
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readEnumConstant
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.readText
|
||||
import com.cobblemon.mod.common.util.writeEnumConstant
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.cobblemon.mod.common.util.writeText
|
||||
import java.util.UUID
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.Entity
|
||||
import java.util.*
|
||||
|
||||
class SpawnPokemonPacket(
|
||||
var ownerId: UUID?,
|
||||
var pokemonUUID: UUID,
|
||||
var storageUUID: UUID?,
|
||||
var scaleModifier: Float,
|
||||
var speciesId: ResourceLocation,
|
||||
var gender: Gender,
|
||||
@@ -55,7 +61,6 @@ class SpawnPokemonPacket(
|
||||
var tickSpawned: Int,
|
||||
var rideBoosts: Map<RidingStat, Float>,
|
||||
var rideStamina: Float,
|
||||
var silent: Boolean,
|
||||
vanillaSpawnPacket: ClientboundAddEntityPacket,
|
||||
) : SpawnExtraDataEntityPacket<SpawnPokemonPacket, PokemonEntity>(vanillaSpawnPacket) {
|
||||
|
||||
@@ -64,7 +69,6 @@ class SpawnPokemonPacket(
|
||||
constructor(entity: PokemonEntity, vanillaSpawnPacket: ClientboundAddEntityPacket) : this(
|
||||
entity.ownerUUID,
|
||||
entity.pokemon.uuid,
|
||||
entity.pokemon.storeCoordinates.get()?.store?.uuid,
|
||||
entity.pokemon.scaleModifier,
|
||||
entity.exposedSpecies.resourceIdentifier,
|
||||
entity.pokemon.gender,
|
||||
@@ -89,14 +93,12 @@ class SpawnPokemonPacket(
|
||||
entity.tickCount,
|
||||
entity.entityData.get(PokemonEntity.RIDE_BOOSTS),
|
||||
entity.entityData.get(PokemonEntity.RIDE_STAMINA),
|
||||
entity.isSilent,
|
||||
vanillaSpawnPacket
|
||||
)
|
||||
|
||||
override fun encodeEntityData(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeNullable(ownerId) { _, v -> buffer.writeUUID(v) }
|
||||
buffer.writeUUID(this.pokemonUUID)
|
||||
buffer.writeNullable(this.storageUUID) { pb, value -> pb.writeUUID(value) }
|
||||
buffer.writeFloat(this.scaleModifier)
|
||||
buffer.writeIdentifier(this.speciesId)
|
||||
buffer.writeEnumConstant(this.gender)
|
||||
@@ -125,21 +127,10 @@ class SpawnPokemonPacket(
|
||||
{ _, value -> buffer.writeFloat(value) }
|
||||
)
|
||||
buffer.writeFloat(rideStamina)
|
||||
buffer.writeBoolean(silent)
|
||||
}
|
||||
|
||||
override fun applyData(entity: PokemonEntity, level: ClientLevel) {
|
||||
entity.ownerUUID = ownerId
|
||||
|
||||
// Reuse the stored Pokémon instance to avoid creating a duplicate,
|
||||
// preventing client/entity desync issues.
|
||||
this@SpawnPokemonPacket.storageUUID?.let {
|
||||
val storedPokemon = CobblemonClient.storage.locatePokemon(it, this@SpawnPokemonPacket.pokemonUUID)
|
||||
if (storedPokemon != null) {
|
||||
entity.pokemon = storedPokemon
|
||||
}
|
||||
}
|
||||
|
||||
entity.pokemon.apply {
|
||||
uuid = this@SpawnPokemonPacket.pokemonUUID
|
||||
scaleModifier = this@SpawnPokemonPacket.scaleModifier
|
||||
@@ -171,7 +162,6 @@ class SpawnPokemonPacket(
|
||||
entity.entityData.set(PokemonEntity.RIDE_BOOSTS, rideBoosts)
|
||||
entity.entityData.set(PokemonEntity.RIDE_STAMINA, rideStamina)
|
||||
entity.entityData.set(PokemonEntity.SCALE_MODIFIER, scaleModifier)
|
||||
entity.isSilent = silent
|
||||
|
||||
entity.ejectPassengers()
|
||||
passengers.forEach {
|
||||
@@ -189,7 +179,6 @@ class SpawnPokemonPacket(
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): SpawnPokemonPacket {
|
||||
val ownerId = buffer.readNullable { buffer.readUUID() }
|
||||
val pokemonUUID = buffer.readUUID()
|
||||
val storageUUID = buffer.readNullable { buffer.readUUID() }
|
||||
val scaleModifier = buffer.readFloat()
|
||||
val speciesId = buffer.readIdentifier()
|
||||
val gender = buffer.readEnumConstant(Gender::class.java)
|
||||
@@ -217,13 +206,11 @@ class SpawnPokemonPacket(
|
||||
{ buffer.readFloat() }
|
||||
)
|
||||
val rideStamina = buffer.readFloat()
|
||||
val silent = buffer.readBoolean()
|
||||
val vanillaPacket = decodeVanillaPacket(buffer)
|
||||
|
||||
return SpawnPokemonPacket(
|
||||
ownerId,
|
||||
pokemonUUID,
|
||||
storageUUID,
|
||||
scaleModifier,
|
||||
speciesId,
|
||||
gender,
|
||||
@@ -248,7 +235,6 @@ class SpawnPokemonPacket(
|
||||
tickSpawned,
|
||||
rideBoosts,
|
||||
rideStamina,
|
||||
silent,
|
||||
vanillaPacket
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
|
||||
/**
|
||||
* Event to signal a transition in battle music. When received by the client, will either replace the currently playing
|
||||
* battle music with a new instance, or pause and temporarily switches from the current instance to play a [soundEvent].
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since December 16, 2925
|
||||
*/
|
||||
data class BattleMusicCue(
|
||||
/** The identifier of this cue. */
|
||||
val id: ResourceLocation,
|
||||
/** The track or sound effect to play. */
|
||||
val soundEvent: SoundEvent,
|
||||
/** Whether the [soundEvent] should replace and become the main track. */
|
||||
val replace: Boolean,
|
||||
/** Determines which cue's [soundEvent] plays if multiple cues are scheduled at once. Priority is lost when cue becomes
|
||||
* the main track. */
|
||||
val priority: Int,
|
||||
/** Time in seconds before the [soundEvent] starts playing. */
|
||||
val delay: Int,
|
||||
/** If the currently playing track should fade out, and the [soundEvent] should fade in. */
|
||||
val fade: Boolean = false
|
||||
)
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A configuration that dispatches a [BattleTrack] to use when playing battle music.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since January 6th, 2026
|
||||
*/
|
||||
class BattleThemeConfig(
|
||||
id: ResourceLocation,
|
||||
/** */
|
||||
override val tracks: Collection<BattleTrack>,
|
||||
/** 2nd-priority [BattleMusicCue]s that are subscribed by every track in the configuration. */
|
||||
val cues: Collection<BattleMusicCue>,
|
||||
) : SoundTrackConfig(id, tracks)
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
|
||||
object BattleThemes : JsonDataRegistry<BattleThemeConfig> {
|
||||
|
||||
override val resourcePath = "battle_themes"
|
||||
|
||||
|
||||
override val id: ResourceLocation = cobblemonResource(this.resourcePath)
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<BattleThemeConfig>()
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(BattleThemeConfig::class.java)
|
||||
|
||||
/** */
|
||||
private val battleSoundTrackConfigs = mutableMapOf<ResourceLocation, BattleThemeConfig>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, BattleThemeConfig>) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): BattleThemeConfig? = this.battleSoundTrackConfigs[identifier]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
class BattleTrack(
|
||||
val battle_conditions
|
||||
) : SoundTrack {
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* r
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since December 16, 2025
|
||||
*/
|
||||
open class SoundTrack {
|
||||
|
||||
val ambient: ResourceLocation
|
||||
val wildLocation: ResourceLocation
|
||||
val trainerLocation: ResourceLocation
|
||||
val priority: Int = 1
|
||||
val requirements: MutableSet<EntityQueryRequirement>
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.cobblemon.mod.common.ost
|
||||
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A configuration that dispatches a [SoundTrack] to use when playing music.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since January 6th, 2026
|
||||
*/
|
||||
open class SoundTrackConfig(
|
||||
/** The identifier of this configuration. */
|
||||
val id: ResourceLocation,
|
||||
/** The */
|
||||
open val tracks: Collection<SoundTrack>,
|
||||
) {
|
||||
|
||||
fun dispatchTrack(): BattleTrack {
|
||||
// TODO based on requirements
|
||||
}
|
||||
}
|
||||
|
||||
// should this be templated instead?
|
||||
@@ -673,7 +673,7 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
* Whether this Pokémon's held item can be dropped by its AI.
|
||||
*/
|
||||
internal var canDropHeldItem: Boolean = false
|
||||
get() = field || heldItem.isEmpty
|
||||
get() = field && !heldItem.isEmpty
|
||||
|
||||
val riding: RidingProperties
|
||||
get() = this.form.riding
|
||||
@@ -1437,11 +1437,6 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
|
||||
fun getOwnerEntity(): LivingEntity? {
|
||||
if (isClient) {
|
||||
val ownerUUID = entity?.ownerUUID ?: return null
|
||||
return entity?.level()?.getPlayerByUUID(ownerUUID)
|
||||
}
|
||||
|
||||
return storeCoordinates.get()?.let {
|
||||
if (isPlayerOwned()) {
|
||||
server()?.playerList?.getPlayer(it.store.uuid)
|
||||
|
||||
+7
-57
@@ -8,22 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.pokemon.adapters
|
||||
|
||||
import com.cobblemon.mod.common.api.interaction.InteractionEffect
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.adapters.RequirementAdapter
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.Requirement
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter
|
||||
import com.cobblemon.mod.common.pokemon.requirements.*
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import com.google.common.collect.HashBiMap
|
||||
import com.google.gson.*
|
||||
import net.minecraft.advancements.critereon.ItemPredicate
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import java.lang.reflect.Type
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -67,22 +58,6 @@ object CobblemonRequirementAdapter : RequirementAdapter {
|
||||
this.registerType(PropertyRangeRequirement.ADAPTER_VARIANT, PropertyRangeRequirement::class)
|
||||
this.registerType(AdvancementRequirement.ADAPTER_VARIANT, AdvancementRequirement::class)
|
||||
this.registerType(OwnerHoldsItemRequirement.ADAPTER_VARIANT, OwnerHoldsItemRequirement::class)
|
||||
this.registerType(DepthRequirement.ADAPTER_VARIANT, DepthRequirement::class)
|
||||
this.registerType(SkyRequirement.ADAPTER_VARIANT, SkyRequirement::class)
|
||||
}
|
||||
|
||||
val gson: Gson by lazy {
|
||||
GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter)
|
||||
.registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory())
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
}
|
||||
|
||||
override fun <T : Requirement> registerType(id: String, type: KClass<T>) {
|
||||
@@ -91,40 +66,15 @@ object CobblemonRequirementAdapter : RequirementAdapter {
|
||||
|
||||
override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Requirement {
|
||||
val variant = json.asJsonObject.get(VARIANT).asString.lowercase()
|
||||
val type = getRequirementType(variant)
|
||||
val type = this.types[variant] ?: throw IllegalArgumentException("Cannot resolve evolution requirement type for variant $variant")
|
||||
return context.deserialize(json, type.java)
|
||||
}
|
||||
|
||||
override fun serialize(requirement: Requirement, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
val json = context.serialize(requirement, requirement::class.java).asJsonObject
|
||||
val variant = getVariant(requirement)
|
||||
override fun serialize(src: Requirement, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
val json = context.serialize(src, src::class.java).asJsonObject
|
||||
val variant = this.types.inverse()[src::class] ?: throw IllegalArgumentException("Cannot resolve evolution requirement for type ${src::class.qualifiedName}")
|
||||
json.addProperty(VARIANT, variant)
|
||||
return json
|
||||
}
|
||||
|
||||
fun encode(requirement: Requirement, buffer: FriendlyByteBuf) {
|
||||
buffer.writeString(gson.toJson(requirement, Requirement::class.java))
|
||||
}
|
||||
|
||||
fun decode(buffer: FriendlyByteBuf): Requirement {
|
||||
return gson.fromJson(buffer.readString(), Requirement::class.java)
|
||||
}
|
||||
|
||||
private fun getVariant(requirement: Requirement): String {
|
||||
val variant = this.types.inverse()[requirement::class]
|
||||
if (variant == null) {
|
||||
throw IllegalArgumentException("Cannot resolve evolution requirement for type ${requirement::class.qualifiedName}")
|
||||
}
|
||||
|
||||
return variant
|
||||
}
|
||||
|
||||
private fun getRequirementType(variant: String): KClass<out Requirement> {
|
||||
val requirementType = this.types[variant]
|
||||
if (requirementType == null) {
|
||||
throw IllegalArgumentException("Cannot resolve evolution requirement type for variant $variant")
|
||||
}
|
||||
|
||||
return requirementType
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -11,9 +11,9 @@ package com.cobblemon.mod.common.pokemon.requirements
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import kotlin.collections.iterator
|
||||
|
||||
/**
|
||||
* An [com.cobblemon.mod.common.api.pokemon.requirement.Requirement] that checks if the player has a certain [net.minecraft.advancements.Advancement]
|
||||
@@ -26,16 +26,13 @@ class AdvancementRequirement(val requiredAdvancement: ResourceLocation) : OwnerQ
|
||||
|
||||
override fun checkPlayer(
|
||||
pokemon: Pokemon,
|
||||
owner: Player
|
||||
owner: ServerPlayer
|
||||
): Boolean {
|
||||
val serverPlayer = owner as? ServerPlayer ?: return false
|
||||
|
||||
for (entry in serverPlayer.advancements.progress) {
|
||||
for (entry in owner.advancements.progress) {
|
||||
if (entry.key.id == requiredAdvancement && entry.value.isDone) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -9,12 +9,13 @@
|
||||
package com.cobblemon.mod.common.pokemon.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* A [EntityQueryRequirement] for when a [LivingEntity] is expected to be in a certain area.
|
||||
* A [EntityQueryRequirement] for when a [Pokemon] is expected to be in a certain area.
|
||||
*
|
||||
* @property box The [AABB] expected to be in.
|
||||
* @author Licious
|
||||
@@ -26,5 +27,5 @@ class AreaRequirement : EntityQueryRequirement {
|
||||
}
|
||||
|
||||
val box: AABB = AABB.unitCubeFromLowerCorner(Vec3.ZERO)
|
||||
override fun check(queriedEntity: LivingEntity) = box.contains(queriedEntity.position())
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity) = box.contains(queriedEntity.position())
|
||||
}
|
||||
+2
-2
@@ -18,7 +18,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
|
||||
/**
|
||||
* A [Requirement] for when a [LivingEntity] is expected to be in a certain [Biome].
|
||||
* A [Requirement] for when a [Pokemon] is expected to be in a certain [Biome].
|
||||
*
|
||||
* @property biomeCondition The [ResourceLocation] of the [Biome] the queried entity is expected to be in.
|
||||
* @author Licious
|
||||
@@ -27,7 +27,7 @@ import net.minecraft.world.level.biome.Biome
|
||||
class BiomeRequirement : EntityQueryRequirement {
|
||||
val biomeCondition: RegistryLikeCondition<Biome>? = null
|
||||
val biomeAnticondition: RegistryLikeCondition<Biome>? = null
|
||||
override fun check(queriedEntity: LivingEntity): Boolean {
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
|
||||
val biome = queriedEntity.level().getBiome(queriedEntity.blockPosition()).value()
|
||||
val registry = queriedEntity.level().registryAccess().registryOrThrow(Registries.BIOME)
|
||||
return (biomeCondition == null || biomeCondition.fits(biome, registry)) && (biomeAnticondition == null || !biomeAnticondition.fits(biome, registry))
|
||||
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package com.cobblemon.mod.common.pokemon.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* An [EntityQueryRequirement] that evaluates whether a [LivingEntity] is at a certain block level.
|
||||
*
|
||||
* @property minY The minimum block level to satisfy this requirement. If null, defaults to the dimension's min height.
|
||||
* @property maxY The maximum block level to satisfy this requirement. If null, defaults to the dimension's max height.
|
||||
* @author Segfault Guy
|
||||
* @since December 16, 2025
|
||||
*/
|
||||
class DepthRequirement(val minY: Int?, val maxY: Int?) : EntityQueryRequirement {
|
||||
|
||||
override fun check(queriedEntity: LivingEntity): Boolean {
|
||||
val minLevelY = queriedEntity.level().minBuildHeight
|
||||
val maxLevelY = queriedEntity.level().maxBuildHeight
|
||||
val test = minY?.coerceIn(minLevelY, maxLevelY) ?: minLevelY
|
||||
val test2 = maxY?.coerceIn(minLevelY, maxLevelY) ?: maxLevelY
|
||||
|
||||
return queriedEntity.blockPosition().y in test..test2
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "depth"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -28,7 +28,7 @@ class MoonPhaseRequirement(moonPhase: MoonPhase) : EntityQueryRequirement {
|
||||
|
||||
val moonPhase: MoonPhase = moonPhase
|
||||
|
||||
override fun check(queriedEntity: LivingEntity): Boolean {
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
|
||||
return try {
|
||||
val moonPhase = MoonPhase.ofWorld(queriedEntity.level())
|
||||
this.moonPhase == moonPhase
|
||||
|
||||
+4
-2
@@ -12,9 +12,11 @@ import com.cobblemon.mod.common.api.pokemon.requirement.OwnerQueryRequirement
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.advancements.critereon.ItemPredicate
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import kotlin.collections.iterator
|
||||
|
||||
/**
|
||||
* An [OwnerQueryRequirement] that checks if the player/npc is holding a certain [ItemPredicate]
|
||||
@@ -28,7 +30,7 @@ class OwnerHoldsItemRequirement(val itemCondition: ItemPredicate)
|
||||
|
||||
override fun checkPlayer(
|
||||
pokemon: Pokemon,
|
||||
owner: Player
|
||||
owner: ServerPlayer
|
||||
): Boolean {
|
||||
return checkItem(owner)
|
||||
}
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package com.cobblemon.mod.common.pokemon.requirements
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.requirement.EntityQueryRequirement
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* An [EntityQueryRequirement] that evaluates whether a [LivingEntity] is exposed to a dimension's sky.
|
||||
*
|
||||
* @param invert If true, this requirement evaluates whether the entity CANNOT see a dimension's sky.
|
||||
* @author Segfault Guy
|
||||
* @since December 16, 2025
|
||||
*/
|
||||
class SkyRequirement(val invert: Boolean = false) : EntityQueryRequirement {
|
||||
|
||||
override fun check(queriedEntity: LivingEntity) = queriedEntity.level().canSeeSky(queriedEntity.blockPosition()).xor(invert)
|
||||
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "sky"
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -16,7 +16,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.level.levelgen.structure.Structure
|
||||
|
||||
/**
|
||||
* A [EntityQueryRequirement] for when a [LivingEntity] is expected to be in a certain structure.
|
||||
* A [EntityQueryRequirement] for when a [Pokemon] is expected to be in a certain structure.
|
||||
*
|
||||
* @property structureCondition The [Identifier] of the structure the queried entity is expected to be in.
|
||||
* @author whatsy
|
||||
@@ -25,7 +25,7 @@ import net.minecraft.world.level.levelgen.structure.Structure
|
||||
class StructureRequirement : EntityQueryRequirement {
|
||||
val structureCondition: RegistryLikeCondition<Structure>? = null
|
||||
val structureAnticondition: RegistryLikeCondition<Structure>? = null
|
||||
override fun check(queriedEntity: LivingEntity): Boolean {
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
|
||||
val structures = queriedEntity.level().getChunk(queriedEntity.blockPosition()).allReferences
|
||||
val registry = queriedEntity.level().registryAccess().registryOrThrow(Registries.STRUCTURE)
|
||||
return (structureCondition == null || structures.any { structureCondition.fits(it.key, registry) }) && (structureAnticondition == null || !structures.any { structureAnticondition.fits(it.key, registry) })
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import net.minecraft.world.entity.LivingEntity
|
||||
*/
|
||||
class TimeRangeRequirement : EntityQueryRequirement {
|
||||
val range = TimeRange(0..23999)
|
||||
override fun check(queriedEntity: LivingEntity) = this.range.contains((queriedEntity.level().dayTime() % DAY_DURATION).toInt())
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity) = this.range.contains((queriedEntity.level().dayTime() % DAY_DURATION).toInt())
|
||||
companion object {
|
||||
const val ADAPTER_VARIANT = "time_range"
|
||||
private const val DAY_DURATION = 24000
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ class WeatherRequirement : EntityQueryRequirement {
|
||||
val isRaining: Boolean? = null
|
||||
val isThundering: Boolean? = null
|
||||
|
||||
override fun check(queriedEntity: LivingEntity): Boolean {
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity): Boolean {
|
||||
val world = queriedEntity.level()
|
||||
return when {
|
||||
isRaining == true && !world.isRaining -> false
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.level.Level
|
||||
|
||||
/**
|
||||
* A [EntityQueryRequirement] for when a [LivingEntity] is expected to be in a [Level].
|
||||
* A [EntityQueryRequirement] for when a [Pokemon] is expected to be in a [Level].
|
||||
*
|
||||
* @property identifier The [ResourceLocation] of the [Level] the queried entity is expected to be in.
|
||||
* @author Licious
|
||||
@@ -26,5 +26,5 @@ class WorldRequirement : EntityQueryRequirement {
|
||||
const val ADAPTER_VARIANT = "world"
|
||||
}
|
||||
val identifier: ResourceLocation = ResourceLocation.parse("minecraft:the_overworld")
|
||||
override fun check(queriedEntity: LivingEntity) = queriedEntity.level().dimension().location() == this.identifier
|
||||
override fun check(pokemon: Pokemon, queriedEntity: LivingEntity) = queriedEntity.level().dimension().location() == this.identifier
|
||||
}
|
||||
+8
-12
@@ -8,22 +8,22 @@
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.google.gson.*
|
||||
import com.google.gson.JsonDeserializationContext
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.JsonOps
|
||||
import java.lang.reflect.Type
|
||||
|
||||
class CodecBackedAdapter<T>(val codec: Codec<T>) : JsonDeserializer<T>, JsonSerializer<T> {
|
||||
|
||||
override fun deserialize(
|
||||
jElement: JsonElement,
|
||||
typeOfT: Type,
|
||||
context: JsonDeserializationContext
|
||||
): T {
|
||||
val ops = RegistryOpsProvider.getOpsWithDefaultFallback()
|
||||
val result = ops.withDecoder(codec).apply(jElement)
|
||||
return result.result().orElseThrow {
|
||||
IllegalStateException("Failed to deserialize $jElement: ${result.error().orElse(null)}")
|
||||
}.first
|
||||
return JsonOps.INSTANCE.withDecoder(codec).apply(jElement).result().get().first as T
|
||||
}
|
||||
|
||||
override fun serialize(
|
||||
@@ -31,10 +31,6 @@ class CodecBackedAdapter<T>(val codec: Codec<T>) : JsonDeserializer<T>, JsonSeri
|
||||
typeOfSrc: Type?,
|
||||
context: JsonSerializationContext?
|
||||
): JsonElement {
|
||||
val ops = RegistryOpsProvider.getOpsWithDefaultFallback()
|
||||
val result = ops.withEncoder(codec).apply(src)
|
||||
return result.result().orElseThrow {
|
||||
IllegalStateException("Failed to serialize $src: ${result.error().orElse(null)}")
|
||||
}
|
||||
return JsonOps.INSTANCE.withEncoder(codec).apply(src).result().get()
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.util.adapters
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.JsonElement
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import com.mojang.serialization.JsonOps
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.resources.RegistryOps
|
||||
|
||||
/**
|
||||
* Utility for obtaining RegistryOps with the correct client/server registry access.
|
||||
* Used when manually encoding/decoding registry-backed values (e.g., items, predicates).
|
||||
*/
|
||||
object RegistryOpsProvider {
|
||||
fun getOpsWithDefaultFallback(): DynamicOps<JsonElement> {
|
||||
if (Cobblemon.implementation.environment() == Environment.CLIENT) {
|
||||
val minecraft = Minecraft.getInstance()
|
||||
if (minecraft != null && minecraft.level != null)
|
||||
return RegistryOps.create(JsonOps.INSTANCE, minecraft.level!!.registryAccess())
|
||||
}
|
||||
|
||||
|
||||
if (Cobblemon.implementation.environment() == Environment.SERVER) {
|
||||
val server = server()
|
||||
if (server != null)
|
||||
return RegistryOps.create(JsonOps.INSTANCE, server.registryAccess())
|
||||
}
|
||||
|
||||
return JsonOps.INSTANCE
|
||||
}
|
||||
}
|
||||
@@ -820,14 +820,6 @@
|
||||
"cobblemon.cooking.cooking_quality.medium": "Medium",
|
||||
"cobblemon.cooking.cooking_quality.high": "High",
|
||||
|
||||
"effect.cobblemon.cleanse_all": "Effect Cleanse",
|
||||
"effect.cobblemon.cleanse_negative": "Negative Effect Cleanse",
|
||||
"effect.cobblemon.mental_restoration": "Mental Restoration",
|
||||
|
||||
"effect.cobblemon.cleanse_all": "Effect Cleanse",
|
||||
"effect.cobblemon.cleanse_negative": "Negative Effect Cleanse",
|
||||
"effect.cobblemon.mental_restoration": "Mental Restoration",
|
||||
|
||||
"cobblemon.fossil.armor": "Armor",
|
||||
"cobblemon.fossil.bird": "Bird",
|
||||
"cobblemon.fossil.claw": "Claw",
|
||||
@@ -3523,7 +3515,6 @@
|
||||
"tag.item.cobblemon.plants": "Plants",
|
||||
"tag.item.cobblemon.seeds": "Seeds",
|
||||
"tag.item.cobblemon.boats": "Boats",
|
||||
"tag.item.cobblemon.chest_boats": "Chest Boats",
|
||||
"tag.item.cobblemon.hanging_signs": "Hanging Signs",
|
||||
"tag.item.cobblemon.signs": "Signs",
|
||||
"tag.item.cobblemon.dawn_stone_ores": "Dawn Stone Ores",
|
||||
@@ -9454,8 +9445,5 @@
|
||||
"stat.cobblemon.traded": "Pokémon Traded",
|
||||
"stat.cobblemon.times_ridden": "Pokémon Ridden",
|
||||
"stat.cobblemon.rod_casts": "PokéRod Casts",
|
||||
"stat.cobblemon.reel_ins": "PokéRod Catches",
|
||||
"stat.cobblemon.riding_land": "Distance by Pokémon on Land",
|
||||
"stat.cobblemon.riding_air": "Distance by Pokémon in Air",
|
||||
"stat.cobblemon.riding_liquid": "Distance by Pokémon in Liquid"
|
||||
"stat.cobblemon.reel_ins": "PokéRod Catches"
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"format_version": "1.21.6",
|
||||
"credit": "Made with Blockbench",
|
||||
"texture_size": [64, 24],
|
||||
"textures": {
|
||||
"0": "cobblemon:item/wearable/shell_helmet",
|
||||
"particle": "cobblemon:item/wearable/shell_helmet"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [4, 1, 7],
|
||||
"to": [12, 4, 10],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [4, 0, 6, 2], "texture": "#0"},
|
||||
"east": {"uv": [4, 2, 4.75, 4], "texture": "#0"},
|
||||
"south": {"uv": [1.75, 12.66667, 3.75, 14.66667], "texture": "#0"},
|
||||
"west": {"uv": [4.75, 2, 5.5, 4], "texture": "#0"},
|
||||
"up": {"uv": [4, 2, 2, 0], "texture": "#0"},
|
||||
"down": {"uv": [4, 2, 2, 4.66667], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 0, 7],
|
||||
"to": [12, 1, 7],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, -3, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [5.5, 3.33333, 5.75, 4], "texture": "#0"},
|
||||
"east": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"south": {"uv": [5.75, 3.33333, 6, 4], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"up": {"uv": [0.25, 0, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0.25, 0, 0, 0], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 7],
|
||||
"to": [5, 1, 7],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [0, -3, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [4, 4, 4.25, 4.66667], "texture": "#0"},
|
||||
"east": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"south": {"uv": [3.75, 12.66667, 4, 13.33333], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"up": {"uv": [0.25, 0, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0.25, 0, 0, 0], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [12, -1, 7],
|
||||
"to": [12, 1, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 11]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"east": {"uv": [4.25, 6.66667, 4.75, 8], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"west": {"uv": [5.5, 2, 6, 3.33333], "texture": "#0"},
|
||||
"up": {"uv": [0, 3.33333, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 3.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, -1, 7],
|
||||
"to": [4, 1, 9],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 11]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"east": {"uv": [4, 10, 4.5, 11.33333], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"west": {"uv": [4.75, 6.66667, 5.25, 8], "texture": "#0"},
|
||||
"up": {"uv": [0, 3.33333, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 3.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 2, 4],
|
||||
"to": [11, 4, 7],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [4.25, 4, 5.75, 5.33333], "texture": "#0"},
|
||||
"east": {"uv": [6, 2.66667, 6.75, 4], "texture": "#0"},
|
||||
"south": {"uv": [4.25, 5.33333, 5.75, 6.66667], "texture": "#0"},
|
||||
"west": {"uv": [5.75, 4, 6.5, 5.33333], "texture": "#0"},
|
||||
"up": {"uv": [5.5, 13.33333, 4, 11.33333], "texture": "#0"},
|
||||
"down": {"uv": [5.25, 13.33333, 3.75, 15.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 2, 7],
|
||||
"to": [11, 2, 10],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [4.25, 4, 5.75, 5.33333], "texture": "#0"},
|
||||
"east": {"uv": [6, 2.66667, 6.75, 4], "texture": "#0"},
|
||||
"south": {"uv": [4.25, 5.33333, 5.75, 6.66667], "texture": "#0"},
|
||||
"west": {"uv": [5.75, 4, 6.5, 5.33333], "texture": "#0"},
|
||||
"up": {"uv": [5.5, 13.33333, 4, 11.33333], "texture": "#0"},
|
||||
"down": {"uv": [3.75, 15.33333, 5.25, 13.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11, 0, 4],
|
||||
"to": [11, 2, 7],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"east": {"uv": [5.75, 5.33333, 6.5, 6.66667], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"west": {"uv": [6, 1.33333, 6.75, 2.66667], "texture": "#0"},
|
||||
"up": {"uv": [0, 2, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 2], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [5, 0, 4],
|
||||
"to": [5, 2, 7],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"east": {"uv": [6, 0, 6.75, 1.33333], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 1.33333], "texture": "#0"},
|
||||
"west": {"uv": [5.25, 6.66667, 6, 8], "texture": "#0"},
|
||||
"up": {"uv": [0, 2, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 2], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 1, 10],
|
||||
"to": [12, 4, 15],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 0, 12]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 10.66667, 1.75, 14], "texture": "#0"},
|
||||
"east": {"uv": [3.25, 8, 4.5, 10], "texture": "#0"},
|
||||
"south": {"uv": [1.75, 10.66667, 4, 12.66667], "texture": "#0"},
|
||||
"west": {"uv": [2, 8, 3.25, 10], "texture": "#0"},
|
||||
"up": {"uv": [6.5, 11.33333, 4.5, 8], "texture": "#0"},
|
||||
"down": {"uv": [4.25, 4.66667, 2, 8], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, -4, 9],
|
||||
"to": [12, 1, 15],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [4, -3, 13]},
|
||||
"faces": {
|
||||
"north": {"uv": [10.75, 3.33333, 12.75, 6.66667], "texture": "#0"},
|
||||
"east": {"uv": [12.75, 0, 14.25, 3.33333], "texture": "#0"},
|
||||
"south": {"uv": [10.75, 0, 12.75, 3.33333], "texture": "#0"},
|
||||
"west": {"uv": [14.25, 0, 15.75, 3.33333], "texture": "#0"},
|
||||
"up": {"uv": [8.75, 4, 10.75, 8], "texture": "#0"},
|
||||
"down": {"uv": [8.75, 0, 10.75, 4], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [6, -1.3, 10.5],
|
||||
"to": [10, 6.7, 18.5],
|
||||
"rotation": {"angle": 45, "axis": "x", "origin": [7.5, 1.65, 13.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.75, 3.33333, 13.75, 8.66667], "texture": "#0"},
|
||||
"east": {"uv": [2, 0, 0, 5.33333], "texture": "#0"},
|
||||
"south": {"uv": [13.75, 3.33333, 14.75, 8.66667], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 2, 5.33333], "texture": "#0"},
|
||||
"up": {"uv": [12.75, 8.66667, 13.75, 14], "texture": "#0"},
|
||||
"down": {"uv": [13.75, 8.66667, 14.75, 14], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, -1.4, 7.4],
|
||||
"to": [12, -1.4, 18.4],
|
||||
"rotation": {"angle": 45, "axis": "x", "origin": [7.5, 1.65, 13.5]},
|
||||
"faces": {
|
||||
"north": {"uv": [12.75, 3.33333, 13.75, 8.66667], "texture": "#0"},
|
||||
"east": {"uv": [0, 5.33333, 2, 10.66667], "texture": "#0"},
|
||||
"south": {"uv": [13.75, 3.33333, 14.75, 8.66667], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 2, 5.33333], "texture": "#0"},
|
||||
"up": {"uv": [12.75, 8.66667, 13.75, 14], "texture": "#0"},
|
||||
"down": {"uv": [6.75, 0, 8.75, 6.66667], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4.01, -4, 7],
|
||||
"to": [4.01, 4, 15],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"east": {"uv": [8.75, 8, 10.75, 13.33333], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"west": {"uv": [6.5, 6.66667, 8.5, 12], "texture": "#0"},
|
||||
"up": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 5.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [11.99, -4, 7],
|
||||
"to": [11.99, 4, 15],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"east": {"uv": [6.5, 6.66667, 8.5, 12], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"west": {"uv": [10.75, 9.33333, 12.75, 14.66667], "texture": "#0"},
|
||||
"up": {"uv": [0, 0, 0, 5.33333], "texture": "#0"},
|
||||
"down": {"uv": [0, 0, 0, 5.33333], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, 0, 7.01],
|
||||
"to": [12, 4, 7.01],
|
||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, -3, 9]},
|
||||
"faces": {
|
||||
"north": {"uv": [10.75, 3.33333, 12.75, 6.66667], "texture": "#0"},
|
||||
"east": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"south": {"uv": [10.75, 6.66667, 12.75, 9.33333], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 0, 0.66667], "texture": "#0"},
|
||||
"up": {"uv": [0.25, 0, 0, 0], "texture": "#0"},
|
||||
"down": {"uv": [0.25, 0, 0, 0], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [4, -3.99, 12],
|
||||
"to": [12, -3.99, 15],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 2, 0], "texture": "#0"},
|
||||
"east": {"uv": [0, 0, 0.75, 0], "texture": "#0"},
|
||||
"south": {"uv": [0, 0, 2, 0], "texture": "#0"},
|
||||
"west": {"uv": [0, 0, 0.75, 0], "texture": "#0"},
|
||||
"up": {"uv": [10.75, 8.66667, 12.75, 6.66667], "texture": "#0"},
|
||||
"down": {"uv": [10.75, 4.66667, 12.75, 6.66667], "texture": "#0"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"head": {
|
||||
"translation": [0, 15.25, -6],
|
||||
"scale": [1.9, 1.9, 1.9]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1517,139 +1517,76 @@
|
||||
{ "name": "cobblemon:animation/wings/steel_wing_flap_medium_8", "volume": 0.25 }
|
||||
]
|
||||
},
|
||||
"ride.loop.wind.mono": {
|
||||
"ride.loop.wind": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/wind_loop_mono",
|
||||
"name": "cobblemon:ride/loop/wind_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 48.0,
|
||||
"volume": 0.15
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.wind.stereo": {
|
||||
"ride.loop.leather": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/wind_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.04
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.leather.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/leather_flight_loop_mono",
|
||||
"name": "cobblemon:ride/loop/leather_flight_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 48.0,
|
||||
"volume": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.leather.stereo": {
|
||||
"ride.loop.plumage": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/leather_flight_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.05
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.plumage.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/plumage_flight_loop_mono",
|
||||
"name": "cobblemon:ride/loop/plumage_flight_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 48.0,
|
||||
"volume": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.plumage.stereo": {
|
||||
"ride.loop.saucer": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/plumage_flight_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.05
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.saucer.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/saucer_flight_loop_mono",
|
||||
"name": "cobblemon:ride/loop/saucer_flight_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 48.0,
|
||||
"volume": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.saucer.stereo": {
|
||||
"ride.loop.rocket": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/saucer_flight_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.rocket.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/rocket_flight_loop_mono",
|
||||
"name": "cobblemon:ride/loop/rocket_flight_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 48.0,
|
||||
"volume": 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.rocket.stereo": {
|
||||
"ride.loop.water_surface": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/rocket_flight_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.3
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.water_surface.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/water_surface_loop_mono",
|
||||
"name": "cobblemon:ride/loop/water_surface_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 32.0,
|
||||
"volume": 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.water_surface.stereo": {
|
||||
"ride.loop.underwater": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/water_surface_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.13
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.underwater.mono": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/underwater_loop_mono",
|
||||
"name": "cobblemon:ride/loop/underwater_loop",
|
||||
"stream": true,
|
||||
"attenuation_distance": 16.0,
|
||||
"volume": 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
"ride.loop.underwater.stereo": {
|
||||
"sounds": [
|
||||
{
|
||||
"name": "cobblemon:ride/loop/underwater_loop_stereo",
|
||||
"stream": true,
|
||||
"volume": 0.2
|
||||
}
|
||||
]
|
||||
},
|
||||
"pokemon.bulbasaur.ambient": {
|
||||
"sounds": [ "cobblemon:pokemon/bulbasaur/bulbasaur_ambient" ]
|
||||
},
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 863 B |
Binary file not shown.
|
Before Width: | Height: | Size: 599 B |
Binary file not shown.
|
Before Width: | Height: | Size: 606 B |
Binary file not shown.
|
Before Width: | Height: | Size: 566 B |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 582 B |
Loaded 100 of 147 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user