Compare commits

..
Author SHA1 Message Date
Segfault Guy 9309c53a40 Added CanDynamaxInstruction for multi battles. 2024-08-20 23:12:48 -04:00
1951 changed files with 2056 additions and 59838 deletions
+1 -2
View File
@@ -39,5 +39,4 @@ common/src/main/resources/assets/cobblemon/showdown
common/.fabric
# MacOS
.DS_Store
.kotlin/sessions/kotlin-compiler-16609242564043830292.salive
.DS_Store
-3
View File
@@ -1,3 +0,0 @@
### Additions
- Added the Poké Dex as a craftable item.
- Poké Dexes can be placed on lecterns.
+17 -71
View File
@@ -60,16 +60,24 @@
- Hidden Power now displays its effective typing.
- Moves impacted by the abilities Pixelate, Refrigerate, Aerilate, Galvanize, and Normalize now display as their altered typing.
- Added Polished Tumblestone and Tumblestone Brick block sets from Tumblestone, Black Tumblestone, and Sky Tumblestone.
- Added Fire, Water, Thunder, Leaf, Ice, Sun, Moon, Shiny, Dawn, and Dusk Stone Storage Blocks.
- Added Metronome, Protective Pads, Punching Glove, Room Service, Scope Lens, Shed Shell, Terrain Extender, Throat Spray, Utility Umbrella, Wide Lens, and Zoom Lens held items
- Moves can now be benched without specifying a replacement move, allowing for empty move slots.
- Moves learned via Sketch now persist after battle.
- Added ston_henge_ruins, luna_henge_ruins, and sol_henge_ruins structures.
- Added Eject Pack, Metronome, Protective Pads, Punching Glove, Room Service, Scope Lens, Shed Shell, Terrain Extender, Throat Spray, Utility Umbrella, Wide Lens, and Zoom Lens held items
- Added a `battleInvulnerability` gamerule to make players invulnerable to any damage during a battle
- Added a `mobTargetInBattle` gamerule to exclude players from being targeted by mobs during a battle
- Added battle log messages for switching out Pokémon
- Added Evolution particles and sounds for Pokemon that are sent out when evolution is started.
### Added cries to the following Pokémon
- Timburr, Gurdurr, Conkeldurr
- Golett, Golurk
### Changes
- Altered the item model for Medicinal Leeks and Roasted Leeks to be held like sticks and other rod items.
- Adjusted some berry balance values like yield and growth times
- Changes to mulch buffs/durations
- Dreepy is now shoulder mountable
- Link Cable recipe has been redesigned
- Updated potion sprites
- Weedle, Caterpie, Spearow, Smoochum, Mew, Murkrow, Larvitar, Taillow, Plusle, Minun, Beldum, Starly, Buneary, Combee, Pachirisu, Pidove, Petilil, Hisui Bias Petilil, Zorua, Hisuian Zorua, Elgyem, Fletchling, Skrelp, Klefki, Fomantis, Morelull, Dreepy, Shroodle, Tatsugiri, Glimmet, and Roaming Gimmighoul are now shoulder mountable
- Chikorita's ability to look around removed due to the awkwardness of it.
- Link Cable recipe has been redesigned
- Updated potion sprites
- Removed the interchangeable evolution results for the first stage Hisuian starters to prevent confusion. The method still exists for stage 2 to 3, but stage 1 to 2 was not distinguishable enough for many users.
### Pokémon Added
#### Gen 2
@@ -86,72 +94,10 @@
#### Gen 9
- Farigiraf
### Added cries to the following Pokémon
- Timburr, Gurdurr, Conkeldurr
- Golett, Golurk
### Changes
- Altered the item model for Medicinal Leeks and Roasted Leeks to be held like sticks and other rod items.
- Adjusted some berry balance values like yield and growth times
- Adjusted volumes of sounds made by Display Cases, Berry Bushes, Energy Root, Medicinal Leek, Vivichoke, Mints, Revival Herbs and Gilded Chests.
- Changes to mulch buffs/durations
- Dreepy is now shoulder mountable
- Link Cable recipe has been redesigned
- Updated potion sprites
- Weedle, Caterpie, Spearow, Smoochum, Mew, Murkrow, Larvitar, Taillow, Plusle, Minun, Beldum, Starly, Buneary, Combee, Pachirisu, Pidove, Petilil, Hisui Bias Petilil, Zorua, Hisuian Zorua, Elgyem, Fletchling, Skrelp, Klefki, Fomantis, Morelull, Dreepy, Shroodle, Tatsugiri, Glimmet, and Roaming Gimmighoul are now shoulder mountable
- Chikorita's ability to look around removed due to the awkwardness of it.
- Link Cable recipe has been redesigned
- Updated potion sprites
- Updated sounds for Medicinal Leeks, Big Roots, Energy Roots and Revival Herbs
- Updated UI sounds for clicking and evolving Pokémon
- Removed the interchangeable evolution results for the first stage Hisuian starters to prevent confusion. The method still exists for stage 2 to 3, but stage 1 to 2 was not distinguishable enough for many users.
- Kakuna, Beedrill, Snorlax, Munchlax, and Lurantis received model updates
### Fixes
- Fixed trading Pokémon setting their friendsip to 0 instead of the base value.
- Fixed a scenario where a Pokémon that rolled to spawn with a special Tera type sometimes has a Tera type that is already a part of their natural typing.
- Fixed PokemonProperty argument suggestions for ``tera`` and ``tera_type`` not suggesting ``stellar``.
- Fixed being able to stack Relic Coin Pouches on top of each other.
- Fixed Model loader generating misleading crash-reports when client is crashing
- Scaled down Amaura's fetus model to avoid clipping through the tank while animating
- Big Roots and Energy Roots now share the same sounds as intented.
- Fixed Cubone's cry not having a sound.
- Fixed sounds made by blocks playing at a lower pitch than intended.
- Fixed the Seafloor spawning context not being a usable context.
- Fixed Pokemon spawning in non-full blocks like slabs.
- Fixed Gilded Chests not dropping the chest itself when broken, only the contents.
- Fixed Pokémon losing their Hidden Ability through evolution if the middle stage did not have a Hidden Ability.
- Hidden Power no longer plays the water type action effect. (It now plays the normal type action effect.)
- Fixed Chimchar and Monferno T posing whenever they sleep.
- Fixed the Magby line not having any placeholder walk animations.
- Fixed Duskull and Dusclops using skylight levels for their nether spawn data. There is no sun in the Nether!
- Fixed Hisuian Zoroark using base Zoroark stats.
- Fixed Bellossom clipping into the player head when shoulder mounted.
- Fixed Shroomish's look range to prevent it from looking higher than it should.
- Fixed Crumbling Arch not blending in with the world.
- Fixed Energy Root applying being usable on a fainted Pokemon.
- Fixed Pokémon entity not spawning when starting a battle while recalling said Pokémon
- Fixed species comparison not using namespace for both sides in PokemonProperties.isSubsetOf.
- Fixed PokemonProperties#asString prefixing nicknames with a '$'
- Fixed reviving items throwing an exception when used in battle
- Fixed messages for Focus Sash, Confusion, Mummy, Ice Face, Own Tempo, and Revive
- Fixed PC not saving when Pokemon was changed outside.
- Fixed shearble Pokemon not dropping correct wool colors.
- Fixed pasture spawning Pokemon inside solid blocks when closest spawning position is blocked off.
- Fixed Tumbling Down advancement not being granted by tumblestone variants.
- Improve error handling when loading spawn-sets to ensure invalid configurations don't crash the server
- Fixed empty JsonPlayerData files resulting in players being unable to join server/world
- Fixed crumbling_arch_ruins from generating a giant cube of air and removed the chest
- Fixed possible crash on large population servers due to concurrent access of data.
### Developer
- SpawnCause is now an implementation of SpawningInfluence.
- Added "forcedAspects" to Pokemon to make it easier to easily add basic aspects to a Pokémon in a way that persists. We already know that everyone is going to overuse this.
- Made the Pokemon.aspects setter private. This could technically break sidemods but if you are affected by this then you were using it wrong! Use Pokemon.forcedAspects to fix it.
- Many types related to ``Pokemon`` including itself now have dedicated ``Codec``, please migrate to them from the NBT/JSON/PacketBuffer write/read methods.
- ``TeraTypes`` now implements ``Iterable``.
- PokemonBattle now starts on turn 0.
- All sounds related to evolving Pokémon have been moved to the "sounds/evolution" folder.
### Data Pack & Resource Pack Creators
- Added support for "shedders" similar to Shedinja's evolution logic.
+1 -1
View File
@@ -40,7 +40,7 @@ dependencies {
modApi(libs.molang)
// Integrations
compileOnlyApi(libs.jei.api)
// compileOnlyApi(libs.jei.api)
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
isTransitive = false
}
@@ -1,54 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import com.cobblemon.mod.common.item.PokedexItem;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.ItemModelShaper;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/*
I think it would be nice to maybe use the existing mixin we have for custom item rendering [BuiltinModelItemRendererMixin]
Obviously that would require changes. Potentially each item renderer defines what modes it overrides for?
*/
@Mixin(ItemRenderer.class)
public abstract class ItemRendererMixin {
@Shadow @Final private ItemModelShaper itemModelShaper;
@Shadow public abstract void render(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource vertexConsumers, int light, int overlay, BakedModel model);
@Inject(
method = "Lnet/minecraft/client/renderer/entity/ItemRenderer;render(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemDisplayContext;ZLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IILnet/minecraft/client/resources/model/BakedModel;)V",
at = @At("HEAD"),
cancellable = true
)
private void cobblemon$overridePokedexModel(ItemStack stack, ItemDisplayContext renderMode, boolean leftHanded, PoseStack matrices, MultiBufferSource multiBufferSource, int i, int j, BakedModel model, CallbackInfo ci) {
boolean shouldOverride = renderMode != ItemDisplayContext.GUI && renderMode != ItemDisplayContext.FIXED;
if (shouldOverride && stack.getItem() instanceof PokedexItem) {
BakedModel replacementModel = CobblemonBakingOverrides.INSTANCE.getPokedexOverride(((PokedexItem) stack.getItem()).getType()).getModel();
if (!model.equals(replacementModel)) {
ci.cancel();
render(stack, renderMode, leftHanded, matrices, multiBufferSource, i, j, replacementModel);
}
}
}
}
@@ -9,6 +9,7 @@
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonBakingOverrides;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import net.minecraft.client.color.block.BlockColors;
@@ -19,6 +20,8 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.UnbakedModel;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.profiling.ProfilerFiller;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -28,10 +31,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ModelBakery.class)
public abstract class ModelLoaderMixin {
@Shadow abstract UnbakedModel getModel(ResourceLocation resourceLocation);
@Shadow protected abstract void registerModel(ModelResourceLocation modelId, UnbakedModel unbakedModel);
@Final
@Shadow
private Map<ResourceLocation, UnbakedModel> unbakedCache;
@Final
@Shadow
private static Logger LOGGER;
@Inject(
method = "<init>",
at = @At("TAIL")
@@ -42,8 +51,19 @@ public abstract class ModelLoaderMixin {
Map<ResourceLocation, List<BlockStateModelLoader.LoadedJson>> blockStates,
CallbackInfo ci) {
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
var unbakedModel = this.getModel(bakingOverride.getModelLocation());
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
try {
BlockModel unbakedModel = this.loadBlockModel(bakingOverride.getModelLocation());
this.unbakedCache.put(bakingOverride.getModelIdentifier().id(), unbakedModel);
this.registerModel(bakingOverride.getModelIdentifier(), unbakedModel);
} catch (IOException e) {
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
throw new RuntimeException(e);
}
});
}
@Shadow
private BlockModel loadBlockModel(ResourceLocation id) throws IOException {
return null;
}
}
@@ -10,13 +10,8 @@ package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
import com.cobblemon.mod.common.item.PokedexItem;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
import net.minecraft.client.Minecraft;
import net.minecraft.client.MouseHandler;
import net.minecraft.util.Mth;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -28,8 +23,6 @@ public class PartyScrollMixin {
@Shadow
private double accumulatedScrollY;
@Shadow @Final private Minecraft minecraft;
@Inject(
method = "onScroll",
at = @At(
@@ -41,7 +34,7 @@ public class PartyScrollMixin {
),
cancellable = true
)
public void cobblemon$scrollParty(long window, double horizontal, double vertical, CallbackInfo ci) {
public void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) {
if (PartySendBinding.INSTANCE.getWasDown()) {
int i = (int)accumulatedScrollY;
if (i > 0) {
@@ -57,21 +50,4 @@ public class PartyScrollMixin {
}
}
}
@Inject(
method = "onScroll",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/player/Inventory;swapPaint(D)V"
),
cancellable = true
)
public void cobblemon$doPokedexZoom(long window, double horizontal, double vertical, CallbackInfo ci) {
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
usageContext.adjustZoom(vertical);
ci.cancel();
}
}
}
@@ -18,18 +18,7 @@ import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
import com.cobblemon.mod.common.pokemon.Pokemon;
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
import com.cobblemon.mod.common.util.DataKeys;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -40,6 +29,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
import java.util.UUID;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@Mixin(Player.class)
public abstract class PlayerMixin extends LivingEntity {
@@ -65,7 +63,7 @@ public abstract class PlayerMixin extends LivingEntity {
super(p_20966_, p_20967_);
}
@Inject(method = "respawnEntityOnShoulder", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/Level;)Ljava/util/Optional;"), cancellable = true)
@Inject(method = "respawnEntityOnShoulder", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;create(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/Level;)Ljava/util/Optional;"), cancellable = true)
private void cobblemon$removePokemon(CompoundTag nbt, CallbackInfo ci) {
if (CompoundTagExtensionsKt.isPokemonEntity(nbt)) {
final UUID uuid = this.getPokemonID(nbt);
@@ -161,16 +159,4 @@ public abstract class PlayerMixin extends LivingEntity {
}
}
}
@Inject(method = "isInvulnerableTo", at = @At("HEAD"), cancellable = true)
public void isInvulnerableTo(DamageSource source, CallbackInfoReturnable<Boolean> ci) {
if (!level().isClientSide) {
ServerPlayer player = (ServerPlayer)(Object)this;
boolean invulnerableInBattle = this.level().getGameRules().getBoolean(CobblemonGameRules.BATTLE_INVULNERABILITY);
boolean inBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (invulnerableInBattle && inBattle) {
ci.setReturnValue(true);
}
}
}
}
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin;
import com.cobblemon.mod.common.Cobblemon;
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(TargetingConditions.class)
public class TargetingConditionsMixin {
@Inject(method = "test", at = @At("HEAD"), cancellable = true)
public void test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity, CallbackInfoReturnable<Boolean> ci) {
if (targetEntity instanceof ServerPlayer player) {
boolean canTargetInBattle = player.level().getGameRules().getBoolean(CobblemonGameRules.MOB_TARGET_IN_BATTLE);
boolean targetInBattle = Cobblemon.INSTANCE.getBattleRegistry().getBattleByParticipatingPlayer(player) != null;
if (!canTargetInBattle && targetInBattle) ci.setReturnValue(false);
}
}
}
@@ -1,19 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.accessor;
import net.minecraft.client.gui.components.AbstractSelectionList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(AbstractSelectionList.class)
public interface EntryListWidgetAccessor {
@Accessor("renderHeader")
boolean getRenderHeader();
}
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.CobblemonClient;
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
import net.minecraft.client.player.AbstractClientPlayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AbstractClientPlayer.class)
public class AbstractClientPlayerMixin {
@Inject(
method = "getFieldOfViewModifier()F",
at = @At(
value = "HEAD"
),
cancellable = true
)
public void cobblemon$getPokedexFovMultiplier(CallbackInfoReturnable<Float> cir) {
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
if (usageContext.getScanningGuiOpen()) {
cir.setReturnValue(usageContext.getFovMultiplier());
}
}
}
@@ -1,30 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.gui.ScrollingWidget;
import net.minecraft.client.gui.components.AbstractSelectionList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(AbstractSelectionList.class)
public abstract class EntryListWidgetMixin {
@SuppressWarnings("ConstantValue")
@ModifyConstant(method = "getEntryAtPosition", constant = @Constant(intValue = 4))
public int cobblemon$adjustOnlyIfNecessary(int input) {
if(ScrollingWidget.class.isInstance(this)) {
return 0;
}
return input;
}
}
@@ -1,39 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.mixin.client;
import com.cobblemon.mod.common.client.CobblemonClient;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiGraphics;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* Mixin to give us a hook to render the PartyOverlay below the Chat
*
* @author Qu
* @since 2022-02-22
*/
@Mixin(Gui.class)
public class GuiMixin {
//This injects into the actual BooleanSupplier lambda for the "this.layers.add(layeredDraw, () -> !minecraft.options.hideGui)" call
// sus af. You have to get the method name by looking at the bytecode of the class. Can do in intellij By clicking View -> Show Bytecode (top left)
@Inject(method = "method_55797", at = @At("HEAD"), cancellable = true)
private static void cobblemon$dontRenderUiInPokedex(Minecraft minecraft, CallbackInfoReturnable<Boolean> cir) {
if (CobblemonClient.INSTANCE.getPokedexUsageContext().getScanningGuiOpen()) {
cir.setReturnValue(false);
}
}
}
@@ -34,7 +34,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ItemRenderer.class)
public abstract class ItemRendererMixin {
@Unique private final String MODEL_PATH = Cobblemon.implementation.getModAPI() == ModAPI.FABRIC ? "fabric_resource" : "standalone";
@Unique private static final String MODEL_PATH = Cobblemon.implementation.getModAPI() == ModAPI.FABRIC ? "fabric_resource" : "standalone";
@Shadow @Final private ItemModelShaper itemModelShaper;
@@ -9,9 +9,6 @@
package com.cobblemon.mod.common
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
//import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
import com.cobblemon.mod.common.advancement.CobblemonCriteria
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.SeasonResolver
import com.cobblemon.mod.common.api.data.DataProvider
@@ -19,14 +16,11 @@ import com.cobblemon.mod.common.api.drop.CommandDropEntry
import com.cobblemon.mod.common.api.drop.DropEntry
import com.cobblemon.mod.common.api.drop.ItemDropEntry
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_STARTED_POST
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_SCANNED
import com.cobblemon.mod.common.api.events.CobblemonEvents.STARTER_CHOSEN
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
import com.cobblemon.mod.common.api.permission.PermissionValidator
import com.cobblemon.mod.common.api.pokeball.catching.calculators.CaptureCalculator
@@ -62,11 +56,9 @@ import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactor
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
import com.cobblemon.mod.common.api.storage.pc.PCStore
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreManager
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreType
import com.cobblemon.mod.common.api.storage.player.adapter.DexDataNbtBackend
import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataJsonBackend
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.battles.BagItems
@@ -77,12 +69,10 @@ import com.cobblemon.mod.common.battles.ShowdownThread
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
import com.cobblemon.mod.common.client.CobblemonClient
import com.cobblemon.mod.common.command.argument.DexArgumentType
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
import com.cobblemon.mod.common.command.argument.FormArgumentType
import com.cobblemon.mod.common.command.argument.MoveArgumentType
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
import com.cobblemon.mod.common.command.argument.SpeciesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
import com.cobblemon.mod.common.command.argument.PokemonPropertiesArgumentType
import com.cobblemon.mod.common.command.argument.PokemonStoreArgumentType
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
@@ -92,7 +82,6 @@ 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.AdvancementHandler
import com.cobblemon.mod.common.events.PokedexHandler
import com.cobblemon.mod.common.events.ServerTickHandler
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
import com.cobblemon.mod.common.permission.LaxPermissionValidator
@@ -115,6 +104,8 @@ import com.cobblemon.mod.common.util.*
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
import com.mongodb.ConnectionString
import com.mongodb.MongoClientSettings
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import java.io.File
@@ -161,7 +152,7 @@ object Cobblemon {
val battleRegistry = BattleRegistry
var storage = PokemonStoreManager()
var molangData = NbtMoLangDataStoreFactory
lateinit var playerDataManager: PlayerInstancedDataStoreManager
lateinit var playerData: PlayerDataStoreManager
lateinit var starterConfig: StarterConfig
val dataProvider: DataProvider = CobblemonDataProvider
var permissionValidator: PermissionValidator by Delegates.observable(LaxPermissionValidator().also { it.initialize() }) { _, _, newValue -> newValue.initialize() }
@@ -209,7 +200,7 @@ object Cobblemon {
DATA_SYNCHRONIZED.subscribe {
storage.onPlayerDataSync(it)
playerDataManager.syncAllToPlayer(it)
playerData.get(it).sendToPlayer(it)
starterHandler.handleJoin(it)
ServerSettingsPacket(this.config.preventCompletePartyDeposit, this.config.displayEntityLevelLabel).sendToPlayer(it)
}
@@ -217,7 +208,7 @@ object Cobblemon {
PCLinkManager.removeLink(it.player.uuid)
BattleRegistry.onPlayerDisconnect(it.player)
storage.onPlayerDisconnect(it.player)
playerDataManager.onPlayerDisconnect(it.player)
playerData.onPlayerDisconnect(it.player)
TradeManager.onLogoff(it.player)
}
PlatformEvents.PLAYER_DEATH.subscribe {
@@ -242,6 +233,9 @@ object Cobblemon {
}
}
// Register the grow_tumblestone advancement
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
PlatformEvents.CHANGE_DIMENSION.subscribe {
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
}
@@ -257,8 +251,6 @@ object Cobblemon {
}
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
}
fun initialize() {
@@ -300,21 +292,16 @@ object Cobblemon {
}
PlatformEvents.SERVER_STARTING.subscribe { event ->
val server = event.server
playerDataManager = PlayerInstancedDataStoreManager().also { it.setup(server) }
playerData = PlayerDataStoreManager().also { it.setup(server) }
val mongoClient: MongoClient?
val pokemonStoreRoot = server.getWorldPath(LevelResource.ROOT).resolve("pokemon").toFile()
val storeAdapter = when (config.storageFormat) {
"nbt", "json" -> {
val generalJsonFactory = CachedPlayerDataStoreFactory(PlayerDataJsonBackend())
generalJsonFactory.setup(server)
val pokedexNbtFactory = CachedPlayerDataStoreFactory(DexDataNbtBackend())
pokedexNbtFactory.setup(server)
playerDataManager.setFactory(generalJsonFactory, PlayerInstancedDataStoreType.GENERAL)
playerDataManager.setFactory(pokedexNbtFactory, PlayerInstancedDataStoreType.POKEDEX)
val jsonFactory = JsonPlayerDataStoreFactory()
jsonFactory.setup(server)
playerData.setFactory(jsonFactory)
if (config.storageFormat == "nbt") {
NBTStoreAdapter(pokemonStoreRoot.absolutePath, useNestedFolders = true, folderPerClass = true)
@@ -327,9 +314,7 @@ object Cobblemon {
}
}
/*
"mongodb" -> {
/*
try {
Class.forName("com.mongodb.client.MongoClient")
@@ -338,18 +323,14 @@ object Cobblemon {
.build()
mongoClient = MongoClients.create(mongoClientSettings)
val mongoFactory = MongoPlayerDataStoreFactory(mongoClient, config.mongoDBDatabaseName)
playerData.setFactory(mongoFactory, PlayerInstancedDataStoreType.GENERAL)
playerData.setFactory(mongoFactory)
MongoDBStoreAdapter(mongoClient, config.mongoDBDatabaseName)
} catch (e: ClassNotFoundException) {
LOGGER.error("MongoDB driver not found.")
throw e
}
*/
}
*/
else -> throw IllegalArgumentException("Unsupported storageFormat: ${config.storageFormat}")
}
.with(ReforgedConversion(server.getWorldPath(LevelResource.ROOT))) as FileStoreAdapter<*>
@@ -366,13 +347,21 @@ object Cobblemon {
PlatformEvents.SERVER_STOPPED.subscribe {
storage.unregisterAll()
playerDataManager.saveAllStores()
playerData.saveAll()
}
PlatformEvents.SERVER_STARTED.subscribe {
bestSpawner.onServerStarted()
battleRegistry.onServerStarted()
}
PlatformEvents.SERVER_TICK_POST.subscribe { ServerTickHandler.onTick(it.server) }
POKEMON_CAPTURED.subscribe { AdvancementHandler.onCapture(it) }
// EGG_HATCH.subscribe { AdvancementHandler.onHatch(it) }
BATTLE_VICTORY.subscribe { AdvancementHandler.onWinBattle(it) }
EVOLUTION_COMPLETE.subscribe(Priority.LOWEST) { event ->
AdvancementHandler.onEvolve(event)
}
LEVEL_UP_EVENT.subscribe { AdvancementHandler.onLevelUp(it) }
TRADE_COMPLETED.subscribe { AdvancementHandler.onTradeCompleted(it) }
BagItems.observable.subscribe {
LOGGER.info("Starting dummy Showdown battle to force it to pre-load data.")
@@ -384,12 +373,8 @@ object Cobblemon {
).ifSuccessful { it.mute = true }
}
registerEventHandlers()
}
fun registerEventHandlers() {
AdvancementHandler.registerListeners()
PokedexHandler.registerListeners()
//To whomever is merging, this is moved out of Cobblemon and into the CobblemonImplementations
//CobblemonSherds.registerSherds()
}
fun getLevel(dimension: ResourceKey<Level>): Level? {
@@ -487,15 +472,13 @@ object Cobblemon {
}
private fun registerArgumentTypes() {
this.implementation.registerCommandArgument(cobblemonResource("pokemon"), SpeciesArgumentType::class, SingletonArgumentInfo.contextFree(SpeciesArgumentType::species))
this.implementation.registerCommandArgument(cobblemonResource("pokemon"), PokemonArgumentType::class, SingletonArgumentInfo.contextFree(PokemonArgumentType::pokemon))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_properties"), PokemonPropertiesArgumentType::class, SingletonArgumentInfo.contextFree(PokemonPropertiesArgumentType::properties))
this.implementation.registerCommandArgument(cobblemonResource("spawn_bucket"), SpawnBucketArgumentType::class, SingletonArgumentInfo.contextFree(SpawnBucketArgumentType::spawnBucket))
this.implementation.registerCommandArgument(cobblemonResource("move"), MoveArgumentType::class, SingletonArgumentInfo.contextFree(MoveArgumentType::move))
this.implementation.registerCommandArgument(cobblemonResource("party_slot"), PartySlotArgumentType::class, SingletonArgumentInfo.contextFree(PartySlotArgumentType::partySlot))
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, SingletonArgumentInfo.contextFree(PokemonStoreArgumentType::pokemonStore))
this.implementation.registerCommandArgument(cobblemonResource("dialogue"), DialogueArgumentType::class, SingletonArgumentInfo.contextFree(DialogueArgumentType::dialogue))
this.implementation.registerCommandArgument(cobblemonResource("form"), FormArgumentType::class, SingletonArgumentInfo.contextFree(FormArgumentType::form))
this.implementation.registerCommandArgument(cobblemonResource("dex"), DexArgumentType::class, SingletonArgumentInfo.contextFree (DexArgumentType::dex))
}
}
@@ -36,9 +36,6 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
@JvmField
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.of(::PCBlockEntity, CobblemonBlocks.PC).build(null))
@JvmField
val LECTERN: BlockEntityType<LecternBlockEntity> = this.create("lectern", BlockEntityType.Builder.of(::LecternBlockEntity, CobblemonBlocks.LECTERN).build(null))
@JvmField
val BERRY = this.create("berry", BlockEntityType.Builder.of(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common
import com.cobblemon.mod.common.api.apricorn.Apricorn
import com.cobblemon.mod.common.block.*
import com.cobblemon.mod.common.block.LecternBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.block.chest.GildedChestBlock
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
@@ -264,27 +263,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
)
)
@JvmField
val SMOOTH_TUMBLESTONE = this.create("smooth_tumblestone",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
)
)
@JvmField
val SMOOTH_TUMBLESTONE_STAIRS = this.create("smooth_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(SMOOTH_TUMBLESTONE.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SMOOTH_TUMBLESTONE)))
@JvmField
val SMOOTH_TUMBLESTONE_SLAB = this.create("smooth_tumblestone_slab", SlabBlock(BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
))
@JvmField
val TUMBLESTONE_BRICKS = this.create("tumblestone_bricks", Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_ORANGE)
@@ -292,7 +270,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
))
)
)
@JvmField
val TUMBLESTONE_BRICK_STAIRS = this.create("tumblestone_brick_stairs", StairsBlockInvoker.`cobblemon$create`(TUMBLESTONE_BRICKS.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(TUMBLESTONE_BRICKS)))
@JvmField
@@ -363,27 +342,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
)
)
@JvmField
val SMOOTH_SKY_TUMBLESTONE = this.create("smooth_sky_tumblestone",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.COLOR_LIGHT_BLUE)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
)
)
@JvmField
val SMOOTH_SKY_TUMBLESTONE_STAIRS = this.create("smooth_sky_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(SMOOTH_SKY_TUMBLESTONE.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SMOOTH_SKY_TUMBLESTONE)))
@JvmField
val SMOOTH_SKY_TUMBLESTONE_SLAB = this.create("smooth_sky_tumblestone_slab", SlabBlock(BlockBehaviour.Properties.of()
.mapColor(MapColor.COLOR_LIGHT_BLUE)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
))
@JvmField
val SKY_TUMBLESTONE_BRICKS = this.create("sky_tumblestone_bricks",
Block(
BlockBehaviour.Properties.of()
@@ -464,28 +422,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
.instrument(NoteBlockInstrument.BASEDRUM)
)
)
@JvmField
val SMOOTH_BLACK_TUMBLESTONE = this.create("smooth_black_tumblestone",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
)
)
@JvmField
val SMOOTH_BLACK_TUMBLESTONE_STAIRS = this.create("smooth_black_tumblestone_stairs", StairsBlockInvoker.`cobblemon$create`(SMOOTH_BLACK_TUMBLESTONE.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SMOOTH_BLACK_TUMBLESTONE)))
@JvmField
val SMOOTH_BLACK_TUMBLESTONE_SLAB = this.create("smooth_black_tumblestone_slab", SlabBlock(BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_BLACK)
.strength(1.0F)
.sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BASEDRUM)
))
@JvmField
val BLACK_TUMBLESTONE_BRICKS = this.create("black_tumblestone_bricks",
Block(
@@ -528,117 +464,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
)
)
@JvmField
val FIRE_STONE_BLOCK = this.create("fire_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.FIRE)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val WATER_STONE_BLOCK = this.create("water_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.WATER)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val THUNDER_STONE_BLOCK = this.create("thunder_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.GLOW_LICHEN)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val LEAF_STONE_BLOCK = this.create("leaf_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.COLOR_GREEN)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val ICE_STONE_BLOCK = this.create("ice_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.ICE)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val SUN_STONE_BLOCK = this.create("sun_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.TERRACOTTA_ORANGE)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val MOON_STONE_BLOCK = this.create("moon_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.DEEPSLATE)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val SHINY_STONE_BLOCK = this.create("shiny_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.QUARTZ)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val DAWN_STONE_BLOCK = this.create("dawn_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.DIAMOND)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val DUSK_STONE_BLOCK = this.create("dusk_stone_block",
Block(
BlockBehaviour.Properties.of()
.mapColor(MapColor.WARPED_HYPHAE)
.strength(1.0F)
.sound(CobblemonSounds.EVOLUTION_STONE_BLOCK_SOUNDS)
.requiresCorrectToolForDrops()
.instrument(NoteBlockInstrument.BIT)
)
)
@JvmField
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
@JvmField
@@ -813,19 +638,6 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
)
)
@JvmField
val LECTERN = create(
"lectern",
LecternBlock(
BlockBehaviour.Properties.of()
.mapColor(MapColor.WOOD)
.instrument(NoteBlockInstrument.BASS)
.sound(SoundType.WOOD)
.strength(2.5F)
.ignitedByLava()
)
)
@JvmField
val DISPLAY_CASE = create(
"display_case",
@@ -835,7 +647,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
.noOcclusion()
.pushReaction(PushReaction.BLOCK)
.mapColor(MapColor.STONE)
.strength(0.3F)
.strength(0.3f)
)
)
@@ -39,7 +39,6 @@ object CobblemonCommands {
PcCommand.register(dispatcher)
SpawnPokemonFromPool.register(dispatcher)
PokeboxCommand.register(dispatcher)
PokedexCommand.register(dispatcher)
TestStoreCommand.register(dispatcher)
QueryLearnsetCommand.register(dispatcher)
TestPcSlotCommand.register(dispatcher)
@@ -19,7 +19,6 @@ import com.cobblemon.mod.common.api.text.gray
import com.cobblemon.mod.common.block.BerryBlock
import com.cobblemon.mod.common.block.MintBlock
import com.cobblemon.mod.common.block.MintBlock.MintType
import com.cobblemon.mod.common.client.pokedex.PokedexTypes
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
import com.cobblemon.mod.common.item.*
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
@@ -153,21 +152,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val ANCIENT_ORIGIN_BALL = pokeBallItem(PokeBalls.ANCIENT_ORIGIN_BALL)
@JvmField
val POKEDEX_BLACK = create("pokedex_black", PokedexItem(PokedexTypes.BLACK))
@JvmField
val POKEDEX_BLUE = create("pokedex_blue", PokedexItem(PokedexTypes.BLUE))
@JvmField
val POKEDEX_GREEN = create("pokedex_green", PokedexItem(PokedexTypes.GREEN))
@JvmField
val POKEDEX_PINK = create("pokedex_pink", PokedexItem(PokedexTypes.PINK))
@JvmField
val POKEDEX_RED = create("pokedex_red", PokedexItem(PokedexTypes.RED))
@JvmField
val POKEDEX_WHITE = create("pokedex_white", PokedexItem(PokedexTypes.WHITE))
@JvmField
val POKEDEX_YELLOW = create("pokedex_yellow", PokedexItem(PokedexTypes.YELLOW))
@JvmField
val VIVICHOKE = compostableItem("vivichoke")
@@ -272,8 +256,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
@JvmField
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
@JvmField
val LECTERN = blockItem("lectern", CobblemonBlocks.LECTERN)
// Evolution items
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
@@ -980,12 +962,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHISELED_POLISHED_TUMBLESTONE = blockItem("chiseled_polished_tumblestone", CobblemonBlocks.CHISELED_POLISHED_TUMBLESTONE)
@JvmField
val SMOOTH_TUMBLESTONE = blockItem("smooth_tumblestone", CobblemonBlocks.SMOOTH_TUMBLESTONE)
@JvmField
val SMOOTH_TUMBLESTONE_STAIRS = blockItem("smooth_tumblestone_stairs", CobblemonBlocks.SMOOTH_TUMBLESTONE_STAIRS)
@JvmField
val SMOOTH_TUMBLESTONE_SLAB = blockItem("smooth_tumblestone_slab", CobblemonBlocks.SMOOTH_TUMBLESTONE_SLAB)
@JvmField
val TUMBLESTONE_BRICKS = blockItem("tumblestone_bricks", CobblemonBlocks.TUMBLESTONE_BRICKS)
@JvmField
val TUMBLESTONE_BRICK_STAIRS = blockItem("tumblestone_brick_stairs", CobblemonBlocks.TUMBLESTONE_BRICK_STAIRS)
@@ -1006,12 +982,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHISELED_POLISHED_SKY_TUMBLESTONE = blockItem("chiseled_polished_sky_tumblestone", CobblemonBlocks.CHISELED_POLISHED_SKY_TUMBLESTONE)
@JvmField
val SMOOTH_SKY_TUMBLESTONE = blockItem("smooth_sky_tumblestone", CobblemonBlocks.SMOOTH_SKY_TUMBLESTONE)
@JvmField
val SMOOTH_SKY_TUMBLESTONE_STAIRS = blockItem("smooth_sky_tumblestone_stairs", CobblemonBlocks.SMOOTH_SKY_TUMBLESTONE_STAIRS)
@JvmField
val SMOOTH_SKY_TUMBLESTONE_SLAB = blockItem("smooth_sky_tumblestone_slab", CobblemonBlocks.SMOOTH_SKY_TUMBLESTONE_SLAB)
@JvmField
val SKY_TUMBLESTONE_BRICKS = blockItem("sky_tumblestone_bricks", CobblemonBlocks.SKY_TUMBLESTONE_BRICKS)
@JvmField
val SKY_TUMBLESTONE_BRICK_STAIRS = blockItem("sky_tumblestone_brick_stairs", CobblemonBlocks.SKY_TUMBLESTONE_BRICK_STAIRS)
@@ -1032,12 +1002,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHISELED_POLISHED_BLACK_TUMBLESTONE = blockItem("chiseled_polished_black_tumblestone", CobblemonBlocks.CHISELED_POLISHED_BLACK_TUMBLESTONE)
@JvmField
val SMOOTH_BLACK_TUMBLESTONE = blockItem("smooth_black_tumblestone", CobblemonBlocks.SMOOTH_BLACK_TUMBLESTONE)
@JvmField
val SMOOTH_BLACK_TUMBLESTONE_STAIRS = blockItem("smooth_black_tumblestone_stairs", CobblemonBlocks.SMOOTH_BLACK_TUMBLESTONE_STAIRS)
@JvmField
val SMOOTH_BLACK_TUMBLESTONE_SLAB = blockItem("smooth_black_tumblestone_slab", CobblemonBlocks.SMOOTH_BLACK_TUMBLESTONE_SLAB)
@JvmField
val BLACK_TUMBLESTONE_BRICKS = blockItem("black_tumblestone_bricks", CobblemonBlocks.BLACK_TUMBLESTONE_BRICKS)
@JvmField
val BLACK_TUMBLESTONE_BRICK_STAIRS = blockItem("black_tumblestone_brick_stairs", CobblemonBlocks.BLACK_TUMBLESTONE_BRICK_STAIRS)
@@ -1048,27 +1012,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
@JvmField
val CHISELED_BLACK_TUMBLESTONE_BRICKS = blockItem("chiseled_black_tumblestone_bricks", CobblemonBlocks.CHISELED_BLACK_TUMBLESTONE_BRICKS)
@JvmField
val FIRE_STONE_BLOCK = blockItem("fire_stone_block", CobblemonBlocks.FIRE_STONE_BLOCK)
@JvmField
val WATER_STONE_BLOCK = blockItem("water_stone_block", CobblemonBlocks.WATER_STONE_BLOCK)
@JvmField
val THUNDER_STONE_BLOCK = blockItem("thunder_stone_block", CobblemonBlocks.THUNDER_STONE_BLOCK)
@JvmField
val LEAF_STONE_BLOCK = blockItem("leaf_stone_block", CobblemonBlocks.LEAF_STONE_BLOCK)
@JvmField
val ICE_STONE_BLOCK = blockItem("ice_stone_block", CobblemonBlocks.ICE_STONE_BLOCK)
@JvmField
val SUN_STONE_BLOCK = blockItem("sun_stone_block", CobblemonBlocks.SUN_STONE_BLOCK)
@JvmField
val MOON_STONE_BLOCK = blockItem("moon_stone_block", CobblemonBlocks.MOON_STONE_BLOCK)
@JvmField
val SHINY_STONE_BLOCK = blockItem("shiny_stone_block", CobblemonBlocks.SHINY_STONE_BLOCK)
@JvmField
val DAWN_STONE_BLOCK = blockItem("dawn_stone_block", CobblemonBlocks.DAWN_STONE_BLOCK)
@JvmField
val DUSK_STONE_BLOCK = blockItem("dusk_stone_block", CobblemonBlocks.DUSK_STONE_BLOCK)
@JvmField
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
"automaton_armor_trim_smithing_template",
@@ -24,7 +24,6 @@ import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
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.InteractPokemonUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
@@ -32,7 +31,6 @@ import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
import com.cobblemon.mod.common.client.net.pokedex.ServerConfirmedScanHandler
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
@@ -90,14 +88,19 @@ import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPac
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.starter.SetClientPlayerDataPacket
import com.cobblemon.mod.common.net.messages.client.storage.RemoveClientPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.SwapClientPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.party.InitializePartyPacket
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.SetPCBoxPokemonPacket
import com.cobblemon.mod.common.net.messages.client.storage.pc.SetPCPokemonPacket
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
@@ -107,7 +110,6 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotification
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.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.BattleSelectActionsPacket
@@ -125,7 +127,6 @@ import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
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.SetNicknamePacket
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
@@ -184,10 +185,6 @@ 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.UpdateTradeOfferHandler
import com.cobblemon.mod.common.net.messages.client.pokedex.ServerConfirmedScanPacket
import com.cobblemon.mod.common.net.messages.server.pokedex.scanner.FinishScanningPacket
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.util.server
import net.minecraft.server.level.ServerPlayer
@@ -267,7 +264,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(SummaryUIPacket.ID, SummaryUIPacket::decode, SummaryUIPacketHandler))
list.add(PacketRegisterInfo(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler))
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
// Starter packets
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
@@ -321,7 +317,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(NPCRegistrySyncPacket.ID, NPCRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(PokeRodRegistrySyncPacket.ID, PokeRodRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(ScriptRegistrySyncPacket.ID, ScriptRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(PokedexDexSyncPacket.ID, PokedexDexSyncPacket::decode, DataRegistrySyncPacketHandler()))
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
// Effects
@@ -371,8 +366,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler))
list.add(PacketRegisterInfo(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler))
//Pokedex scanning
list.add(PacketRegisterInfo(ServerConfirmedScanPacket.ID, ServerConfirmedScanPacket::decode, ServerConfirmedScanHandler))
return list
}
@@ -428,10 +421,6 @@ object CobblemonNetwork {
list.add(PacketRegisterInfo(OfferTradePacket.ID, OfferTradePacket::decode, OfferTradeHandler))
list.add(PacketRegisterInfo(UpdateTradeOfferPacket.ID, UpdateTradeOfferPacket::decode, UpdateTradeOfferHandler))
// Pokedex scanning
list.add(PacketRegisterInfo(StartScanningPacket.ID, StartScanningPacket::decode, StartScanningHandler))
list.add(PacketRegisterInfo(FinishScanningPacket.ID, FinishScanningPacket::decode, FinishScanningHandler))
// Pasture
list.add(PacketRegisterInfo(PasturePokemonPacket.ID, PasturePokemonPacket::decode, PasturePokemonHandler))
list.add(PacketRegisterInfo(UnpasturePokemonPacket.ID, UnpasturePokemonPacket::decode, UnpasturePokemonHandler))
@@ -61,43 +61,14 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
@JvmField
val POKEDEX_OPEN = this.create("item.pokedex.open")
@JvmField
val POKEDEX_CLOSE = this.create("item.pokedex.close")
@JvmField
val POKEDEX_SCAN_OPEN = this.create("item.pokedex.scan_open")
@JvmField
val POKEDEX_SCAN_CLOSE = this.create("item.pokedex.scan_close")
@JvmField
val POKEDEX_SCAN = this.create("item.pokedex.scan")
@JvmField
val POKEDEX_SCAN_LOOP = this.create("item.pokedex.scan_loop")
@JvmField
val POKEDEX_SCAN_DETAIL = this.create("item.pokedex.scan_detail")
@JvmField
val POKEDEX_CLICK = this.create("item.pokedex.click")
@JvmField
val POKEDEX_CLICK_SHORT = this.create("item.pokedex.click_short")
@JvmField
val POKEDEX_SNAP_PICTURE = this.create("item.pokedex.snap")
@JvmField
val POKEDEX_ZOOM_IN = this.create("item.pokedex.zoom_in")
@JvmField
val POKEDEX_ZOOM_OUT = this.create("item.pokedex.zoom_out")
@JvmField
val POKEDEX_ZOOM_INCREMENT = this.create("item.pokedex.zoom_increment")
@JvmField
val ITEM_USE = this.create("item.use")
@JvmField
val EVOLUTION_NOTIFICATION = this.create("evolution.notification")
val CAN_EVOLVE = this.create("pokemon.can_evolve")
@JvmField
val EVOLUTION_UI = this.create("evolution.ui")
val EVOLVING = this.create("pokemon.evolving")
@JvmField
val EVOLUTION = this.create("evolution")
val EVOLVE = this.create("evolution.evolve")
@JvmField
val PVN_BATTLE = this.create("battle.pvn.default")
@@ -190,15 +161,6 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
@JvmField
val TUMBLESTONE_STEP = this.create("tumblestone.step")
@JvmField
val EVOLUTION_STONE_BLOCK_BREAK = this.create("evolution_stone_block.break")
@JvmField
val EVOLUTION_STONE_BLOCK_HIT = this.create("evolution_stone_block.hit")
@JvmField
val EVOLUTION_STONE_BLOCK_PLACE = this.create("evolution_stone_block.place")
@JvmField
val EVOLUTION_STONE_BLOCK_STEP = this.create("evolution_stone_block.step")
@JvmField
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
@JvmField
@@ -248,7 +210,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
@JvmField
val RELIC_COIN_SACK_SOUNDS = SoundType(1f, 1.1f,
val RELIC_COIN_SACK_SOUNDS = SoundType(1f, 1f,
RELIC_COIN_SACK_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_SACK_PLACE,
@@ -256,7 +218,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
RELIC_COIN_SACK_STEP
)
@JvmField
val RELIC_COIN_POUCH_SOUNDS = SoundType(1f, 1.1f,
val RELIC_COIN_POUCH_SOUNDS = SoundType(1f, 1f,
RELIC_COIN_POUCH_BREAK,
RELIC_COIN_SACK_STEP,
RELIC_COIN_POUCH_PLACE,
@@ -302,7 +264,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
val IMPACT_WATER = this.create("impact.water")
@JvmField
val TUMBLESTONE_SOUNDS = SoundType(1f, 1.1f,
val TUMBLESTONE_SOUNDS = SoundType(1f, 1f,
TUMBLESTONE_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
@@ -311,25 +273,16 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val TUMBLESTONE_BLOCK_SOUNDS = SoundType(1f, 1.1f,
val TUMBLESTONE_BLOCK_SOUNDS = SoundType(1f, 1f,
TUMBLESTONE_BLOCK_BREAK,
TUMBLESTONE_STEP,
TUMBLESTONE_PLACE,
TUMBLESTONE_HIT,
TUMBLESTONE_STEP
)
@JvmField
val EVOLUTION_STONE_BLOCK_SOUNDS = SoundType(1f, 1.1f,
EVOLUTION_STONE_BLOCK_BREAK,
EVOLUTION_STONE_BLOCK_STEP,
EVOLUTION_STONE_BLOCK_PLACE,
EVOLUTION_STONE_BLOCK_HIT,
EVOLUTION_STONE_BLOCK_STEP
)
@JvmField
val BERRY_BUSH_SOUNDS = SoundType(0.8f, 1.1f,
val BERRY_BUSH_SOUNDS = SoundType(1f, 1f,
BERRY_BUSH_BREAK,
SoundEvents.GRASS_STEP,
BERRY_BUSH_PLACE,
@@ -338,25 +291,25 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val BIG_ROOT_SOUNDS = SoundType(0.8f, 1.1f,
val BIG_ROOT_SOUNDS = SoundType(1f, 1f,
BIG_ROOT_BREAK,
SoundEvents.ROOTS_STEP,
SoundEvents.ROOTS_PLACE,
SoundEvents.ROOTS_HIT,
SoundEvents.ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = SoundType(1f, 1f,
SoundEvents.ROOTS_BREAK,
SoundEvents.ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.ROOTS_HIT,
SoundEvents.ROOTS_FALL
)
@JvmField
val ENERGY_ROOT_SOUNDS = SoundType(0.8f, 1.1f,
BIG_ROOT_BREAK,
SoundEvents.ROOTS_STEP,
ENERGY_ROOT_PLACE,
SoundEvents.ROOTS_HIT,
SoundEvents.ROOTS_FALL
)
@JvmField
val MEDICINAL_LEEK_SOUNDS = SoundType(1f, 1.1f,
val MEDICINAL_LEEK_SOUNDS = SoundType(1f, 1f,
MEDICINAL_LEEK_BREAK,
SoundEvents.GRASS_STEP,
MEDICINAL_LEEK_PLACE,
@@ -365,7 +318,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val VIVICHOKE_SOUNDS = SoundType(0.6f, 1.1f,
val VIVICHOKE_SOUNDS = SoundType(1f, 1f,
VIVICHOKE_BREAK,
SoundEvents.GRASS_STEP,
VIVICHOKE_PLACE,
@@ -374,7 +327,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val MINT_SOUNDS = SoundType(0.6f, 1.1f,
val MINT_SOUNDS = SoundType(1f, 1f,
MINT_BREAK,
SoundEvents.GRASS_STEP,
MINT_PLACE,
@@ -383,7 +336,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val REVIVAL_HERB_SOUNDS = SoundType(0.6f, 1.1f,
val REVIVAL_HERB_SOUNDS = SoundType(1f, 1f,
REVIVAL_HERB_BREAK,
SoundEvents.GRASS_STEP,
REVIVAL_HERB_PLACE,
@@ -392,7 +345,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
)
@JvmField
val GILDED_CHEST_SOUNDS = SoundType(1f, 1.1f,
val GILDED_CHEST_SOUNDS = SoundType(1f, 1f,
GILDED_CHEST_BREAK,
GILDED_CHEST_STEP,
GILDED_CHEST_PLACE,
@@ -59,7 +59,7 @@ class AspectCriterion(
// pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
// }
//
// override fun matches(player: ServerPlayer, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
// override fun matches(player: ServerPlayerEntity, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
// val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
// return this.aspects.all { it in caughtAspects }
// }
@@ -34,7 +34,8 @@ class BattleCountableCriterion(
override fun matches(player: ServerPlayer, context: BattleCountableContext): Boolean {
var typeCheck = false
val advancementData = Cobblemon.playerDataManager.getGenericData(player).advancementData
val advancementData = Cobblemon.playerData.get(player).advancementData
if (battleTypes.isEmpty() || battleTypes.contains("any")) {
typeCheck = true
}
@@ -86,7 +87,7 @@ class BattleCountableCriterion(
// json.add("battle_types", battleTypes.toJsonArray())
// }
//
// override fun matches(player: ServerPlayer, context: BattleCountableContext): Boolean {
// override fun matches(player: ServerPlayerEntity, context: BattleCountableContext): Boolean {
// var typeCheck = false
// val advancementData = Cobblemon.playerData.get(player).advancementData
// if (battleTypes.isEmpty() || battleTypes.contains("any")) {
@@ -54,7 +54,7 @@ class CaughtPokemonCriterion(
// type = json.get("type")?.asString ?: "any"
// }
//
// override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
// override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
// return super.matches(player, context) && (context.type == type || type == "any")
// }
//}
@@ -50,7 +50,7 @@ open class CountableCriterion<T : CountableContext>(
// json.addProperty("count", count)
// }
//
// override fun matches(player: ServerPlayer, context: T) = context.times >= count
// override fun matches(player: ServerPlayerEntity, context: T) = context.times >= count
//}
//
///**
@@ -64,7 +64,7 @@ open class CountableCriterion<T : CountableContext>(
// * @since November 4th, 2022
// */
//class SimpleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountableContext>(id, predicate)
//fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayer, times: Int) = trigger(player, CountableContext(times))
//fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayerEntity, times: Int) = trigger(player, CountableContext(times))
//
///**
// * Some type of context that has a count associated with it, representing how many times the trigger has occurred.
@@ -55,7 +55,7 @@ class EvolvePokemonCriterion(
// evolution = json.get("evolution")?.asString ?: "any"
// }
//
// override fun matches(player: ServerPlayer, context: EvolvePokemonContext): Boolean {
// override fun matches(player: ServerPlayerEntity, context: EvolvePokemonContext): Boolean {
// return context.times >= count && (context.species == species.asIdentifierDefaultingNamespace() || species == "any") &&
// (context.evolution == evolution.asIdentifierDefaultingNamespace() || evolution == "any")
// }
@@ -57,7 +57,7 @@ class LevelUpCriterion(
evolved = json.get("has_evolved")?.asBoolean ?: true
}
override fun matches(player: ServerPlayer, context: LevelUpContext): Boolean {
override fun matches(player: ServerPlayerEntity, context: LevelUpContext): Boolean {
val preEvo = context.pokemon.preEvolution == null
val hasEvolution = !context.pokemon.evolutions.none()
var evolutionCheck = true
@@ -79,7 +79,7 @@ class PartyCheckCriterion(
}
}
override fun matches(player: ServerPlayer, context: PartyCheckContext): Boolean {
override fun matches(player: ServerPlayerEntity, context: PartyCheckContext): Boolean {
val playerParty = player.party()
val matches = mutableListOf<Identifier>()
party.forEach {
@@ -57,7 +57,7 @@ class PlantTumblestoneCriterion(
// * @param context The context of the criterion
// * @return True if the tumblestone block can grow at the given position, false otherwise
// */
// override fun matches(player: ServerPlayer, context: PlantTumblestoneContext): Boolean {
// override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
// return context.tumbleStoneBlock.canGrow(context.pos, player.level())
// }
//}
@@ -80,7 +80,7 @@ class TradePokemonCriterion(
receivedHeldItem = json.get("received_held_item")?.asString ?: "minecraft:air"
}
override fun matches(player: ServerPlayer, context: TradePokemonContext): Boolean {
override fun matches(player: ServerPlayerEntity, context: TradePokemonContext): Boolean {
val heldItem1 = context.traded.heldItem().item.registryEntry.ResourceKey().value
val heldItem2 = context.received.heldItem().item.registryEntry.ResourceKey().value
return (context.traded.species.resourceIdentifier == traded.asIdentifierDefaultingNamespace() || traded == "any") &&
@@ -33,7 +33,6 @@ import java.io.PrintWriter
* @since April 1st, 2022.
*/
object JsonManifestWalker {
// im walkin ere
/**
* Builds a manifest at [manifestPath] using the files inside the same folder.
*
@@ -21,7 +21,6 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
import com.cobblemon.mod.common.api.events.CobblemonEvents
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
import com.cobblemon.mod.common.api.moves.Moves
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
import com.cobblemon.mod.common.api.net.NetworkPacket
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
@@ -115,7 +114,7 @@ open class PokemonBattle(
var ended = false
// TEMP battle showcase stuff
var announcingRules = false
var turn: Int = 0
var turn: Int = 1
private set
private var ticks: Int = 0
@@ -141,7 +141,7 @@ abstract class BattleActor(
* NPC and player actors expect to append their [getName] while wild Pokémon append nothing.
*
* @param name The name of an object being appended, typically a Pokémon nickname received from showdown.
* @return A [MutableComponent] of the [name] append with owner prefix.
* @return A [MutableText] of the [name] append with owner prefix.
*/
abstract fun nameOwned(name: String): MutableComponent
@@ -27,7 +27,6 @@ import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent
import com.cobblemon.mod.common.api.events.pokeball.PokeBallCaptureCalculatedEvent
import com.cobblemon.mod.common.api.events.pokeball.PokemonCatchRateEvent
import com.cobblemon.mod.common.api.events.pokeball.ThrownPokeballHitEvent
import com.cobblemon.mod.common.api.events.pokedex.scanning.PokemonScannedEvent
import com.cobblemon.mod.common.api.events.pokemon.*
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionAcceptedEvent
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEvent
@@ -41,7 +40,6 @@ import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
import com.cobblemon.mod.common.api.reactive.CancelableObservable
import com.cobblemon.mod.common.api.reactive.EventObservable
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.Observable.Companion.filter
import com.cobblemon.mod.common.api.reactive.Observable.Companion.map
import com.cobblemon.mod.common.api.reactive.SimpleObservable
@@ -69,6 +67,8 @@ object CobblemonEvents {
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
@JvmField
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
@JvmField
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
@JvmField
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
@@ -147,9 +147,6 @@ object CobblemonEvents {
@JvmField
val STARTER_CHOSEN = CancelableObservable<StarterChosenEvent>()
@JvmField
val POKEMON_SCANNED = EventObservable<PokemonScannedEvent>()
@JvmField
val APRICORN_HARVESTED = EventObservable<ApricornHarvestEvent>()
// Berries
@@ -169,9 +166,4 @@ object CobblemonEvents {
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
@JvmField
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
@JvmField
val POKEMON_GAINED = EventObservable<PokemonGainedEvent>()
@JvmField
val POKEMON_SEEN = EventObservable<PokemonSeenEvent>()
}
}
@@ -1,21 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokedex.scanning
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
data class PokemonScannedEvent(val player: ServerPlayer, val scannedEntity: PokemonEntity) {
val pokemon: Pokemon
get() = scannedEntity.pokemon
val isOwned: Boolean
get() = pokemon.getOwnerPlayer() == player
}
@@ -10,5 +10,5 @@ package com.cobblemon.mod.common.api.events.pokemon
//data class HatchEggEvent (
// val pokemon: Pokemon,
// val player: ServerPlayer
// val player: ServerPlayerEntity
//)
@@ -1,18 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon
import com.cobblemon.mod.common.pokemon.Pokemon
import java.util.UUID
data class PokemonGainedEvent(
val playerId: UUID,
val pokemon: Pokemon
) {
}
@@ -1,19 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.events.pokemon
import com.cobblemon.mod.common.pokemon.Pokemon
import net.minecraft.server.level.ServerPlayer
import java.util.UUID
data class PokemonSeenEvent(
val playerId: UUID,
val pokemon: Pokemon
) {
}
@@ -29,7 +29,7 @@ data class PokeRod(
val pokeBallId: ResourceLocation,
//Hex string of color
val lineColor: String,
var name: ResourceLocation
var name: ResourceLocation// ?// TODO (techdaan) Why was this nullable?
) {
internal fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeIdentifier(name)
@@ -10,14 +10,10 @@ package com.cobblemon.mod.common.api.gui
import com.cobblemon.mod.common.api.text.font
import com.cobblemon.mod.common.client.gui.battle.BattleOverlay.Companion.PORTRAIT_DIAMETER
import com.cobblemon.mod.common.client.render.SpriteType
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
import com.cobblemon.mod.common.client.render.models.blockbench.repository.PokemonModelRepository
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository
import com.cobblemon.mod.common.entity.PoseType
import com.cobblemon.mod.common.util.toHex
import com.mojang.authlib.minecraft.client.MinecraftClient
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.platform.Lighting
import com.mojang.blaze3d.systems.RenderSystem
@@ -98,6 +94,8 @@ fun drawRectangle(
bufferbuilder.addVertex(matrix, endX, endY, blitOffset).setUv(maxU, maxV)
bufferbuilder.addVertex(matrix, endX, y, blitOffset).setUv(maxU, minV)
bufferbuilder.addVertex(matrix, x, y, blitOffset).setUv(minU, minV)
// TODO: Figure out if this is correct replacement.
// OLD: BufferRenderer.draw(bufferbuilder)
BufferUploader.drawWithShader(bufferbuilder.buildOrThrow())
}
@@ -116,6 +114,21 @@ fun drawCenteredText(
context.drawString(textRenderer, comp, x.toInt() - textRenderer.width(comp) / 2, y.toInt(), colour, shadow)
}
@JvmOverloads
fun drawTextJustifiedRight(
context: GuiGraphics,
font: ResourceLocation? = null,
text: MutableComponent,
x: Number,
y: Number,
colour: Int,
shadow: Boolean = true
) {
val comp = text.let { if (font != null) it.font(font) else it }
val font = Minecraft.getInstance().font
context.drawString(font, comp, x.toInt() - font.width(comp), y.toInt(), colour, shadow)
}
@JvmOverloads
fun drawText(
context: GuiGraphics,
@@ -148,21 +161,6 @@ fun drawText(
return isHovered
}
@JvmOverloads
fun drawTextJustifiedRight(
context: GuiGraphics,
font: ResourceLocation? = null,
text: MutableComponent,
x: Number,
y: Number,
colour: Int,
shadow: Boolean = true
) {
val comp = text.let { if (font != null) it.font(font) else it }
val font = Minecraft.getInstance().font
context.drawString(font, comp, x.toInt() - font.width(comp), y.toInt(), colour, shadow)
}
@JvmOverloads
fun drawText(
context: GuiGraphics,
@@ -216,77 +214,60 @@ fun drawPosablePortrait(
limbSwingAmount: Float = 0F,
ageInTicks: Float = 0F,
headYaw: Float = 0F,
headPitch: Float = 0F,
r: Float = 1F,
g: Float = 1F,
b: Float = 1F,
a: Float = 1F
headPitch: Float = 0F
) {
val model = repository.getPoser(identifier, aspects)
state.currentAspects = aspects
state.currentModel = model
val texture = repository.getTexture(identifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, contextScale)
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
val renderType = RenderType.entityCutout(texture)
RenderSystem.applyModelViewMatrix()
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (reversed) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
val originalPose = state.currentPose
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
originalPose?.let { state.setPose(it) }
matrixStack.pushPose()
matrixStack.translate(0.0, PORTRAIT_DIAMETER.toDouble() + 2.0, 0.0)
matrixStack.scale(scale, scale, -scale)
matrixStack.translate(0.0, -PORTRAIT_DIAMETER / 18.0, 0.0)
matrixStack.translate(model.portraitTranslation.x * if (reversed) -1F else 1F, model.portraitTranslation.y, model.portraitTranslation.z - 4)
matrixStack.scale(model.portraitScale, model.portraitScale, 1 / model.portraitScale)
matrixStack.mulPose(quaternion1) // TODO (techdaan): correct?
matrixStack.mulPose(quaternion2)
val sprite = repository.getSprite(identifier, aspects, SpriteType.PORTRAIT);
val light1 = Vector3f(0.2F, 1.0F, -1.0F)
val light2 = Vector3f(0.1F, 0.0F, 8.0F)
RenderSystem.setShaderLights(light1, light2)
quaternion1.conjugate()
if (sprite == null) {
val model = repository.getPoser(identifier, aspects)
state.currentAspects = aspects
state.currentModel = model
val texture = repository.getTexture(identifier, aspects, state.animationSeconds)
val immediate = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = immediate.getBuffer(renderType)
val packedLight = LightTexture.pack(11, 7)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(identifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, contextScale)
context.put(RenderContext.SPECIES, identifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
val renderType = RenderType.entityCutout(texture)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (reversed) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
val originalPose = state.currentPose
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, limbSwing, limbSwingAmount, ageInTicks, headYaw, headPitch)
originalPose?.let { state.setPose(it) }
matrixStack.translate(
model.portraitTranslation.x * if (reversed) -1F else 1F,
model.portraitTranslation.y,
model.portraitTranslation.z - 4
)
matrixStack.scale(model.portraitScale, model.portraitScale, 1 / model.portraitScale)
matrixStack.mulPose(quaternion1)
matrixStack.mulPose(quaternion2)
val light1 = Vector3f(0.2F, 1.0F, -1.0F)
val light2 = Vector3f(0.1F, 0.0F, 8.0F)
RenderSystem.setShaderLights(light1, light2)
quaternion1.conjugate()
val immediate = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = immediate.getBuffer(renderType)
val packedLight = LightTexture.pack(11, 7)
val colour = toHex(r, g, b, a)
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, colour)
immediate.endBatch()
}
model.setDefault()
Lighting.setupFor3DItems()
} else {
renderSprite(matrixStack, sprite)
model.withLayerContext(immediate, state, repository.getLayers(identifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
immediate.endBatch()
}
matrixStack.popPose()
model.setDefault()
Lighting.setupFor3DItems()
}
fun drawProfile(
@@ -298,75 +279,50 @@ fun drawProfile(
partialTicks: Float,
scale: Float = 20F
) {
val model = repository.getPoser(resourceIdentifier, aspects)
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f).let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, 1F)
context.put(RenderContext.SPECIES, resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
state.currentAspects = aspects
state.currentModel = model
val renderType = RenderType.entityCutout(texture)//model.getLayer(texture)
RenderSystem.applyModelViewMatrix()
matrixStack.scale(scale, scale, -scale)
val sprite = repository.getSprite(resourceIdentifier, aspects, SpriteType.PROFILE);
if(sprite == null) {
val model = repository.getPoser(resourceIdentifier, aspects)
val texture = repository.getTexture(resourceIdentifier, aspects, state.animationSeconds)
val context = RenderContext()
model.context = context
repository.getTextureNoSubstitute(resourceIdentifier, aspects, 0f)
.let { context.put(RenderContext.TEXTURE, it) }
context.put(RenderContext.SCALE, 1F)
context.put(RenderContext.SPECIES, resourceIdentifier)
context.put(RenderContext.ASPECTS, aspects)
context.put(RenderContext.POSABLE_STATE, state)
state.currentAspects = aspects
state.currentModel = model
val renderType = RenderType.entityCutout(texture)//model.getLayer(texture)
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
state.setPoseToFirstSuitable(PoseType.PORTRAIT)
state.updatePartialTicks(partialTicks)
model.applyAnimations(null, state, 0F, 0F, 0F, 0F, 0F)
matrixStack.translate(model.profileTranslation.x, model.profileTranslation.y, model.profileTranslation.z - 4.0)
matrixStack.scale(model.profileScale, model.profileScale, 1 / model.profileScale)
// matrixStack.multiply(rotation)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (false) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
matrixStack.mulPose(quaternion1)
matrixStack.mulPose(quaternion2)
Lighting.setupForEntityInInventory()
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
entityRenderDispatcher.setRenderShadow(true)
val quaternion1 = Axis.YP.rotationDegrees(-32F * if (false) -1F else 1F)
val quaternion2 = Axis.XP.rotationDegrees(5F)
matrixStack.mulPose(quaternion1)
matrixStack.mulPose(quaternion2)
Lighting.setupForEntityInInventory() // TODO (techdaan): Does this map correctly?
val entityRenderDispatcher = Minecraft.getInstance().entityRenderDispatcher
entityRenderDispatcher.setRenderShadow(true)
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
val bufferSource = Minecraft.getInstance().renderBuffers().bufferSource()
val buffer = bufferSource.getBuffer(renderType)
val light1 = Vector3f(-1F, 1F, 1.0F)
val light2 = Vector3f(1.3F, -1F, 1.0F)
RenderSystem.setShaderLights(light1, light2)
val packedLight = LightTexture.pack(11, 7)
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
}
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
} else {
renderSprite(matrixStack, sprite)
model.withLayerContext(bufferSource, state, repository.getLayers(resourceIdentifier, aspects)) {
model.render(context, matrixStack, buffer, packedLight, OverlayTexture.NO_OVERLAY, -0x1)
bufferSource.endBatch()
}
}
fun renderSprite(matrixStack: PoseStack, sprite: ResourceLocation) {
val matrix: PoseStack.Pose = matrixStack.last()
matrix.pose().translate(-1f, 0f, 0f)
RenderSystem.setShaderTexture(0, sprite);
RenderSystem.setShader(GameRenderer::getPositionTexShader)
var buffer = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
buffer.addVertex(matrix, 2f, 0f, 0.0f).setUv(1f, 0f)
buffer.addVertex(matrix, 0f, 0f, 0.0f).setUv(0f, 0f)
buffer.addVertex(matrix, 0f, 2f, 0.0f).setUv(0f, 1f)
buffer.addVertex(matrix, 2f, 2f, 0.0f).setUv(1f, 1f)
BufferUploader.drawWithShader(buffer.buildOrThrow())
model.setDefault()
entityRenderDispatcher.setRenderShadow(true)
Lighting.setupFor3DItems()
}
@@ -41,27 +41,20 @@ class MultiLineLabelK(
fun renderLeftAligned(
context: GuiGraphics,
x: Number, y: Number,
YStartOffset: Number = 0,
ySpacing: Number,
colour: Int,
scale: Float = 1F,
shadow: Boolean = true
) {
context.pose().pushPose()
context.pose().scale(scale, scale, 1F)
comps.forEachIndexed { index, textWithWidth ->
val yOffset = if (index == 0) YStartOffset else 0
drawString(
context = context,
x = x.toFloat() / scale,
y = (y.toFloat() + yOffset.toFloat() + ySpacing.toFloat() * index) / scale,
x = x, y = y.toFloat() + ySpacing.toFloat() * index,
colour = colour,
shadow = shadow,
text = textWithWidth.text.string,
font = font
)
}
context.pose().popPose()
}
class TextWithWidth internal constructor(val text: FormattedText, val width: Int)
@@ -99,7 +99,7 @@ interface PokemonSelectingItem {
stack.shrink(1)
battlePokemon.actor.itemsUsed.add(bagItem)
}
CobblemonCriteria.POKEMON_INTERACT.trigger(player, PokemonInteractContext(battlePokemon.effectedPokemon.species.resourceIdentifier, BuiltInRegistries.ITEM.getKey(stack.item)))
CobblemonCriteria.POKEMON_INTERACT.trigger(player, PokemonInteractContext(battlePokemon.entity!!.pokemon.species.resourceIdentifier, BuiltInRegistries.ITEM.getKey(stack.item)))
}
}
@@ -10,8 +10,6 @@ package com.cobblemon.mod.common.api.molang
import com.bedrockk.molang.runtime.MoLangRuntime
import com.bedrockk.molang.runtime.value.MoValue
import com.cobblemon.mod.common.util.asExpressionLike
import com.mojang.serialization.Codec
/**
* An object that can be given a [MoLangRuntime] to produce a single [MoValue]. This abstracts
@@ -33,11 +31,4 @@ interface ExpressionLike {
fun resolveBoolean(runtime: MoLangRuntime) = resolveDouble(runtime) == 1.0
fun resolveObject(runtime: MoLangRuntime) = resolve(runtime) as ObjectValue<*>
companion object {
val CODEC: Codec<ExpressionLike> = Codec.STRING.xmap({
it.asExpressionLike()
}) {
it.getString()
}
}
}
@@ -35,8 +35,10 @@ class MoveSet : Iterable<Move> {
/**
* Gets all Moves from the Pokémon but skips null Moves
*/
fun getMoves() = moves.filterNotNull()
fun getMovesWithNulls() = moves.toList()
fun getMoves(): List<Move> {
return moves.filterNotNull()
}
fun hasSpace() = moves.any { it == null }
/**
@@ -123,7 +125,6 @@ class MoveSet : Iterable<Move> {
for (i in 0 until MOVE_COUNT) {
if (moves[i] == null) {
moves[i] = move
move.observable.subscribe { this.update() }
update()
return
}
@@ -90,7 +90,7 @@ interface EntityProvider {
}
//class MoveAnimationKeyframe(
// val sound: ResourceLocation? = null,
// val sound: Identifier? = null,
// val animation: List<AnimationWithMoments> = listOf(),
// val effects: List<ActionEffect> = listOf()
//)
@@ -13,7 +13,7 @@ import java.util.concurrent.CompletableFuture
class CannotInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
context.canBeInterrupted = false
context.canBeInterrupted = true
return CompletableFuture.completedFuture(Unit)
}
}
@@ -71,7 +71,6 @@ object CobblemonPermissions {
val CLEAR_PARTY = this.create("${COMMAND_PREFIX}clearparty", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val CLEAR_PC = this.create("${COMMAND_PREFIX}clearpc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val POKEDEX = this.create("${COMMAND_PREFIX}pokedex", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
val NPC_EDIT = this.create("${COMMAND_PREFIX}npcedit", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
@@ -163,6 +163,7 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
createDefault("safari_ball", CatchRateModifiers.SAFARI)
createDefault("fast_ball", BaseStatModifier(Stats.SPEED, { it >= 100 }, 4F))
createDefault("level_ball", CatchRateModifiers.LEVEL)
// ToDo we will need fishing context here once fishing is implemented for a multiplier
createDefault("lure_ball", CatchRateModifiers.LURE)
createDefault("heavy_ball", CatchRateModifiers.WEIGHT_BASED)
createDefault("love_ball", CatchRateModifiers.LOVE)
@@ -1,152 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
import net.minecraft.resources.ResourceLocation
abstract class AbstractPokedexManager {
open val speciesRecords: MutableMap<ResourceLocation, SpeciesDexRecord> = mutableMapOf()
private val dexCalculatedValues = mutableMapOf<ResourceLocation, MutableMap<PokedexValueCalculator<*>, Any>>()
private val globalCalculatedValues = mutableMapOf<GlobalPokedexValueCalculator<*>, Any>()
@Transient
val struct = QueryStruct(hashMapOf()).addStandardFunctions()
.addFunction("get_species_record") { params ->
val speciesId = params.getString(0).asIdentifierDefaultingNamespace()
speciesRecords[speciesId]?.struct ?: QueryStruct(hashMapOf())
}
fun deleteSpeciesRecord(speciesId: ResourceLocation) {
speciesRecords.remove(speciesId)
markDirty()
}
fun getSpeciesRecord(speciesId: ResourceLocation): SpeciesDexRecord? {
return speciesRecords[speciesId]
}
fun getOrCreateSpeciesRecord(speciesId: ResourceLocation): SpeciesDexRecord {
return speciesRecords.getOrPut(speciesId) {
val record = SpeciesDexRecord()
record.initialize(this, speciesId)
onSpeciesRecordUpdated(record)
record
}
}
fun getHighestKnowledgeFor(entry: PokedexEntry): PokedexEntryProgress {
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return PokedexEntryProgress.NONE
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return PokedexEntryProgress.NONE
}
// For each distinct form in this entry, get the highest knowledge level for the unlock forms, then take the highest of those.
return entry.forms.maxOfOrNull { form ->
form.unlockForms.maxOfOrNull {
speciesRecord.getFormRecord(it)?.knowledge ?: PokedexEntryProgress.NONE
} ?: PokedexEntryProgress.NONE
} ?: PokedexEntryProgress.NONE
}
fun getEncounteredForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.ENCOUNTERED)
}
fun getCaughtForms(entry: PokedexEntry) : List<PokedexForm> {
return getFormsWithKnowledge(entry, PokedexEntryProgress.CAUGHT)
}
fun getFormsWithKnowledge(entry: PokedexEntry, knowledge: PokedexEntryProgress) : List<PokedexForm> {
val speciesRecord = getSpeciesRecord(entry.speciesId) ?: return emptyList()
val hasAllAspects = entry.conditionAspects.all(speciesRecord::hasAspect)
if (!hasAllAspects) {
return emptyList()
}
// For each distinct form in this entry, get the highest knowledge level for the unlock forms, then take the highest of those.
return entry.forms.filter { form ->
form.unlockForms.any { (speciesRecord.getFormRecord(it)?.knowledge ?: PokedexEntryProgress.NONE) >= knowledge }
}
}
fun getSeenShinyStates(entry: PokedexEntry, form: PokedexForm): Set<String> {
return getSpeciesRecord(entry.speciesId)?.getFormRecord(form.displayForm)?.getSeenShinyStates() ?: return emptySet()
}
fun getSeenGenders(entry: PokedexEntry, form: PokedexForm): Set<Gender> {
return getSpeciesRecord(entry.speciesId)?.getFormRecord(form.displayForm)?.getGenders() ?: emptySet()
}
fun getSeenAspects(entry: PokedexEntry): Set<String> {
return getSpeciesRecord(entry.speciesId)?.getAspects() ?: emptySet()
}
fun getKnowledgeForSpecies(speciesId: ResourceLocation): PokedexEntryProgress {
return speciesRecords[speciesId]?.getKnowledge() ?: PokedexEntryProgress.NONE
}
open fun onSpeciesRecordUpdated(speciesDexRecord: SpeciesDexRecord) {
// Save stuff and packet updates
dexCalculatedValues.clear()
globalCalculatedValues.clear()
}
fun <T : Any> getDexCalculatedValue(dex: ResourceLocation, calculatedPokedexValue: PokedexValueCalculator<T>): T {
val existingValue = dexCalculatedValues[dex]?.get(calculatedPokedexValue) as? T
if (existingValue != null) {
return existingValue
} else {
val vals = dexCalculatedValues.getOrPut(dex) { mutableMapOf() }
val newValue = calculatedPokedexValue.calculate(this, Dexes.dexEntryMap[dex]!!.getEntries().associateBy { it.id })
vals[calculatedPokedexValue] = newValue
return newValue
}
}
fun <T : Any> getGlobalCalculatedValue(calculatedPokedexValue: GlobalPokedexValueCalculator<T>): T {
val existingValue = globalCalculatedValues[calculatedPokedexValue] as? T
if (existingValue != null) {
return existingValue
} else {
val newValue = calculatedPokedexValue.calculate(this)
globalCalculatedValues[calculatedPokedexValue] = newValue
return newValue
}
}
open fun markDirty() {
// Save stuff
}
companion object {
const val NUM_CAUGHT_KEY = "cobblemon.pokedex.entries.caught"
const val NUM_SEEN_KEY = "cobblemon.pokedex.entries.seen"
fun getKeyForSpeciesBase(speciesId: ResourceLocation): String {
return "cobblemon.pokedex.${speciesId.path}"
}
fun getKnowledgeKeyForSpecies(speciesId: ResourceLocation): String {
return "${getKeyForSpeciesBase(speciesId)}.knowledge"
}
fun getKnowledgeKeyForForm(speciesId: ResourceLocation, formName: String): String {
return "${getKnowledgeKeyForSpecies(speciesId)}.${formName.lowercase()}"
}
fun getCaptureMethodKeyForSpecies(speciesId: ResourceLocation): String {
return "${getKeyForSpeciesBase(speciesId)}.capturemethod"
}
}
}
@@ -1,78 +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.pokedex
import com.cobblemon.mod.common.Cobblemon
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.DexAdditions.DexAddition
import com.cobblemon.mod.common.api.pokedex.def.AggregatePokedexDef
import com.cobblemon.mod.common.api.pokedex.def.SimplePokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
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 DexAdditions : JsonDataRegistry<DexAddition> {
override val id = cobblemonResource("dex_additions")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<DexAdditions>()
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.disableHtmlEscaping()
.setPrettyPrinting()
.create()
override val typeToken: TypeToken<DexAddition> = TypeToken.get(DexAddition::class.java)
override val resourcePath = "dex_additions"
override fun reload(data: Map<ResourceLocation, DexAddition>) {
data.entries.forEach { (key, value) ->
Dexes.dexEntryMap[value.dexId]?.let { dexDef ->
if (dexDef is SimplePokedexDef) {
var invalid = false
value.entries.forEach {
if (!DexEntries.entries.containsKey(it)) {
invalid = true
Cobblemon.LOGGER.error("Unable to apply dex addition {} as the entry {} does not exist", key, it)
}
}
if (invalid) {
return@forEach
}
dexDef.appendEntries(value.entries)
} else if (dexDef is AggregatePokedexDef) {
var invalid = false
value.entries.forEach {
if (!Dexes.dexEntryMap.containsKey(it)) {
invalid = true
Cobblemon.LOGGER.error("Unable to apply dex addition {} as the sub-dex {} does not exist", key, it)
}
}
dexDef.appendSubDexIds(value.entries)
}
} ?: Cobblemon.LOGGER.error("Unable to apply dex addition {} as the dex {} does not exist", key, value.dexId)
}
observable.emit(this)
}
override fun sync(player: ServerPlayer) {} // Will be synced as part of the dexes
class DexAddition {
val dexId: ResourceLocation = ResourceLocation.parse("cobblemon:national")
/** Could be PokedexEntry locations or PokedexDef locations depending on what type dex the dexId points to. */
val entries = mutableListOf<ResourceLocation>()
}
}
@@ -1,54 +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.pokedex
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
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 Dexes : JsonDataRegistry<PokedexDef> {
override val id = cobblemonResource("dexes")
override val type = PackType.SERVER_DATA
override val observable = SimpleObservable<Dexes>()
override val gson: Gson = GsonBuilder()
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.registerTypeAdapter(PokedexDef::class.java, CodecBackedAdapter(PokedexDef.CODEC))
.disableHtmlEscaping()
.setPrettyPrinting()
.create()
override val typeToken: TypeToken<PokedexDef> = TypeToken.get(PokedexDef::class.java)
override val resourcePath = "dexes"
//Maps a dex id to its PokedexDef
val dexEntryMap = linkedMapOf<ResourceLocation, PokedexDef>()
override fun reload(data: Map<ResourceLocation, PokedexDef>) {
dexEntryMap.clear()
data.entries.sortedBy { it.value.sortOrder }.forEach { (id, def) -> dexEntryMap[id] = def }
observable.emit(this)
}
override fun sync(player: ServerPlayer) {
PokedexDexSyncPacket(dexEntryMap.values)
}
}
@@ -1,133 +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.pokedex
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.struct.VariableStruct
import com.bedrockk.molang.runtime.value.StringValue
import com.cobblemon.mod.common.pokemon.Gender
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.readEnumConstant
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeEnumConstant
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.Sets
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.network.RegistryFriendlyByteBuf
/**
* A record of a form in the Pokédex. There are a number of tracked properties regarding the form and what
* the dex has seen, and adding to it can be done through [encountered] and [caught].
*
* @author Hiroku
* @since August 23rd, 2024
*/
class FormDexRecord {
companion object {
val CODEC: Codec<FormDexRecord> = RecordCodecBuilder.create { instance ->
instance.group(
ListCodec(Codec.STRING, 0, 3).fieldOf("genders").forGetter { it.genders.map { it.name } },
ListCodec(Codec.STRING, 0, 2).fieldOf("seenShinyStates").forGetter { it.seenShinyStates.toList() },
Codec.STRING.fieldOf("knowledge").forGetter { it.knowledge.name }
).apply(instance) { genders, seenShinyStates, knowledge ->
FormDexRecord().also {
it.genders.addAll(genders.map(Gender::valueOf))
it.seenShinyStates.addAll(seenShinyStates)
it.knowledge = PokedexEntryProgress.valueOf(knowledge)
}
}
}
}
/** The genders that the dex is aware of. */
private val genders: MutableSet<Gender> = mutableSetOf()
/** Shiny states could be shiny or non-shiny - on the off chance they only saw the shiny, they shouldn't know what the normal looks like. */
private val seenShinyStates = mutableSetOf<String>() // consider: radiants in the future (radiants should just be a resource pack tbh)
/** The current awareness of the form that the dex has. */
var knowledge = PokedexEntryProgress.NONE
private set
private val data = VariableStruct() // Could use this for various other properties maybe, consider this a draft
@Transient
lateinit var speciesDexRecord: SpeciesDexRecord
@Transient
lateinit var struct: QueryStruct
fun initialize(speciesDexRecord: SpeciesDexRecord) {
this.speciesDexRecord = speciesDexRecord
struct = QueryStruct(hashMapOf())
.addFunction("data") { data }
.addFunction("knowledge") { StringValue(knowledge.name) }
.addFunction("has_seen_gender") { params -> genders.contains(Gender.valueOf(params.getString(0).uppercase())) }
}
fun encountered(pokemon: Pokemon) {
if (wouldBeDifferent(pokemon, PokedexEntryProgress.ENCOUNTERED)) {
addInformation(pokemon, PokedexEntryProgress.ENCOUNTERED)
}
}
fun caught(pokemon: Pokemon) {
if (wouldBeDifferent(pokemon, PokedexEntryProgress.CAUGHT)) {
addInformation(pokemon, PokedexEntryProgress.CAUGHT)
}
}
fun getGenders(): Set<Gender> = genders
fun hasSeenShinyState(shiny: Boolean): Boolean = seenShinyStates.contains(if (shiny) "shiny" else "normal")
fun getSeenShinyStates(): Set<String> = seenShinyStates
//Used when granting all entries in dex, should figure out better way
fun addAllShinyStatesAndGenders() {
genders.addAll(listOf(Gender.MALE, Gender.FEMALE))
seenShinyStates.addAll(listOf("shiny", "normal"))
}
fun setKnowledgeProgress(newKnowledge: PokedexEntryProgress) {
knowledge = newKnowledge
speciesDexRecord.onFormRecordUpdated(this)
}
private fun addInformation(pokemon: Pokemon, knowledge: PokedexEntryProgress) {
genders.add(pokemon.gender)
seenShinyStates.add(if (pokemon.shiny) "shiny" else "normal")
if (knowledge.ordinal > this.knowledge.ordinal) {
this.knowledge = knowledge
}
speciesDexRecord.addInformation(pokemon, knowledge)
speciesDexRecord.onFormRecordUpdated(this)
}
/** Returns whether the given [Pokemon] and [knowledge] would add new information to the Pokédex.*/
fun wouldBeDifferent(pokemon: Pokemon, knowledge: PokedexEntryProgress): Boolean {
return pokemon.gender !in genders
|| (pokemon.shiny && "shiny" !in seenShinyStates)
|| (!pokemon.shiny && "normal" !in seenShinyStates)
|| knowledge.ordinal > this.knowledge.ordinal
|| speciesDexRecord.wouldBeDifferent(pokemon)
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(genders) { _, it -> buffer.writeEnumConstant(it) }
buffer.writeCollection(seenShinyStates) { _, it -> buffer.writeString(it) }
buffer.writeEnumConstant(knowledge)
}
fun decode(buffer: RegistryFriendlyByteBuf) {
genders.clear()
seenShinyStates.clear()
genders.addAll(buffer.readCollection(Sets::newHashSetWithExpectedSize) { buffer.readEnumConstant(Gender::class.java) })
seenShinyStates.addAll(buffer.readCollection(Sets::newHashSetWithExpectedSize) { buffer.readString() })
knowledge = buffer.readEnumConstant(PokedexEntryProgress::class.java)
}
}
@@ -1,35 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.util.StringRepresentable
/**
* Contains stats about a specific pokemon for putting in the pokedex
*
* @author JPAK, Apion
* @since February 21, 2024
*/
enum class PokedexEntryProgress : StringRepresentable, Comparable<PokedexEntryProgress> {
NONE,
ENCOUNTERED,
CAUGHT;
override fun getSerializedName() = this.name
companion object {
val CODEC: Codec<PokedexEntryProgress> = RecordCodecBuilder.create { instance ->
instance.map ({
PokedexEntryProgress.valueOf(it)
}, PrimitiveCodec.STRING.fieldOf("name").forGetter { it.name })
}
}
}
@@ -1,73 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
import com.cobblemon.mod.common.api.storage.player.InstancedPlayerData
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreType
import com.cobblemon.mod.common.api.storage.player.client.ClientPokedexManager
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
import com.cobblemon.mod.common.pokemon.FormData
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.Species
import com.cobblemon.mod.common.util.getPlayer
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.UUID
import net.minecraft.resources.ResourceLocation
class PokedexManager(
override val uuid: UUID,
override val speciesRecords: MutableMap<ResourceLocation, SpeciesDexRecord>
) : AbstractPokedexManager(), InstancedPlayerData {
fun encounter(pokemon: Pokemon) {
val speciesId = pokemon.species.resourceIdentifier
val formName = pokemon.form.name
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).encountered(pokemon)
}
fun catch(pokemon: Pokemon) {
val speciesId = pokemon.species.resourceIdentifier
val formName = pokemon.form.name
getOrCreateSpeciesRecord(speciesId).getOrCreateFormRecord(formName).caught(pokemon)
}
override fun markDirty() {
}
override fun initialize() {
speciesRecords.entries.forEach { (key, value) -> value.initialize(this, key) }
}
override fun onSpeciesRecordUpdated(speciesDexRecord: SpeciesDexRecord) {
uuid.getPlayer()?.sendPacket(
SetClientPlayerDataPacket(
type = PlayerInstancedDataStoreType.POKEDEX,
playerData = ClientPokedexManager(mutableMapOf(speciesDexRecord.id to speciesDexRecord)),
isIncremental = true
)
)
}
companion object {
val CODEC = RecordCodecBuilder.create<PokedexManager> { instance ->
instance.group(
PrimitiveCodec.STRING.fieldOf("uuid").forGetter { it.uuid.toString() },
Codec.unboundedMap(ResourceLocation.CODEC, SpeciesDexRecord.CODEC).fieldOf("speciesRecords").forGetter { it.speciesRecords }
).apply(instance) { uuid, map ->
//Codec stuff seems to deserialize to an immutable map, so we have to convert it to mutable explicitly
PokedexManager(UUID.fromString(uuid), map.toMutableMap()).also { it.initialize() }
}
}
}
override fun toClientData() = ClientPokedexManager(speciesRecords)
}
@@ -1,32 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import net.minecraft.resources.ResourceLocation
interface PokedexValueCalculator<T> {
fun calculate(dexManager: AbstractPokedexManager, dex: Map<ResourceLocation, PokedexEntry>): T
}
interface GlobalPokedexValueCalculator<T> {
fun calculate(dexManager: AbstractPokedexManager): T
}
object CaughtCount : PokedexValueCalculator<Int> {
override fun calculate(dexManager: AbstractPokedexManager, dex: Map<ResourceLocation, PokedexEntry>): Int {
return dex.entries.map { it.value }.count { dexManager.getKnowledgeForSpecies(it.speciesId) == PokedexEntryProgress.CAUGHT }
}
}
object SeenCount : PokedexValueCalculator<Int> {
override fun calculate(dexManager: AbstractPokedexManager, dex: Map<ResourceLocation, PokedexEntry>): Int {
return dex.entries.map { it.value }.count { dexManager.getKnowledgeForSpecies(it.speciesId) != PokedexEntryProgress.NONE }
}
}
@@ -1,145 +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.pokedex
import com.bedrockk.molang.runtime.struct.QueryStruct
import com.bedrockk.molang.runtime.value.DoubleValue
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import com.google.common.collect.Sets
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import java.util.UUID
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Dex recorded information about a particular Pokémon species. This includes all forms and their information.
* Across all forms there is a single list of known aspects which is generally used to track cosmetic variation
* though technically things like gender and form-motivating aspects will get collected inadvertently.
*
* @author Hiroku
* @since August 23rd, 2024
*/
class SpeciesDexRecord {
companion object {
val CODEC: Codec<SpeciesDexRecord> = RecordCodecBuilder.create { instance ->
instance.group(
ListCodec(PrimitiveCodec.STRING, 0, 512).fieldOf("aspects").forGetter { it.aspects.toList() },
Codec.unboundedMap(Codec.STRING, FormDexRecord.CODEC).fieldOf("formRecords").forGetter { it.formRecords }
).apply(instance) { aspects, formRecords ->
SpeciesDexRecord().also {
it.aspects.addAll(aspects)
it.formRecords.putAll(formRecords)
}
}
}
}
@Transient
lateinit var id: ResourceLocation
private val aspects: MutableSet<String> = mutableSetOf()
private val formRecords: MutableMap<String, FormDexRecord> = mutableMapOf()
@Transient
val struct = QueryStruct(hashMapOf()).addStandardFunctions()
.addFunction("get_form_record") { params ->
val formName = params.getString(0)
formRecords[formName]?.struct ?: QueryStruct(hashMapOf())
}
.addFunction("get_or_create_form_record") { params ->
getOrCreateFormRecord(params.getString(0)).struct
}
.addFunction("add_aspect") { params ->
val aspect = params.getString(0)
aspects.add(aspect)
}
.addFunction("has_knowledge") { params ->
val knowledge = params.getString(0)
DoubleValue(formRecords.values.any { it.knowledge.name.equals(knowledge.toString(), ignoreCase = true) })
}
.addFunction("is_caught") { params ->
DoubleValue(formRecords.values.any { it.knowledge.name.equals("CAUGHT", ignoreCase = true) })
}
// more, also worth moving to something like MoLangFunctions.kt so it's easier to API in more values
@Transient
lateinit var pokedexManager: AbstractPokedexManager
fun initialize(pokedexManager: AbstractPokedexManager, id: ResourceLocation) {
this.id = id
this.pokedexManager = pokedexManager
this.formRecords.forEach { it.value.initialize(this) }
}
fun onFormRecordUpdated(formDexRecord: FormDexRecord) {
pokedexManager.onSpeciesRecordUpdated(this)
}
fun addInformation(pokemon: Pokemon, knowledge: PokedexEntryProgress) {
aspects.addAll(pokemon.aspects)
}
fun addAspects(addedAspects: Set<String>) {
aspects.addAll(addedAspects)
}
/** Returns true if the given Pokémon contains new information. Internal because it's only to be called from [FormDexRecord.wouldBeDifferent]. */
internal fun wouldBeDifferent(pokemon: Pokemon) = pokemon.aspects.any { it !in aspects }
fun getOrCreateFormRecord(formName: String): FormDexRecord {
return formRecords.getOrPut(formName.lowercase()) {
val record = FormDexRecord()
record.initialize(this)
onFormRecordUpdated(record)
// Some more stuff eventually
record
}
}
fun getFormRecord(formName: String): FormDexRecord? {
return formRecords[formName.lowercase()]
}
fun deleteFormRecord(formName: String) {
formRecords.remove(formName)
}
fun getAspects(): Set<String> = this.aspects
fun hasAspect(aspect: String) = aspect in aspects
fun getKnowledge() = formRecords.values.maxOfOrNull { it.knowledge } ?: PokedexEntryProgress.NONE
fun hasAtLeast(knowledge: PokedexEntryProgress) = getKnowledge().ordinal >= knowledge.ordinal
fun hasSeenForm(formName: String) = formRecords.entries.any { it.key.equals(formName, ignoreCase = true) && it.value.knowledge != PokedexEntryProgress.NONE }
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeCollection(aspects) { _, it -> buffer.writeString(it) }
buffer.writeInt(formRecords.size)
for ((formName, formRecord) in formRecords) {
buffer.writeString(formName)
formRecord.encode(buffer)
}
}
fun decode(buffer: RegistryFriendlyByteBuf) {
aspects.clear()
aspects.addAll(buffer.readCollection(Sets::newHashSetWithExpectedSize) { buffer.readString() })
formRecords.clear()
val numForms = buffer.readInt()
for (i in 0 until numForms) {
val formName = buffer.readString()
val formRecord = FormDexRecord()
formRecord.decode(buffer)
formRecords[formName] = formRecord
}
}
}
@@ -1,105 +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.pokedex.def
import com.cobblemon.mod.common.api.pokedex.Dexes
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.writeIdentifier
import com.cobblemon.mod.common.util.writeSizedInt
import com.google.common.collect.Lists
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation
class AggregatePokedexDef(
override val id: ResourceLocation,
) : PokedexDef() {
override val typeId = ID
private val subDexIds = mutableListOf<ResourceLocation>()
var squash = true
private set
fun appendSubDexIds(subDexIds: List<ResourceLocation>) {
this.subDexIds.addAll(subDexIds)
}
override fun getEntries(): List<PokedexEntry> {
if (!squash) {
return Dexes.dexEntryMap.values.filter { it.id in subDexIds }.flatMap { it.getEntries() }
} else {
val speciesToEntry = linkedMapOf<ResourceLocation, PokedexEntry>()
subDexIds.forEach { dexId ->
Dexes.dexEntryMap[dexId]?.getEntries()?.forEach { entry ->
val preExisting = speciesToEntry[entry.speciesId]
if (preExisting != null) {
speciesToEntry[preExisting.speciesId] = preExisting.combinedWith(entry)
} else {
speciesToEntry[entry.speciesId] = entry
}
}
}
return speciesToEntry.values.toList()
}
}
override fun shouldSynchronize(other: PokedexDef) = true
override fun decode(buffer: RegistryFriendlyByteBuf) {
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
val size = buffer.readInt()
for (i in 0 until size) {
subDexIds.add(buffer.readIdentifier())
}
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
buffer.writeInt(subDexIds.size)
subDexIds.forEach {
buffer.writeIdentifier(it)
}
}
companion object {
val ID = cobblemonResource("aggregate_pokedex_def")
val CODEC: MapCodec<AggregatePokedexDef> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
ResourceLocation.CODEC.fieldOf("id").forGetter { it.id },
PrimitiveCodec.INT.fieldOf("sortOrder").forGetter { it.sortOrder },
ResourceLocation.CODEC.listOf().fieldOf("subDexIds").forGetter { it.subDexIds },
PrimitiveCodec.BOOL.fieldOf("squash").forGetter { it.squash }
).apply(instance) { id, sortOrder, entries, squash ->
val result = AggregatePokedexDef(id)
result.sortOrder = sortOrder
result.subDexIds.addAll(entries)
result.squash = squash
result
}
}
val PACKET_CODEC: StreamCodec<ByteBuf, AggregatePokedexDef> = StreamCodec.composite(
ResourceLocation.STREAM_CODEC, AggregatePokedexDef::id,
ByteBufCodecs.INT, AggregatePokedexDef::sortOrder,
ByteBufCodecs.collection(Lists::newArrayListWithCapacity, ResourceLocation.STREAM_CODEC), AggregatePokedexDef::subDexIds
) { id, sortOrder, entries ->
val result = AggregatePokedexDef(id)
result.sortOrder = sortOrder
//result.subDexIds.addAll(entries)
result
}
}
}
@@ -1,56 +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.pokedex.def
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import io.netty.buffer.ByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation
/**
* A class that defines what entries are in a Pokedex
*
* @since August 24, 2024
* @author Apion
*/
abstract class PokedexDef: ClientDataSynchronizer<PokedexDef> {
//The ID used to find the codecs for this "type" of PokedexDef
abstract val typeId: ResourceLocation
//The ID of this dex in the Dexes registry
abstract val id: ResourceLocation
// The sort order for the dex
var sortOrder: Int = 0
abstract fun getEntries(): List<PokedexEntry>
companion object {
val CODEC: Codec<PokedexDef> = ResourceLocation.CODEC.dispatch("type", PokedexDef::typeId, PokedexDef::getCodecById)
val PACKET_CODEC: StreamCodec<ByteBuf, PokedexDef> = ResourceLocation.STREAM_CODEC.dispatch({ it.typeId }, ::getPacketCodecById)
fun getPacketCodecById(id: ResourceLocation): StreamCodec<ByteBuf, out PokedexDef> {
return when (id) {
SimplePokedexDef.ID -> SimplePokedexDef.PACKET_CODEC
AggregatePokedexDef.ID -> AggregatePokedexDef.PACKET_CODEC
else -> throw NotImplementedError("Missing pokedex def packet codec for id: $id")
}
}
fun getCodecById(id: ResourceLocation): MapCodec<out PokedexDef> {
return when (id) {
SimplePokedexDef.ID -> SimplePokedexDef.CODEC
AggregatePokedexDef.ID -> AggregatePokedexDef.CODEC
else -> throw NotImplementedError("Missing pokedex def codec for id: $id")
}
}
}
}
@@ -1,92 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex.def
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.net.IntSize
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readSizedInt
import com.cobblemon.mod.common.util.writeIdentifier
import com.cobblemon.mod.common.util.writeSizedInt
import com.google.common.collect.Lists
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.PrimitiveCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import io.netty.buffer.ByteBuf
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation
/**
* A [PokedexDef] that is just a list of [PokedexEntry]s
*
* @since August 24, 2024
* @author Apion
*/
class SimplePokedexDef(
override val id: ResourceLocation
) : PokedexDef() {
override val typeId = ID
private val entries = mutableListOf<ResourceLocation>()
fun appendEntries(entries: List<ResourceLocation>) {
this.entries.addAll(entries)
}
override fun getEntries() = entries.mapNotNull { DexEntries.entries[it] }
override fun shouldSynchronize(other: PokedexDef) = true
override fun decode(buffer: RegistryFriendlyByteBuf) {
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
val size = buffer.readInt()
for (i in 0 until size) {
entries.add(buffer.readIdentifier())
}
}
override fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
buffer.writeInt(entries.size)
entries.forEach {
buffer.writeIdentifier(it)
}
}
companion object {
val ID = cobblemonResource("simple_pokedex_def")
val CODEC: MapCodec<SimplePokedexDef> = RecordCodecBuilder.mapCodec { instance ->
instance.group(
ResourceLocation.CODEC.fieldOf("id").forGetter { it.id },
PrimitiveCodec.INT.fieldOf("sortOrder").forGetter { it.sortOrder },
ResourceLocation.CODEC.listOf().fieldOf("entries").forGetter { it.entries }
).apply(instance) { id, sortOrder, entries ->
val result = SimplePokedexDef(id)
result.sortOrder = sortOrder
result.entries.addAll(entries)
result
}
}
val PACKET_CODEC: StreamCodec<ByteBuf, SimplePokedexDef> = StreamCodec.composite(
ResourceLocation.STREAM_CODEC, SimplePokedexDef::id,
ByteBufCodecs.INT, SimplePokedexDef::sortOrder,
ByteBufCodecs.collection(Lists::newArrayListWithCapacity, ResourceLocation.STREAM_CODEC), SimplePokedexDef::entries
) { id, sortOrder, entries ->
val result = SimplePokedexDef(id)
result.sortOrder = sortOrder
result.entries.addAll(entries)
result
}
}
}
@@ -1,60 +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.pokedex.entry
import com.cobblemon.mod.common.api.data.JsonDataRegistry
import com.cobblemon.mod.common.api.molang.ExpressionLike
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.net.messages.client.data.DexEntrySyncPacket
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
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 DexEntries : JsonDataRegistry<PokedexEntry> {
override val id = cobblemonResource("dex_entries")
override val type = PackType.SERVER_DATA
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<PokedexEntry> = TypeToken.get(PokedexEntry::class.java)
override val resourcePath = "dex_entries"
val entries = mutableMapOf<ResourceLocation, PokedexEntry>()
override fun reload(data: Map<ResourceLocation, PokedexEntry>) {
data.forEach { _, entry ->
entries[entry.id] = entry
if (entry.forms.isEmpty()) {
entry.forms.add(PokedexForm())
}
entry.forms.forEach {
if (it.unlockForms.isEmpty()) {
it.unlockForms = mutableSetOf(it.displayForm)
}
}
}
observable.emit(this)
}
override val observable = SimpleObservable<DexEntries>()
override fun sync(player: ServerPlayer) {
DexEntrySyncPacket(entries.values)
}
}
@@ -1,58 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex.entry
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.reactive.SimpleObservable
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
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 DexEntryAdditions : JsonDataRegistry<DexEntryAdditions.DexEntryAddition> {
override val id = cobblemonResource("dex_entry_additions")
override val type = PackType.SERVER_DATA
override val gson: Gson = GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
.create()
override val typeToken: TypeToken<DexEntryAddition> = TypeToken.get(DexEntryAddition::class.java)
override val resourcePath = "dex_entry_additions"
override val observable = SimpleObservable<DexEntryAdditions>()
val entries = mutableListOf<PokedexEntry>()
override fun reload(data: Map<ResourceLocation, DexEntryAddition>) {
data.entries.forEach { (key, addition) ->
DexEntries.entries[addition.entryId]?.add(addition)
?: return@forEach Cobblemon.LOGGER.error("Unable to find dex entry {} to add to from dex entry addition {}", addition.entryId, key) // Skip if the entry doesn't exist
}
observable.emit(this)
}
override fun sync(player: ServerPlayer) {} // It'd be synced as part of the DexEntries
class DexEntryAddition {
val entryId: ResourceLocation = cobblemonResource("some_addition")
val forms: List<PokedexForm> = emptyList()
val variations: List<PokedexCosmeticVariation> = emptyList()
}
}
@@ -1,47 +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.pokedex.entry
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
/**
* Controls a toggle in the Pokédex GUI that iterates through some set of aspects that
* presumably match a species feature or other aspect provider on the server side. This is
* used to let the player check out the different variations of a Pokémon.
*
* @author Hiroku
* @since August 25th, 2025
*/
class PokedexCosmeticVariation {
var displayName: String = "cobblemon.pokedex.variation.cosmetic"
var icon: ResourceLocation = cobblemonResource("textures/gui/pokedex/variation/cosmetic.png")
var aspects: Set<String> = emptySet()
fun clone() = PokedexCosmeticVariation().also {
it.displayName = displayName
it.icon = icon
it.aspects = aspects.toSet()
}
fun encode(buffer: RegistryFriendlyByteBuf) {
buffer.writeString(displayName)
buffer.writeResourceLocation(icon)
buffer.writeCollection(aspects) { _, aspect -> buffer.writeString(aspect) }
}
fun decode(buffer: RegistryFriendlyByteBuf) {
displayName = buffer.readString()
icon = buffer.readResourceLocation()
aspects = buffer.readList { buffer.readString() }.toSet()
}
}
@@ -1,105 +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.pokedex.entry
import com.cobblemon.mod.common.util.readIdentifier
import com.cobblemon.mod.common.util.readString
import com.cobblemon.mod.common.util.writeIdentifier
import com.cobblemon.mod.common.util.writeString
import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.resources.ResourceLocation
class PokedexEntry(
val id: ResourceLocation,
val speciesId: ResourceLocation,
val displayAspects: MutableSet<String> = mutableSetOf(),
val conditionAspects: MutableSet<String> = mutableSetOf(),
val forms: MutableList<PokedexForm> = mutableListOf(),
val variations: MutableList<PokedexCosmeticVariation> = mutableListOf()
) {
fun clone() = PokedexEntry(
id,
speciesId,
displayAspects,
conditionAspects,
forms.map { it.clone() }.toMutableList(),
variations.map { it.clone() }.toMutableList()
)
fun combinedWith(other: PokedexEntry): PokedexEntry {
val copy = clone()
other.forms.forEach { form ->
if (form.displayForm !in copy.forms.map { it.displayForm }) {
copy.forms.add(form.clone())
} else {
copy.forms.find { it.displayForm == form.displayForm }!!.unlockForms.addAll(form.unlockForms)
}
}
other.variations.forEach { variation ->
if (variation.displayName !in copy.variations.map { it.displayName }) {
copy.variations.add(variation.clone())
}
}
return copy
}
fun add(addition: DexEntryAdditions.DexEntryAddition) {
addition.forms.forEach { form ->
if (form.displayForm !in forms.map { it.displayForm }) {
forms.add(form)
} else {
forms.find { it.displayForm == form.displayForm }!!.unlockForms.addAll(form.unlockForms)
}
}
addition.variations.forEach { variation ->
if (variation.displayName !in variations.map { it.displayName }) {
variations.add(variation)
}
}
}
fun encode(buf: RegistryFriendlyByteBuf) {
buf.writeIdentifier(id)
buf.writeIdentifier(speciesId)
buf.writeCollection(displayAspects) { _, aspect -> buf.writeString(aspect) }
buf.writeCollection(conditionAspects) { _, aspect -> buf.writeString(aspect) }
buf.writeCollection(forms) { _, form ->
buf.writeString(form.displayForm)
buf.writeCollection(form.unlockForms) { _, unlockForm -> buf.writeString(unlockForm) }
}
buf.writeCollection(variations) { _, variation -> variation.encode(buf) }
}
companion object {
fun decode(buffer: RegistryFriendlyByteBuf): PokedexEntry {
val id = buffer.readIdentifier()
val entryId = buffer.readIdentifier()
val displayAspects = buffer.readList { buffer.readString() }.toMutableSet()
val conditionAspects = buffer.readList { buffer.readString() }.toMutableSet()
val forms = buffer.readList {
val form = PokedexForm()
form.displayForm = buffer.readString()
form.unlockForms.addAll(buffer.readList { buffer.readString() })
form
}
val variations = buffer.readList { PokedexCosmeticVariation().also { it.decode(buffer) } }
return PokedexEntry(id, entryId, displayAspects, conditionAspects, forms, variations)
}
}
}
class PokedexForm {
var displayForm: String = "Normal"
var unlockForms: MutableSet<String> = mutableSetOf()
fun clone() = PokedexForm().also {
it.displayForm = displayForm
it.unlockForms.addAll(unlockForms)
}
}
@@ -1,29 +0,0 @@
/*
* Copyright (C) 2023 Cobblemon Contributors
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.cobblemon.mod.common.api.pokedex.filter
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
/**
* A Pokedex [EntryFilter] that filters out entries that do not contain the current search.
*
* @author whatsy
* @since September 4th, 2024
* @param searchString The string to use when checking.
*/
class SearchFilter(val searchString: String) : EntryFilter() {
override fun test(entry: PokedexEntry): Boolean {
if (searchString == "") return true
val species = PokemonSpecies.getByIdentifier(entry.speciesId) ?: return false
return species.translatedName.string.contains(searchString.trim(), true)
}
}
@@ -164,20 +164,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
*/
fun count() = this.speciesByIdentifier.size
/**
* Gets a map of dex numbers to species.
*
* @return The dex numbers map to species.
*/
fun getSpeciesInNamespace(namespace: String = Cobblemon.MODID): MutableMap<Int, Species> = speciesByDex.row(namespace)
/**
* Get a list of loaded namespaces.
*
* @return The list of loaded namespaces.
*/
fun getNamespaces() = speciesByDex.rowKeySet().toList()
/**
* Picks a random [Species].
*
@@ -8,7 +8,7 @@
package com.cobblemon.mod.common.api.pokemon.evolution
import com.cobblemon.mod.common.Cobblemon.playerDataManager
import com.cobblemon.mod.common.Cobblemon.playerData
import com.cobblemon.mod.common.CobblemonItems
import com.cobblemon.mod.common.CobblemonSounds
import com.cobblemon.mod.common.advancement.CobblemonCriteria
@@ -20,17 +20,18 @@ import com.cobblemon.mod.common.api.moves.BenchedMove
import com.cobblemon.mod.common.api.moves.MoveTemplate
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
import com.cobblemon.mod.common.api.pokemon.evolution.requirement.EvolutionRequirement
import com.cobblemon.mod.common.api.scheduling.afterOnServer
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
import com.cobblemon.mod.common.item.PokeBallItem
import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimationPacket
import com.cobblemon.mod.common.pokemon.Pokemon
import com.cobblemon.mod.common.pokemon.activestate.ShoulderedState
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.LevelUpEvolution
import com.cobblemon.mod.common.pokemon.evolution.variants.TradeEvolution
import com.cobblemon.mod.common.util.cobblemonResource
import com.cobblemon.mod.common.util.lang
import com.cobblemon.mod.common.util.party
import net.minecraft.world.entity.Entity
import net.minecraft.world.item.ItemStack
/**
@@ -121,7 +122,7 @@ interface Evolution : EvolutionLike {
if (pokeballStack == null) return false
}
// If the player has at least one empty spot in their party.
owner.party().getFirstAvailablePosition() ?: return false
val emptySlot = owner.party().getFirstAvailablePosition() ?: return false
// Add shed Pokemon to player's party
val shedPokemon = pokemon.clone()
@@ -129,7 +130,7 @@ interface Evolution : EvolutionLike {
innerShedder.apply(shedPokemon)
shedPokemon.caughtBall = ((pokeballStack?.item ?: CobblemonItems.POKE_BALL) as PokeBallItem).pokeBall
pokemon.storeCoordinates.get()?.store?.add(shedPokemon)
CobblemonCriteria.EVOLVE_POKEMON.trigger(owner, EvolvePokemonContext(pokemon.preEvolution!!.species.resourceIdentifier, shedPokemon.species.resourceIdentifier, playerDataManager.getGenericData(owner).advancementData.totalEvolvedCount))
CobblemonCriteria.EVOLVE_POKEMON.trigger(owner, EvolvePokemonContext(pokemon.preEvolution!!.species.resourceIdentifier, shedPokemon.species.resourceIdentifier, playerData.get(owner).advancementData.totalEvolvedCount))
// Consume one of the balls
pokeballStack?.shrink(1)
@@ -144,7 +145,7 @@ interface Evolution : EvolutionLike {
*/
fun forceEvolve(pokemon: Pokemon) {
// This is a switch to enable/disable the evolution effect while we get particles improved
val useEvolutionEffect = true
val useEvolutionEffect = false
if (pokemon.state is ShoulderedState) {
pokemon.tryRecallWithAnimation()
@@ -154,31 +155,34 @@ interface Evolution : EvolutionLike {
if (pokemonEntity == null || !useEvolutionEffect) {
evolutionMethod(pokemon)
} else {
pokemonEntity.busyLocks.add("evolving")
pokemonEntity.navigation.stop()
pokemonEntity.after(1F) {
evolutionAnimation(pokemonEntity)
pokemonEntity.evolutionEntity = pokemon.getOwnerPlayer()?.let { GenericBedrockEntity(world = it.level()) }
val evolutionEntity = pokemon.entity!!.evolutionEntity
evolutionEntity?.apply {
category = cobblemonResource("evolution")
colliderHeight = pokemonEntity.bbHeight
colliderWidth = pokemonEntity.bbWidth
scale = pokemonEntity.ageScale
syncAge = true // Otherwise particle animation will be starting from zero even if you come along partway through
setPos(pokemonEntity.x, pokemonEntity.y, pokemonEntity.z)
}
pokemonEntity.after(11.2F) {
evolutionMethod(pokemon)
}
pokemonEntity.after( seconds = 12F ) {
cryAnimation(pokemonEntity)
pokemonEntity.busyLocks.remove("evolving")
pokemon.getOwnerPlayer()?.level()?.addFreshEntity(evolutionEntity)
afterOnServer(seconds = 9F) {
if (!pokemonEntity.isRemoved) {
evolutionMethod(pokemon)
afterOnServer(seconds = 1.5F) { pokemonEntity.cry() }
afterOnServer(seconds = 3F) {
if (evolutionEntity != null) {
evolutionEntity.kill()
if (!pokemonEntity.isRemoved) {
pokemonEntity.evolutionEntity = null
}
}
}
}
}
}
}
private fun evolutionAnimation(pokemon: Entity) {
val playPoseableAnimationPacket = PlayPosableAnimationPacket(pokemon.id, setOf("q.bedrock_stateful('evolution', 'evolution', 'endures_primary_animations');"), emptySet())
playPoseableAnimationPacket.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, 128.0, pokemon.level().dimension())
}
private fun cryAnimation(pokemon: Entity) {
val playPoseableAnimationPacket = PlayPosableAnimationPacket(pokemon.id, setOf("cry"), emptySet())
playPoseableAnimationPacket.sendToPlayersAround(pokemon.x, pokemon.y, pokemon.z, 128.0, pokemon.level().dimension())
}
fun evolutionMethod(pokemon: Pokemon) {
this.result.apply(pokemon)
this.learnableMoves.forEach { move ->
@@ -190,9 +194,8 @@ interface Evolution : EvolutionLike {
pokemon.getOwnerPlayer()?.sendSystemMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
}
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLUTION_UI, 1F, 1F)
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, 1F, 1F)
this.shed(pokemon)
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
}
@@ -1,36 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.CollectionSubscription
interface MutableObservableCollection<T, C : Collection<T>> :
ObservableCollection<T, C>,
MutableCollection<T> {
fun subscribe(
priority: Priority = Priority.NORMAL,
anyChangeHandler: (Pair<C, T>) -> Unit,
additionHandler: ((Pair<C, T>) -> Unit)? = null,
removalHandler: ((Pair<C, T>) -> Unit)? = null,
): CollectionSubscription<T, C>
override fun add(element: T): Boolean
fun addIf(element: T, predicate: (C) -> Boolean): Boolean
override fun remove(element: T): Boolean
fun removeIf(predicate: (T) -> Boolean): Boolean
override fun addAll(elements: Collection<T>): Boolean
override fun retainAll(elements: Collection<T>): Boolean
override fun removeAll(elements: Collection<T>): Boolean
override fun iterator(): MutableIterator<T>
override fun clear()
fun mutableCopy(): MutableObservableCollection<T, C>
}
@@ -1,8 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections
interface MutableObservableCollectionIterator<T, C : Collection<T>, I : Iterator<T>> :
ObservableCollectionIterator<T, I>,
MutableIterator<T> {
override fun remove()
}
@@ -1,32 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
interface ObservableCollection<T, C : Collection<T>> :
Collection<T>,
Observable<Pair<C, T>> {
val elements: C
override val size: Int
override fun subscribe(
priority: Priority,
handler: (Pair<C, T>) -> Unit,
): ObservableSubscription<Pair<C, T>>
override fun unsubscribe(subscription: ObservableSubscription<Pair<C, T>>)
override fun isEmpty(): Boolean
fun isNotEmpty(): Boolean
override fun contains(element: T): Boolean
override fun containsAll(elements: Collection<T>): Boolean
override operator fun iterator(): Iterator<T>
fun copy(): ObservableCollection<T, C>
}
@@ -1,7 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections
interface ObservableCollectionIterator<T, I : Iterator<T>> : Iterator<T> {
override fun hasNext(): Boolean
override fun next(): T
}
@@ -1,35 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections
import com.cobblemon.mod.common.api.reactive.Observable
/**
* This attempts to cast [this] value to [Observable].
*
* @return An observable set with [this] as an [Observable] or an empty set.
*/
fun <T> T.getElementObservables(): Set<Observable<*>> {
this.tryGetObservable()?.let { return setOf(it) }
return emptySet()
}
/**
* This attempts to cast [this] value to [Observable].
*
* @return This value as an [Observable] or null.
*/
fun <T> T.tryGetObservable(): Observable<*>? = if (this is Observable<*>) this else null
fun <T> MutableIterator<T>.removeIf(predicate: (T) -> Boolean): Boolean {
var removed = false
this.forEach { element ->
if (predicate(element)) {
this.remove()
if (!removed) {
removed = true
}
}
}
return removed
}
@@ -1,242 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollection
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.IndexedListSubscription
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.ListSubscription
import com.cobblemon.mod.common.api.reactive.collections.removeIf
open class MutableObservableList<T>(
list: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) : MutableObservableCollection<T, List<T>>,
ObservableList<T>(list, elementHandler),
MutableList<T> {
private val additionObservable = SimpleObservable<Pair<List<T>, T>>()
private val removalObservable = SimpleObservable<Pair<List<T>, T>>()
private val setObservable = SimpleObservable<Pair<List<T>, Pair<T, T>>>()
private val swapObservable = SimpleObservable<Pair<List<T>, Pair<T, T>>>()
private val additionObservableIndexed = SimpleObservable<Triple<List<T>, T, Int>>()
private val removalObservableIndexed = SimpleObservable<Triple<List<T>, T, Int>>()
private val setObservableIndexed = SimpleObservable<Triple<List<T>, Pair<T, T>, Int>>()
private val swapObservableIndexed = SimpleObservable<Triple<List<T>, Pair<T, T>, Pair<Int, Int>>>()
override fun subscribe(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
): ListSubscription<T> {
return ListSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
): ListSubscription<T> {
elements.forEach { anyChangeHandler(this to it) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler)
}
fun subscribe(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
setHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
swapHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
): ListSubscription<T> {
@Suppress("DuplicatedCode")
return ListSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
set = setHandler?.let { setObservable.subscribe(priority, it) },
swap = swapHandler?.let { swapObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
setHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
swapHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
): ListSubscription<T> {
elements.forEach { anyChangeHandler(this to it) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler, setHandler, swapHandler)
}
fun subscribeIndexed(
priority: Priority,
additionHandler: ((Triple<List<T>, T, Int>) -> Unit)?,
removalHandler: ((Triple<List<T>, T, Int>) -> Unit)?,
setHandler: ((Triple<List<T>, Pair<T, T>, Int>) -> Unit)?,
swapHandler: ((Triple<List<T>, Pair<T, T>, Pair<Int, Int>>) -> Unit)?,
): IndexedListSubscription<T> {
return IndexedListSubscription(
addition = additionHandler?.let { additionObservableIndexed.subscribe(priority, it) },
removal = removalHandler?.let { removalObservableIndexed.subscribe(priority, it) },
set = setHandler?.let { setObservableIndexed.subscribe(priority, it) },
swap = swapHandler?.let { swapObservableIndexed.subscribe(priority, it) },
)
}
/**
* @return `true` after handling [register] & all subscriptions to [additionObservable],
* [additionObservableIndexed], & [ObservableList.emitAnyChange].
*/
private fun emitAddition(element: T, index: Int): Boolean {
register(element)
additionObservable.emit(list to element)
additionObservableIndexed.emit(Triple(list, element, index))
return emitAnyChange(element)
}
/**
* @return `true` after handling [unregister] & all subscriptions to [removalObservable],
* [removalObservableIndexed] & [ObservableList.emitAnyChange].
*/
private fun emitRemoval(element: T, index: Int): Boolean {
unregister(element)
removalObservable.emit(list to element)
removalObservableIndexed.emit(Triple(list, element, index))
return emitAnyChange(element)
}
/**
* @return `true` after handling [register], [unregister] & all subscriptions to [setObservable],
* [setObservableIndexed], & [ObservableList.emitAnyChange].
*/
private fun emitSet(elements: Pair<T, T>, index: Int): Boolean {
register(elements.first)
unregister(elements.second)
setObservable.emit(list to elements)
setObservableIndexed.emit(Triple(list, elements, index))
emitAnyChange(elements.first)
emitAnyChange(elements.second)
return true
}
/**
* @return `true` after handling all subscriptions to [swapObservable],
* [swapObservableIndexed], & [ObservableList.emitAnyChange].
*/
private fun emitSwap(elements: Pair<T, T>, indices: Pair<Int, Int>): Boolean {
swapObservable.emit(list to elements)
swapObservableIndexed.emit(Triple(list, elements, indices))
emitAnyChange(elements.first)
emitAnyChange(elements.second)
return true
}
override operator fun iterator() = MutableObservableListIterator(this)
override fun listIterator() = MutableObservableListIterator(this)
override fun listIterator(index: Int) = MutableObservableListIterator(this, index)
override fun subList(fromIndex: Int, toIndex: Int): MutableObservableSubList<T> {
return MutableObservableSubList(this, fromIndex, toIndex, elementHandler)
}
override fun addIf(element: T, predicate: (List<T>) -> Boolean): Boolean {
return if (predicate(list)) add(element) else false
}
override fun add(element: T): Boolean {
list.add(element)
return emitAddition(element, lastIndex)
}
fun addAtIf(index: Int, element: T, predicate: (List<T>) -> Boolean): Boolean {
return if (predicate(list)) {
add(index, element)
true
} else {
false
}
}
override fun add(index: Int, element: T) {
list.add(index, element)
emitAddition(element, index)
}
fun setIf(index: Int, element: T, predicate: (T) -> Boolean): T? {
return if (predicate(list[index])) set(index, element) else null
}
override operator fun set(index: Int, element: T): T {
return list.set(index, element).also { emitSet(element to it, index) }
}
fun swapIf(indexOne: Int, indexTwo: Int, predicate: () -> Boolean): Boolean {
return predicate().also { if (it) swap(indexOne, indexTwo) }
}
fun swap(indexOne: Int, indexTwo: Int) {
val one = list[indexOne]
val two = list.set(indexTwo, one)
list[indexOne] = two
emitSwap(one to two, indexOne to indexTwo)
}
override fun removeIf(predicate: (T) -> Boolean): Boolean = iterator().removeIf(predicate)
override fun remove(element: T): Boolean {
val indexOf = list.indexOfFirst { it == element }
if (indexOf == -1) {
return false
}
list.removeAt(indexOf)
return emitRemoval(element, indexOf)
}
override fun removeAt(index: Int): T {
val element = list.removeAt(index)
emitRemoval(element, index)
return element
}
fun removeAtIf(index: Int, predicate: (T) -> Boolean): T? {
val element = list[index]
if (predicate(element)) {
list.removeAt(index)
emitRemoval(element, index)
}
return element
}
override fun addAll(elements: Collection<T>): Boolean {
elements.forEach { add(it) }
return true
}
override fun addAll(index: Int, elements: Collection<T>): Boolean {
var currentIndex = index
elements.forEach { add(currentIndex++, it) }
return true
}
override fun removeAll(elements: Collection<T>):Boolean = removeIf { elements.contains(it) }
override fun retainAll(elements: Collection<T>):Boolean = removeIf { !elements.contains(it) }
override fun clear() {
while (isNotEmpty()) {
removeAt(0)
}
}
}
@@ -1,60 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
// the name is not quite long enough yet...
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollectionIterator
open class MutableObservableListIterator<T>(
observableList: MutableObservableList<T>,
index: Int = 0,
) : MutableObservableCollectionIterator<T, Set<T>, ListIterator<T>>,
ObservableListIterator<T>(observableList, index),
MutableListIterator<T> {
private val mutableList: MutableObservableList<T> = observableList
private var illegalSetOrRemoveState: Boolean? = null
set (value) { if (field != value) field = value }
override fun next(): T {
illegalSetOrRemoveState = false
return super.next()
}
override fun previous(): T {
illegalSetOrRemoveState = false
return super.previous()
}
override fun remove() {
throwIfIllegalState("remove")
mutableList.removeAt(--index)
illegalSetOrRemoveState = true
}
override fun set(element: T) {
throwIfIllegalState("set")
mutableList[index -1] = element
}
override fun add(element: T) {
when {
mutableList.isEmpty() -> mutableList.add(element).run { index = 0 }
index < mutableList.size -> mutableList.add(index++, element)
else -> mutableList.add(element).run { index++ }
}
illegalSetOrRemoveState = true
}
private fun throwIfIllegalState(function: String) {
if (illegalSetOrRemoveState == null) {
throw IllegalStateException(
"Observable List iterator '$function' was called before 'next' or 'previous'."
)
} else if (illegalSetOrRemoveState == true) {
throw IllegalStateException(
"Observable List iterator '$function' was called, " +
"but 'remove' or 'add' was already called this iteration."
)
}
}
}
@@ -1,317 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollection
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.ListSubscription
import com.cobblemon.mod.common.api.reactive.collections.removeIf
class MutableObservableSubList<T>(
private val parentList: MutableObservableList<T>,
private val fromIndex: Int,
private val toIndex: Int,
elementHandler: (T) -> Set<Observable<*>>,
) : MutableObservableCollection<T, List<T>>,
ObservableSubList<T>(parentList, fromIndex, toIndex, elementHandler),
MutableList<T> {
private val additionObservable = SimpleObservable<Pair<List<T>, T>>()
private val removalObservable = SimpleObservable<Pair<List<T>, T>>()
private val setObservable = SimpleObservable<Pair<List<T>, Pair<T, T>>>()
private val swapObservable = SimpleObservable<Pair<List<T>, Pair<T, T>>>()
override val elements: List<T>
get() = when {
isEmpty() -> emptyList()
parentList.size < maxSize -> parentList.elements.subList(fromIndex, parentList.size)
else -> parentList.elements.subList(fromIndex, currentToIndex)
}
private val maxLastIndex: Int = toIndex - 1
private val maxSize: Int = toIndex - fromIndex
override val size: Int get() = when {
isEmpty() -> 0
parentList.size < toIndex -> parentList.lastIndex - fromIndex
else -> maxLastIndex
}
/** This is the last index in the sublist window, or -1 if the window is empty. */
val currentLastIndex: Int get() = size - 1
/** This is either [fromIndex] or -1 if the sublist window is empty. */
val currentFromIndex: Int get() = if (isEmpty()) -1 else fromIndex
/**
* If [parentList] size > [toIndex] this is the toIndex,
* if the parentList size is > [fromIndex] this is the parentList size,
* or this is the [currentFromIndex].
*/
private val currentToIndex: Int
get() = when {
toIndex < parentList.size -> toIndex
fromIndex < parentList.size -> parentList.size
else -> currentFromIndex
}
private val currentLastIndexInParent: Int
get() = when {
isEmpty() -> fromIndex
parentList.lastIndex < toIndex -> parentList.lastIndex
else -> maxLastIndex
}
init {
parentList.subscribeIndexed(
priority = Priority.NORMAL,
additionHandler = { (_, element, index) -> emitAddition(element, index) },
removalHandler = { (_, element, index) -> emitRemoval(element, index) },
setHandler = { (_, elements, index) -> emitSet(elements, index) },
swapHandler = { (_, element, index) -> emitSwap(element, index) },
)
}
override fun subscribe(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
): ListSubscription<T> {
return ListSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
): ListSubscription<T> {
elements.forEach { anyChangeHandler(this to it) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler)
}
fun subscribe(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
setHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
swapHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
): ListSubscription<T> {
@Suppress("DuplicatedCode")
return ListSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
set = setHandler?.let { setObservable.subscribe(priority, it) },
swap = swapHandler?.let { swapObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority,
anyChangeHandler: (Pair<List<T>, T>) -> Unit,
additionHandler: ((Pair<List<T>, T>) -> Unit)?,
removalHandler: ((Pair<List<T>, T>) -> Unit)?,
setHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
swapHandler: ((Pair<List<T>, Pair<T, T>>) -> Unit)?,
): ListSubscription<T> {
elements.forEach { anyChangeHandler(this to it) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler, setHandler, swapHandler)
}
private fun emitAddition(element: T, index: Int) {
if (index >= toIndex) {
return
}
val elements = this.elements
if (index >= fromIndex) {
handleAddition(elements, element)
} else if(parentList.lastIndex >= fromIndex) {
handleAddition(elements, parentList[fromIndex])
}
if (parentList.size > toIndex) {
handleRemoval(elements, parentList[toIndex])
}
}
private fun emitRemoval(element: T, index: Int) {
if (index >= toIndex) {
return
}
val elements = this.elements
if (index >= fromIndex) {
handleRemoval(elements, element)
} else if(parentList.lastIndex >= fromIndex - 1) {
handleRemoval(elements, parentList[fromIndex - 1])
}
if (currentLastIndexInParent >= toIndex - 1) {
handleAddition(elements, parentList[toIndex - 1])
}
}
private fun emitSet(elementPair: Pair<T, T>, index: Int) {
if (!index.isInParentRelativeWindow()) {
return
}
register(elementPair.first)
unregister(elementPair.second)
setObservable.emit(elements to elementPair)
emitAnyChange(elementPair.first)
emitAnyChange(elementPair.second)
}
private fun emitSwap(elementPair: Pair<T, T>, indices: Pair<Int, Int>) {
val firstInWindow = indices.first.isInParentRelativeWindow()
val secondInWindow = indices.second.isInParentRelativeWindow()
when {
firstInWindow && !secondInWindow -> {
val elements = this.elements
handleRemoval(elements, elementPair.first)
handleAddition(elements, elementPair.second)
}
!firstInWindow && secondInWindow -> {
val elements = this.elements
handleAddition(elements, elementPair.first)
handleRemoval(elements, elementPair.second)
}
firstInWindow && secondInWindow -> {
swapObservable.emit(elements to elementPair)
emitAnyChange(elementPair.first)
elementPair.second?.let { emitAnyChange(it) }
}
}
}
private fun handleAddition(elements: List<T>, element: T) {
register(element)
additionObservable.emit(elements to element)
emitAnyChange(element)
}
private fun handleRemoval(elements: List<T>, element: T) {
unregister(element)
removalObservable.emit(elements to element)
emitAnyChange(element)
}
override operator fun iterator() = MutableObservableSubListIterator(this)
override fun listIterator() = MutableObservableSubListIterator(this)
override fun listIterator(index: Int) = MutableObservableSubListIterator(this, index)
override fun subList(fromIndex: Int, toIndex: Int): MutableObservableSubList<T> {
return parentList.subList(parentIndex(fromIndex), parentIndex(toIndex))
}
fun swapIf(indexOne: Int, indexTwo: Int, predicate: () -> Boolean): Boolean {
return predicate().also { if (it) swap(indexOne, indexTwo) }
}
fun swap(indexOne: Int, indexTwo: Int) {
val parentIndexOne = parentIndex(indexOne)
val one = parentList[parentIndexOne]
val two = parentList.set(parentIndex(indexTwo), one)
parentList[parentIndexOne] = two
}
override fun addIf(element: T, predicate: (List<T>) -> Boolean): Boolean {
return if (predicate(this)) add(element) else false
}
override fun add(element: T): Boolean {
return if (parentList.lastIndex < toIndex) {
parentList.add(element)
} else {
parentList.add(toIndex, element)
true
}
}
fun addAtIf(index: Int, element: T, predicate: (List<T>) -> Boolean): Boolean {
return if (predicate(this)) {
add(index, element)
true
} else {
false
}
}
override fun add(index: Int, element: T) {
parentList.add(parentIndex(index), element)
}
override operator fun set(index: Int, element: T): T {
return parentList.set(parentIndex(index), element)
}
override fun removeIf(predicate: (T) -> Boolean): Boolean = iterator().removeIf(predicate)
override fun remove(element: T): Boolean {
for (i in fromIndex until parentList.size) {
val current = elements[i]
if (current == element) {
parentList.removeAt(i)
return true
}
}
return false
}
override fun removeAt(index: Int): T = parentList.removeAt(parentIndex(index))
override fun addAll(elements: Collection<T>): Boolean {
val parentIndex = if (currentLastIndex > -1) currentLastIndex + fromIndex else fromIndex
return if (parentIndex > parentList.lastIndex) {
parentList.addAll(elements)
} else {
parentList.addAll(parentIndex, elements)
}
}
override fun addAll(index: Int, elements: Collection<T>): Boolean {
return parentList.addAll(parentIndex(index), elements)
}
override fun removeAll(elements: Collection<T>): Boolean {
return iterator().removeIf { elements.contains(it) }
}
override fun retainAll(elements: Collection<T>): Boolean {
return iterator().removeIf { !elements.contains(it) }
}
/**
* This implementation will remove all elements from the window dynamically. If an element
* is removed & an element shifts into the sublist window that meets the predicate, the
* new element will also be removed.
*
* Note: The other iterators including the ObservableSubListIterator will only operate on
* the window provided before the iteration, even when the iterator is mutable.
*/
private fun removeAllIf(predicate: (T) -> Boolean): Boolean {
if (isEmpty()) {
return false
}
var mutated = false
val outOfParentBounds: (Int) -> Boolean = { it == parentList.size }
for (i in fromIndex until currentToIndex) {
if (outOfParentBounds(i)) {
return mutated
}
while (predicate(parentList[i])) {
parentList.removeAt(i).also { if (!mutated) mutated = true }
if (outOfParentBounds(i)) {
return true
}
}
}
return mutated
}
override fun clear() {
if (isNotEmpty()) {
iterator().removeIf { true }
}
}
}
@@ -1,63 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
// the name is not quite long enough yet...
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollectionIterator
open class MutableObservableSubListIterator<T>(
subList: MutableObservableSubList<T>,
index: Int = 0,
) : MutableObservableCollectionIterator<T, List<T>, ListIterator<T>>,
ObservableSubListIterator<T>(subList, index),
MutableListIterator<T> {
private val mutableSubList: MutableObservableSubList<T> = subList
private var illegalSetOrRemoveState: Boolean? = null
set (value) { if (field != value) field = value }
override fun next(): T {
illegalSetOrRemoveState = false
return super.next()
}
override fun previous(): T {
illegalSetOrRemoveState = false
return super.previous()
}
override fun remove() {
throwIfIllegalState("remove")
mutableSubList.removeAt(--index)
illegalSetOrRemoveState = true
}
override fun set(element: T) {
throwIfIllegalState("set")
mutableSubList[index -1] = element
}
override fun add(element: T) {
when {
subList.isEmpty() -> {
mutableSubList.add(element)
index = mutableSubList.currentFromIndex
}
index < mutableSubList.currentLastIndex -> mutableSubList.add(index++, element)
else -> mutableSubList.add(element).run { index++ }
}
illegalSetOrRemoveState = true
}
private fun throwIfIllegalState(function: String) {
if (illegalSetOrRemoveState == null) {
throw IllegalStateException(
"Observable Sub List iterator '$function' was called before 'next' or 'previous'."
)
} else if (illegalSetOrRemoveState == true) {
throw IllegalStateException(
"Observable Sub List iterator '$function' was called, " +
"but 'remove' or 'add' was already called this iteration."
)
}
}
}
@@ -1,93 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.PrioritizedList
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.collections.ObservableCollection
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
open class ObservableList<T>(
list: Collection<T>,
protected val elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) : ObservableCollection<T, List<T>>,
List<T>,
Observable<Pair<List<T>, T>> {
protected val list: MutableList<T> = list.toMutableList()
private val subscriptions = PrioritizedList<ObservableSubscription<Pair<List<T>, T>>>()
private val subscriptionMap: MutableMap<Observable<*>, ObservableSubscription<*>> = mutableMapOf()
override val elements: List<T> get() = list
override val size: Int get() = list.size
val lastIndex: Int get() = list.lastIndex
init {
list.forEach { register(it) }
}
override fun subscribe(
priority: Priority,
handler: (Pair<List<T>, T>) -> Unit,
): ObservableSubscription<Pair<List<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
return subscription
}
fun subscribeAndHandle(
priority: Priority,
handler: (Pair<List<T>, T>) -> Unit
): ObservableSubscription<Pair<List<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
list.forEach { handler(this to it) }
return subscription
}
override fun unsubscribe(subscription: ObservableSubscription<Pair<List<T>, T>>) {
subscriptions.remove(subscription)
}
protected fun register(element: T) {
elementHandler(element).forEach{ observable ->
subscriptionMap[observable] = observable.subscribe { emitAnyChange(element) }
}
}
protected fun unregister(element: T) {
elementHandler(element).forEach{ subscriptionMap.remove(it)?.unsubscribe() }
}
/** @return true after handling [subscriptions]. */
protected fun emitAnyChange(element: T): Boolean {
subscriptions.forEach { it.handle(list to element) }
return true
}
override fun isEmpty() = list.isEmpty()
override fun isNotEmpty() = list.isNotEmpty()
override fun contains(element: T) = list.contains(element)
override fun containsAll(elements: Collection<T>) = list.containsAll(elements)
override operator fun get(index: Int): T = list[index]
override fun indexOf(element: T) = list.indexOf(element)
override operator fun iterator(): Iterator<T> = list.iterator()
override fun lastIndexOf(element: T) = list.lastIndexOf(element)
override fun listIterator(): ListIterator<T> = list.listIterator()
override fun listIterator(index: Int): ListIterator<T> = list.listIterator(index = index)
override fun subList(fromIndex: Int, toIndex: Int): List<T> = list.subList(fromIndex, toIndex)
override fun copy() = ObservableList(this.list, elementHandler)
open fun mutableCopy() = MutableObservableList(this.list, elementHandler)
}
@@ -1,33 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
open class ObservableListIterator<T>(
protected var list: ObservableList<T>,
protected var index: Int = 0,
) : ListIterator<T> {
override fun hasNext(): Boolean = index < list.size
override fun hasPrevious(): Boolean = list.isNotEmpty() && index > 0
override fun next(): T {
if (!hasNext()) {
throw NoSuchElementException(
"Observable List iterator does not have next element from index $index."
)
}
return list[index++]
}
override fun previous(): T {
if (!hasPrevious()) {
throw NoSuchElementException(
"Observable List iterator does not have a previous element at index ${index -1}."
)
}
return list[--index]
}
override fun nextIndex(): Int = index
override fun previousIndex(): Int = index -1
}
@@ -1,46 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
import net.minecraft.nbt.NbtCompound
fun <T> List<T>.saveToNbt(
elementKey: String = "element",
elementHandler: (T) -> NbtCompound,
): NbtCompound {
val nbt = NbtCompound()
var size = 0
this.iterator().forEach { nbt.put(elementKey + size++, elementHandler(it)) }
nbt.putInt("size", size)
return nbt
}
fun <T> NbtCompound.loadObservableListOf(
elementKey: String = "element",
loadElementHandler: (NbtCompound) -> T,
elementObservableHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = ObservableList(this.loadList(elementKey, loadElementHandler), elementObservableHandler)
fun <T> NbtCompound.loadMutableObservableListOf(
elementKey: String = "element",
loadElementHandler: (NbtCompound) -> T,
elementObservableHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = MutableObservableList(this.loadList(elementKey, loadElementHandler), elementObservableHandler)
private fun <T> NbtCompound.loadList(
elementKey: String = "element",
elementHandler: (NbtCompound) -> T
): List<T> {
val newList = mutableListOf<T>()
if (this.contains("size")) {
val size = this.getInt("size")
for (i in 0 until size) {
newList.add(elementHandler(this.getCompound(elementKey + i)))
}
}
return newList
}
@@ -1,38 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
fun <T> Collection<T>.toObservableList(
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = ObservableList(this, elementHandler)
fun <T> Collection<T>.toMutableObservableList(
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = MutableObservableList(this, elementHandler)
fun <T> observableListOf(
vararg elements: T,
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): ObservableList<T> = ObservableList(elements.toList(), elementHandler)
fun <T> mutableObservableListOf(
vararg elements: T,
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): MutableObservableList<T> = MutableObservableList(elements.toList(), elementHandler)
fun <T> observableListOf(
elements: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): ObservableList<T> = ObservableList(elements, elementHandler)
fun <T> mutableObservableListOf(
elements: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): MutableObservableList<T> = MutableObservableList(elements, elementHandler)
@@ -1,142 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.PrioritizedList
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.collections.ObservableCollection
open class ObservableSubList<T>(
private val parentList: ObservableList<T>,
private val fromIndex: Int,
private val toIndex: Int,
private val elementHandler: (T) -> Set<Observable<*>>,
) : ObservableCollection<T, List<T>>,
List<T>,
Observable<Pair<List<T>, T>> {
private val subscriptions = PrioritizedList<ObservableSubscription<Pair<List<T>, T>>>()
private val subscriptionMap: MutableMap<Observable<*>, ObservableSubscription<*>> = mutableMapOf()
override val elements: List<T> = parentList.elements.subList(fromIndex, toIndex)
override val size: Int = toIndex - fromIndex
init {
for (i in fromIndex until toIndex) {
register(parentList[i])
}
}
override fun subscribe(
priority: Priority,
handler: (Pair<List<T>, T>) -> Unit,
): ObservableSubscription<Pair<List<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
return subscription
}
fun subscribeAndHandle(
priority: Priority,
handler: (Pair<List<T>, T>) -> Unit
): ObservableSubscription<Pair<List<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
elements.forEach { handler(this to it) }
return subscription
}
override fun unsubscribe(subscription: ObservableSubscription<Pair<List<T>, T>>) {
subscriptions.remove(subscription)
}
protected fun register(element: T) {
elementHandler(element).forEach { observable ->
subscriptionMap[observable] = observable.subscribe { emitAnyChange(element) }
}
}
protected fun unregister(element: T) {
elementHandler(element).forEach { observable ->
subscriptionMap.remove(observable)?.unsubscribe()
}
}
protected fun emitAnyChange(element: T): Boolean {
subscriptions.forEach { it.handle(elements to element) }
return true
}
protected fun Int.isInParentRelativeWindow(): Boolean = this in fromIndex until toIndex
override fun isEmpty() = parentList.lastIndex < fromIndex
override fun isNotEmpty() = parentList.size > fromIndex
override fun contains(element: T) = elements.contains(element)
override fun containsAll(elements: Collection<T>) = this.elements.containsAll(elements)
/** @throws IndexOutOfBoundsException if sublist does not contain [subListIndex]. */
protected fun parentIndex(subListIndex: Int) = throwIfOutOfBounds(subListIndex) + fromIndex
/**
* @throws IndexOutOfBoundsException [index] is above [currentLastIndex] or below [fromIndex]
* @return [index]
*/
private fun throwIfOutOfBounds(index: Int): Int {
return if (index in 0 until size) {
index
} else {
throw IndexOutOfBoundsException("Index $index is outside the sub list window.")
}
}
override operator fun get(index: Int): T {
return parentList[parentIndex(index)]
}
override fun indexOf(element: T): Int {
val endIndex = fromIndex + size
for (i in fromIndex until endIndex) {
if (elements[i] == element) {
return i
}
}
return -1
}
override fun lastIndexOf(element: T): Int {
val startIndex = fromIndex + size
for (i in startIndex downTo fromIndex) {
if (elements[i] == element) {
return i
}
}
return -1
}
override operator fun iterator() = ObservableSubListIterator(this)
override fun listIterator() = ObservableSubListIterator(this)
override fun listIterator(index: Int) = ObservableSubListIterator(this, index)
override fun subList(fromIndex: Int, toIndex: Int): List<T> {
return parentList.subList(parentIndex(fromIndex), parentIndex(toIndex))
}
/** @return a read-only copy that will NOT mutate if the backing list mutates. */
override fun copy() = ObservableList(elements, elementHandler)
/** @return a mutable copy that will NOT mutate if the backing list mutates. */
fun mutableCopy() = MutableObservableList(elements, elementHandler)
/** @return a read-only version of [parentList] that will NOT mutate if the parent list mutates */
fun getParentCopy(): ObservableList<T> = parentList.copy()
/** @return a read-only version of [parentList] that will NOT mutate if the parent list mutates */
fun getParentMutableCopy(): MutableObservableList<T> = parentList.mutableCopy()
/** @return a read-only version of [parentList] that WILL mutate if the backing list mutates */
fun getParent(): ObservableList<T> = parentList
}
@@ -1,36 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.list
import com.cobblemon.mod.common.api.reactive.collections.ObservableCollectionIterator
open class ObservableSubListIterator<T>(
protected val subList: ObservableSubList<T>,
protected var index: Int = 0,
) : ObservableCollectionIterator<T, ListIterator<T>>,
ListIterator<T> {
override fun hasNext(): Boolean = index < subList.size
override fun hasPrevious(): Boolean = subList.isNotEmpty() && index > 0
override fun next(): T {
if (!hasNext()) {
throw NoSuchElementException(
"Observable Sub List iterator does not have next element from index $index."
)
}
return subList[index++]
}
override fun previous(): T {
if (!hasPrevious()) {
throw NoSuchElementException(
"Observable Sub List iterator does not have previous element from index ${index - 1}."
)
}
return subList[--index]
}
override fun nextIndex(): Int = index
override fun previousIndex(): Int = index - 1
}
@@ -1,101 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.MapSubscription
import kotlin.collections.Map.Entry
class MutableObservableMap<K, V>(
map: Map<K, V> = mapOf(),
entryHandler: (K, V) -> Set<Observable<*>> = { k, v -> k.getEntryObservables(v) },
) : ObservableMap<K, V>(map = map, entryHandler = entryHandler),
MutableMap<K, V> {
private val additionObservable = SimpleObservable<Pair<Map<K, V>, Pair<K, V>>>()
private val removalObservable = SimpleObservable<Pair<Map<K, V>, Pair<K, V>>>()
fun subscribe(
priority: Priority = Priority.NORMAL,
anyChangeHandler: (Pair<Map<K, V>, Pair<K, V>>) -> Unit,
additionHandler: ((Pair<Map<K, V>, Pair<K, V>>) -> Unit)? = null,
removalHandler: ((Pair<Map<K, V>, Pair<K, V>>) -> Unit)? = null,
): MapSubscription<K, V> {
return MapSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority = Priority.NORMAL,
anyChangeHandler: (Pair<Map<K, V>, Pair<K, V>>) -> Unit,
additionHandler: ((Pair<Map<K, V>, Pair<K, V>>) -> Unit)? = null,
removalHandler: ((Pair<Map<K, V>, Pair<K, V>>) -> Unit)? = null,
): MapSubscription<K, V> {
entries.forEach { anyChangeHandler(this to it.pair()) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler)
}
/**
* @return `true` after handling [register] & all subscriptions to [additionObservable],
* & [ObservableMap.emitAnyChange].
*/
private fun emitAddition(key: K, value: V): Boolean {
register(key, value)
additionObservable.emit(map to (key to value))
return emitAnyChange(key, value)
}
/**
* @return `true` after handling [unregister] & all subscriptions to [removalObservable],
* & [ObservableMap.emitAnyChange].
*/
private fun emitRemoval(key: K, value: V): Boolean {
unregister(key, value)
removalObservable.emit(map to (key to value))
return emitAnyChange(key, value)
}
override operator fun iterator(): MutableObservableMapIterator<K, V> {
return MutableObservableMapIterator(this)
}
operator fun set(key: K, value: V): V? = put(key, value)
fun put(pair: Pair<K, V>): V? = put(pair.first, pair.second)
fun put(entry: Entry<K, V>): V? = put(entry.key, entry.value)
override fun put(key: K, value: V): V? {
val previous = map.put(key, value)
emitAddition(key, value)
if (previous != null) {
emitRemoval(key, previous)
}
return previous
}
fun remove(key: K, value: V): Boolean {
return if (map[key] == value) (remove(key) != null) else false
}
override fun remove(key: K): V? {
val value = map.remove(key) ?: return null
emitRemoval(key, value)
return value
}
override fun putAll(from: Map<out K, V>) = from.forEach { put(it.key, it.value) }
fun getOrDefault(key: K, defaultValue: V): V = map[key] ?: defaultValue
fun getOrPut(key: K, newValue: V) = map[key] ?: newValue.also { put(key, it) }
override fun clear() {
if (map.isNotEmpty()) {
keys.toSet().forEach { remove(it) }
}
}
}
@@ -1,35 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import kotlin.collections.Map.Entry
open class MutableObservableMapIterator<K, V>(
private val observableMap: MutableObservableMap<K, V>,
) : ObservableMapIterator<K, V>(observableMap.entries.toSet().iterator()),
MutableIterator<Entry<K, V>> {
private lateinit var currentEntry: Entry<K, V>
private var removedThisIteration: Boolean? = null
set (value) { if (field != value) field = value }
override fun next(): Entry<K, V> {
currentEntry = super.next()
removedThisIteration = false
return currentEntry
}
override fun remove() {
if (removedThisIteration == null) {
throw IllegalStateException(
"Observable Map iterator 'remove' was called before 'next' or 'previous'."
)
} else if (removedThisIteration == true) {
throw IllegalStateException(
"Observable Map iterator 'remove' was called, " +
"but 'remove' was already called this iteration."
)
}
observableMap.remove(currentEntry.key)
removedThisIteration = true
}
}
@@ -1,124 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import com.cobblemon.mod.common.api.PrioritizedList
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import kotlin.Comparator
import kotlin.collections.Map.Entry
open class ObservableMap<K, V>(
map: Map<K, V>,
protected val entryHandler: (K, V) -> Set<Observable<*>> =
{ k: K, v: V -> k.getEntryObservables(v) },
) : Map<K, V>,
Observable<Pair<Map<K, V>, Pair<K, V>>> {
protected val map: MutableMap<K, V> = map.toMutableMap()
private val subscriptions = PrioritizedList<ObservableSubscription<Pair<Map<K, V>, Pair<K, V>>>>()
private val subscriptionMap: MutableMap<Observable<*>, ObservableSubscription<*>> = mutableMapOf()
override val size get() = map.size
override val keys get() = map.keys
override val values get() = map.values
override val entries get() = map.entries
init {
this.map.forEach { (key, value) ->
entryHandler(key, value).forEach{ observable ->
subscriptionMap[observable] = observable.subscribe {
emitAnyChange(key, value)
}
}
}
}
override fun subscribe(
priority: Priority,
handler: (Pair<Map<K, V>, Pair<K, V>>) -> Unit
): ObservableSubscription<Pair<Map<K, V>, Pair<K, V>>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
return subscription
}
fun subscribeAndHandle(
priority: Priority,
handler: (Pair<Map<K, V>, Pair<K, V>>) -> Unit
): ObservableSubscription<Pair<Map<K, V>, Pair<K, V>>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
map.forEach { handler(this to (it.pair())) }
return subscription
}
override fun unsubscribe(subscription: ObservableSubscription<Pair<Map<K, V>, Pair<K, V>>>) {
subscriptions.remove(subscription)
}
protected open fun register(key: K, value: V) {
if (contains(key, value)) {
entryHandler(key, value).forEach{ observable ->
subscriptionMap[observable] = observable.subscribe { emitAnyChange(key, value) }
}
}
}
protected fun unregister(key: K, value: V) {
entryHandler(key, value).forEach{ subscriptionMap.remove(it)?.unsubscribe() }
}
protected fun emitAnyChange(key: K, value: V): Boolean {
subscriptions.forEach { it.handle(map to (key to value)) }
return true
}
override fun isEmpty() = map.isEmpty()
fun isNotEmpty() = map.isNotEmpty()
override fun containsKey(key: K) = map.containsKey(key)
override fun containsValue(value: V) = map.containsValue(value)
fun contains(pair: Pair<K, V>): Boolean = contains(pair.first, pair.second)
fun contains(entry: Entry<K, V>): Boolean = contains(entry.key, entry.value)
fun contains(key: K, value: V) = map[key] == value
fun contains(predicate: (Entry<K, V>) -> Boolean) = map.any(predicate)
fun containsAll(other: Collection<Entry<K, V>>): Boolean {
return map.all { entry -> other.any { it.key == entry.key && it.value == entry.value } }
}
fun containsAll(other: Map<K, V>): Boolean {
return map.all { entry -> other.any { it.key == entry.key && it.value == entry.value } }
}
open operator fun iterator(): Iterator<Entry<K, V>> = map.iterator()
override operator fun get(key: K) = map[key]
fun toSortedMap(comparator: Comparator<in K>) = map.toMap().toSortedMap(comparator)
fun firstKeyOrNull(predicate: (Entry<K, V>) -> Boolean = { true }): K? {
map.forEach { if (predicate(it)) return it.key }
return null
}
fun firstValueOrNull(predicate: (Entry<K, V>) -> Boolean = { true }): V? {
map.forEach { if (predicate(it)) return it.value }
return null
}
fun firstEntryOrNull(predicate: (Entry<K, V>) -> Boolean = { true }): Entry<K, V>? {
map.forEach { if (predicate(it)) return it }
return null
}
fun copy() = ObservableMap(this.map, entryHandler)
fun mutableCopy() = MutableObservableMap(this.map, entryHandler)
}
@@ -1,11 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import kotlin.collections.Map.Entry
open class ObservableMapIterator<K, V>(
protected var iterator: Iterator<Entry<K, V>>
) : Iterator<Entry<K, V>> {
override fun hasNext():Boolean = iterator.hasNext()
override fun next(): Entry<K, V> = iterator.next()
}
@@ -1,47 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import com.cobblemon.mod.common.api.reactive.Observable
import net.minecraft.nbt.NbtCompound
import kotlin.collections.Map.Entry
fun <K, V> Map<K, V>.saveToNbt(
entryKey: String = "entry",
entryHandler: (Entry<K, V>) -> NbtCompound,
): NbtCompound {
val nbt = NbtCompound()
var size = 0
this.iterator().forEach { nbt.put(entryKey + size++, entryHandler(it)) }
nbt.putInt("size", size)
return nbt
}
fun <K, V> NbtCompound.loadObservableMapOf(
entryKey: String = "entry",
loadEntryHandler: (NbtCompound) -> Pair<K, V>,
entryObservableHandler: (K, V) -> Set<Observable<*>> = { k, v -> k.getEntryObservables(v) },
) = ObservableMap(this.loadMap(entryKey, loadEntryHandler), entryObservableHandler)
fun <K, V> NbtCompound.loadMutableObservableMapOf(
entryKey: String = "entry",
loadEntryHandler: (NbtCompound) -> Pair<K, V>,
entryObservableHandler: (K, V) -> Set<Observable<*>> = { k, v -> k.getEntryObservables(v) },
) = MutableObservableMap(this.loadMap(entryKey, loadEntryHandler), entryObservableHandler)
private fun <K, V> NbtCompound.loadMap(
entryKey: String = "entry",
entryHandler: (NbtCompound) -> Pair<K, V>,
): MutableMap<K, V> {
val newMap: MutableMap<K, V> = mutableMapOf()
if (this.contains("size")) {
val size = this.getInt("size")
for (i in 0 until size) {
val (key, value) = entryHandler(this.getCompound(entryKey + i))
newMap[key] = value
}
}
return newMap
}
@@ -1,113 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.map
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.collections.tryGetObservable
import kotlin.collections.Map.Entry
fun <K, V> Entry<K, V>.pair() = this.key to this.value
fun <K, V> Collection<Entry<K, V>>.pairs(): Set<Pair<K, V>> {
mutableSetOf<Pair<K, V>>().let { set ->
this.forEach { set.add(it.key to it.value) }
return set
}
}
fun <K, V> Map<K, V>.pairs(): Set<Pair<K, V>> {
mutableSetOf<Pair<K, V>>().let { set ->
this.forEach { set.add(it.key to it.value) }
return set
}
}
fun <K, V> Collection<Entry<K, V>>.toMap(): Map<K, V> = this.toMutableMap()
fun <K, V> Collection<Entry<K, V>>.toMutableMap(): MutableMap<K, V> {
return mutableMapOf<K, V>().putAll(this)
}
fun <K, V> MutableMap<K, V>.putAll(entries: Collection<Entry<K, V>>): MutableMap<K, V> {
return entries.forEach { this[it.key] = it.value }.let { this }
}
fun <K, V> defaultEntryHandler() = { k: K, v: V -> k.getEntryObservables(v) }
fun <K, V> K.getEntryObservables(value: V): Set<Observable<*>> {
val observables = mutableSetOf<Observable<*>>()
this.tryGetObservable()?.let { observables.add(it) }
value.tryGetObservable()?.let { observables.add(it) }
return observables
}
fun <K, V> Map<K, V>.toObservableMap(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(this, entryHandler)
fun <K, V> Map<K, V>.toMutableObservableMap(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(this, entryHandler)
fun <K, V> Collection<Pair<K, V>>.toObservableMap(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(this.toMap(), entryHandler)
fun <K, V> Collection<Pair<K, V>>.toMutableObservableMap(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(this.toMap(), entryHandler)
fun <K, V> observableMapOf(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(mapOf(), entryHandler)
fun <K, V> mutableObservableMapOf(
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(mapOf(), entryHandler)
fun <K, V> observableMapOf(
map: Map<K, V> = emptyMap(),
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(map, entryHandler)
fun <K, V> observableMapOf(
vararg pairs: Pair<K, V>,
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(pairs.toMap(), entryHandler)
fun <K, V> mutableObservableMapOf(
vararg pairs: Pair<K, V>,
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(pairs.toMap(), entryHandler)
fun <K, V> mutableObservableMapOf(
map: Map<K, V> = emptyMap(),
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(map, entryHandler)
fun <K, V> observableMapOf(
vararg entries: Entry<K, V>,
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(entries.toSet().toMap(), entryHandler)
fun <K, V> mutableObservableMapOf(
vararg entries: Entry<K, V>,
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(entries.toSet().toMap(), entryHandler)
fun <K, V> observableMapOf(
pairs: Collection<Pair<K, V>> = emptySet(),
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = ObservableMap(pairs.toMap(), entryHandler)
fun <K, V> mutableObservableMapOf(
pairs: Collection<Pair<K, V>> = emptySet(),
entryHandler: (K, V) -> Set<Observable<*>> = defaultEntryHandler(),
) = MutableObservableMap(pairs.toMap(), entryHandler)
@@ -1,100 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.SimpleObservable
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollection
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
import com.cobblemon.mod.common.api.reactive.collections.subscriptions.SetSubscription
import com.cobblemon.mod.common.api.reactive.collections.removeIf
class MutableObservableSet<T>(
set: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) : MutableObservableCollection<T, Set<T>>,
ObservableSet<T>(set, elementHandler),
MutableSet<T> {
private val additionObservable = SimpleObservable<Pair<Set<T>, T>>()
private val removalObservable = SimpleObservable<Pair<Set<T>, T>>()
override fun subscribe(
priority: Priority,
anyChangeHandler: (Pair<Set<T>, T>) -> Unit,
additionHandler: ((Pair<Set<T>, T>) -> Unit)?,
removalHandler: ((Pair<Set<T>, T>) -> Unit)?,
): SetSubscription<T> {
return SetSubscription(
anyChange = this.subscribe(priority, anyChangeHandler),
addition = additionHandler?.let { additionObservable.subscribe(priority, it) },
removal = removalHandler?.let { removalObservable.subscribe(priority, it) },
)
}
fun subscribeAndHandle(
priority: Priority,
anyChangeHandler: (Pair<Set<T>, T>) -> Unit,
additionHandler: ((Pair<Set<T>, T>) -> Unit)?,
removalHandler: ((Pair<Set<T>, T>) -> Unit)?,
): SetSubscription<T> {
elements.forEach { anyChangeHandler(this to it) }
return subscribe(priority, anyChangeHandler, additionHandler, removalHandler)
}
/**
* @return `true` after handling [register] & all subscriptions to [additionObservable]
* & [ObservableSet.emitAnyChange].
*/
private fun emitAddition(element: T): Boolean {
register(element)
additionObservable.emit(set to element)
return emitAnyChange(element)
}
/**
* @return `true` after handling [unregister] & all subscriptions to [removalObservable]
* & [ObservableSet.emitAnyChange].
*/
private fun emitRemoval(element: T): Boolean {
unregister(element)
removalObservable.emit(set to element)
return emitAnyChange(element)
}
override operator fun iterator() = MutableObservableSetIterator(this)
override fun addIf(element: T, predicate: (Set<T>) -> Boolean): Boolean {
return if (predicate(set)) add(element) else false
}
override fun add(element: T): Boolean {
return if (set.add(element)) emitAddition(element) else false
}
override fun removeIf(predicate: (T) -> Boolean): Boolean {
return iterator().removeIf(predicate)
}
fun removeIf(element: T, predicate: (Set<T>) -> Boolean): Boolean {
return if (predicate(set)) remove(element) else false
}
override fun remove(element: T): Boolean {
return if (set.remove(element)) emitRemoval(element) else false
}
override fun addAll(elements: Collection<T>): Boolean {
var mutated = false
elements.forEach { if (add(it) && !mutated) mutated = true }
return mutated
}
override fun removeAll(elements: Collection<T>):Boolean = removeIf { elements.contains(it) }
override fun retainAll(elements: Collection<T>):Boolean = removeIf { !elements.contains(it) }
override fun clear() {
// just a simpler way to call the mutable iterator & emit with each removal
removeIf { true }
}
}
@@ -1,33 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.reactive.collections.MutableObservableCollectionIterator
open class MutableObservableSetIterator<T>(
private val observableSet: MutableObservableSet<T>,
) : MutableObservableCollectionIterator<T, Set<T>, Iterator<T>>,
ObservableSetIterator<T>(observableSet.elements.toSet().iterator()),
MutableIterator<T> {
private var currentElement: T? = null
set (value) { if (field != value) field = value }
private var removedThisIteration: Boolean = false
set (value) { if (field != value) field = value }
override fun next(): T {
currentElement = iterator.next()
removedThisIteration = false
return currentElement!!
}
override fun remove() {
if (currentElement == null) {
throw IllegalStateException("Observable Set iterator 'remove' was called before 'next' or 'previous'.")
} else if (removedThisIteration) {
throw IllegalStateException("Observable Set iterator 'remove' was called, but 'remove' was already called this iteration.")
}
observableSet.remove(currentElement)
currentElement = null
removedThisIteration = true
}
}
@@ -1,86 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.PrioritizedList
import com.cobblemon.mod.common.api.Priority
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.collections.ObservableCollection
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
open class ObservableSet<T>(
set: Collection<T>,
protected val elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) : ObservableCollection<T, Set<T>>,
Set<T>,
Observable<Pair<Set<T>, T>> {
protected val set: MutableSet<T> = set.toMutableSet()
private val subscriptions = PrioritizedList<ObservableSubscription<Pair<Set<T>, T>>>()
private val subscriptionMap: MutableMap<Observable<*>, ObservableSubscription<*>> = mutableMapOf()
// Keep as 'this.set' & not 'set,' b/c compiler doesn't like it & cries a little.
override val elements: Set<T> get() = this.set
override val size: Int get() = set.size
init {
set.forEach { register(it) }
}
override fun subscribe(
priority: Priority,
handler: (Pair<Set<T>, T>) -> Unit,
): ObservableSubscription<Pair<Set<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
return subscription
}
fun subscribeAndHandle(
priority: Priority,
handler: (Pair<Set<T>, T>) -> Unit
): ObservableSubscription<Pair<Set<T>, T>> {
val subscription = ObservableSubscription(this, handler)
subscriptions.add(priority, subscription)
set.forEach { handler(this to it) }
return subscription
}
/*
TODO: fix issue where passing subscription to addition or removal does not unsubscribe
Does this issue really matter?
Calling unsubscribe from the subscription directly works as intended
*/
override fun unsubscribe(subscription: ObservableSubscription<Pair<Set<T>, T>>) {
subscriptions.remove(subscription)
}
protected fun register(element: T) {
elementHandler(element).forEach{ observable ->
subscriptionMap[observable] = observable.subscribe { emitAnyChange(element) }
}
}
protected fun unregister(element: T) {
elementHandler(element).forEach{ subscriptionMap.remove(it)?.unsubscribe() }
}
/** @return true after handling [subscriptions]. */
protected fun emitAnyChange(element: T): Boolean {
subscriptions.forEach { it.handle(set to element) }
return true
}
override fun isEmpty() = set.isEmpty()
override fun isNotEmpty() = set.isNotEmpty()
override fun contains(element: T) = set.contains(element)
override fun containsAll(elements: Collection<T>) = set.containsAll(elements)
override operator fun iterator(): Iterator<T> = set.iterator()
override fun copy() = ObservableSet(set, elementHandler)
fun mutableCopy() = MutableObservableSet(set, elementHandler)
}
@@ -1,11 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.reactive.collections.ObservableCollectionIterator
open class ObservableSetIterator<T>(
protected var iterator: Iterator<T>
) : ObservableCollectionIterator<T, Iterator<T>> {
override fun hasNext():Boolean = iterator.hasNext()
override fun next(): T = iterator.next()
}
@@ -1,46 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
import net.minecraft.nbt.NbtCompound
fun <T> Set<T>.saveToNbt(
elementKey: String = "element",
elementHandler: (T) -> NbtCompound,
): NbtCompound {
val nbt = NbtCompound()
var size = 0
this.iterator().forEach { nbt.put(elementKey + size++, elementHandler(it)) }
nbt.putInt("size", size)
return nbt
}
fun <T> NbtCompound.loadObservableSetOf(
elementKey: String = "element",
loadElementHandler: (NbtCompound) -> T,
elementObservableHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = ObservableSet(this.loadSet(elementKey, loadElementHandler), elementObservableHandler)
fun <T> NbtCompound.loadMutableObservableSetOf(
elementKey: String = "element",
loadElementHandler: (NbtCompound) -> T,
elementObservableHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = MutableObservableSet(this.loadSet(elementKey, loadElementHandler), elementObservableHandler)
private fun <T> NbtCompound.loadSet(
elementKey: String = "element",
elementHandler: (NbtCompound) -> T,
): Set<T> {
val newSet = mutableSetOf<T>()
if (this.contains("size")) {
val size = this.getInt("size")
for (i in 0 until size) {
newSet.add(elementHandler(this.getCompound(elementKey + i)))
}
}
return newSet
}
@@ -1,38 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.set
import com.cobblemon.mod.common.api.reactive.Observable
import com.cobblemon.mod.common.api.reactive.collections.getElementObservables
fun <T> Collection<T>.toObservableSet(
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = ObservableSet(this, elementHandler)
fun <T> Collection<T>.toMutableObservableSet(
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
) = MutableObservableSet(this, elementHandler)
fun <T> observableSetOf(
vararg elements: T,
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): ObservableSet<T> = ObservableSet(elements.toSet(), elementHandler)
fun <T> mutableObservableSetOf(
vararg elements: T,
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): MutableObservableSet<T> = MutableObservableSet(elements.toSet(), elementHandler)
fun <T> observableSetOf(
elements: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): ObservableSet<T> = ObservableSet(elements, elementHandler)
fun <T> mutableObservableSetOf(
elements: Collection<T> = setOf(),
elementHandler: (T) -> Set<Observable<*>> = { it.getElementObservables() },
): MutableObservableSet<T> = MutableObservableSet(elements, elementHandler)
@@ -1,27 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.subscriptions
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
/**
* Immutable observable collections implement an [anyChange] observable subscription directly.
*
* Mutable observable collections implement [anyChange], [addition], & [removal] subscriptions
* through a [CollectionSubscription].
*
* @property anyChange Emits with any mutation of the collection or the collection's observable elements.
*
* @property addition Emits when any collection mutation results from the addition of an element.
*
* @property removal Emits when any collection mutation results from the removal of an element.
*
* @see ListSubscription.set
* @see ListSubscription.swap
*/
interface CollectionSubscription<T, C : Collection<T>> {
val anyChange: ObservableSubscription<Pair<C, T>>
val addition: ObservableSubscription<Pair<C, T>>?
val removal: ObservableSubscription<Pair<C, T>>?
fun unsubscribe()
}
@@ -1,18 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.subscriptions
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
data class IndexedListSubscription<T>(
val addition: ObservableSubscription<Triple<List<T>, T, Int>>? = null,
val removal: ObservableSubscription<Triple<List<T>, T, Int>>? = null,
val set: ObservableSubscription<Triple<List<T>, Pair<T, T>, Int>>? = null,
val swap: ObservableSubscription<Triple<List<T>, Pair<T, T>, Pair<Int, Int>>>? = null,
) {
fun unsubscribe() {
addition?.unsubscribe()
removal?.unsubscribe()
set?.unsubscribe()
swap?.unsubscribe()
}
}
@@ -1,20 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.subscriptions
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
data class ListSubscription<T>(
override val anyChange: ObservableSubscription<Pair<List<T>, T>>,
override val addition: ObservableSubscription<Pair<List<T>, T>>? = null,
override val removal: ObservableSubscription<Pair<List<T>, T>>? = null,
val set: ObservableSubscription<Pair<List<T>, Pair<T, T>>>? = null,
val swap: ObservableSubscription<Pair<List<T>, Pair<T, T>>>? = null,
) : CollectionSubscription<T, List<T>> {
override fun unsubscribe() {
this.anyChange.unsubscribe()
addition?.unsubscribe()
removal?.unsubscribe()
set?.unsubscribe()
swap?.unsubscribe()
}
}
@@ -1,31 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.subscriptions
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
import com.cobblemon.mod.common.api.reactive.collections.map.ObservableMap
import com.cobblemon.mod.common.api.reactive.collections.map.MutableObservableMap
/**
* The immutable [ObservableMap] implements an [anyChange] observable subscription directly.
*
* The [MutableObservableMap] implements [anyChange], [addition], & [removal] subscriptions
* through this class.
*
* @property anyChange Emits with any mutation from removal, addition, or a mutation in place by
* an entry extending the observable interface.
*
* @property addition Emits when any mutation results from the addition of an element.
*
* @property removal Emits when any mutation results from the removal of an element.
*/
data class MapSubscription<K, T>(
val anyChange: ObservableSubscription<Pair<Map<K, T>, Pair<K, T>>>,
val addition: ObservableSubscription<Pair<Map<K, T>, Pair<K, T>>>? = null,
val removal: ObservableSubscription<Pair<Map<K, T>, Pair<K, T>>>? = null,
) {
fun unsubscribe() {
anyChange.unsubscribe()
addition?.unsubscribe()
removal?.unsubscribe()
}
}
@@ -1,16 +0,0 @@
package com.cobblemon.mod.common.api.reactive.collections.subscriptions
import com.cobblemon.mod.common.api.reactive.ObservableSubscription
data class SetSubscription<T>(
override val anyChange: ObservableSubscription<Pair<Set<T>, T>>,
override val addition: ObservableSubscription<Pair<Set<T>, T>>? = null,
override val removal: ObservableSubscription<Pair<Set<T>, T>>? = null,
) : CollectionSubscription<T, Set<T>> {
override fun unsubscribe() {
this.anyChange.unsubscribe()
addition?.unsubscribe()
removal?.unsubscribe()
}
}
@@ -0,0 +1,29 @@
/*
* 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.reference
/**
* Reference data interface. Reference data is defined as information that applies to Cobblemon structurally,
* such as species, stat types, Pokémon types, etc. These do not change during runtime, and are instead used only
* referentially.
*
* A Cobblemon class or interface that implements this interface is capable of being added/modified/deleted
* on the server side and this information will reach the client on login.
*/
interface ReferenceData {
/**
* A unique identifier for this piece of reference data among this reference collection.
* Used to identify when two pieces of reference data are describing the same thing.
*/
fun id(): String
/** Generate a hash to be able to tell if the server and client have a differing version of this. */
override fun hashCode(): Int
// TODO write and read from byte buffer
}
@@ -78,8 +78,8 @@ class ParticleEvent(
particleEffect?.let { effect ->
val bedrockParticleOptions = BedrockParticleOptionsRepository.getEffect(effect.effect) ?: return@let
val rootMatrix = when (effect.type) {
EventParticleOptions.EventParticleType.EMITTER-> MatrixWrapper().updatePosition(storm.matrixWrapper.position).updateMatrix(storm.matrixWrapper.matrix)
EventParticleOptions.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
EventParticleOptions.EventParticleType.EMITTER,// -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
EventParticleOptions.EventParticleType.EMITTER_BOUND,// -> storm.matrixWrapper
EventParticleOptions.EventParticleType.PARTICLE,
EventParticleOptions.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let {
Vec3(
@@ -91,8 +91,8 @@ class ParticleEvent(
}
val sourceVelocity = when (effect.type) {
EventParticleOptions.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
EventParticleOptions.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
EventParticleOptions.EventParticleType.EMITTER,// -> storm.sourceVelocity().let { { it } }
EventParticleOptions.EventParticleType.EMITTER_BOUND,// -> storm.sourceVelocity
EventParticleOptions.EventParticleType.PARTICLE -> { { Vec3.ZERO } }
EventParticleOptions.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let {
Vec3(

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